Skip to content
This repository has been archived by the owner on Feb 22, 2024. It is now read-only.

feat: add Isokratia execution #266

Merged
merged 2 commits into from
Feb 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 66 additions & 0 deletions src/clients/evm/ethereum-tx/abis/IsokratiaExecutionStrategy.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
[
"constructor(uint32,uint256,address,address,uint256)",
"error AttemptProofExecutionNotFinalized()",
"error CannotCommitProposalBeforeStartBlock(uint32,uint32)",
"error DuplicateExecutionPayloadHash()",
"error DurationMustExceedProvingTimeAllownace(uint32,uint32,uint32)",
"error ExecutionFailed()",
"error InvalidProof()",
"error InvalidProposalStatus(uint8)",
"error InvalidSpace()",
"error IsokratiaProposalAlreadyExists(bytes32)",
"error MerkleRootAlreadyExists()",
"error MerkleRootDoesNotExist()",
"error NotIsokratiaProposal(uint256)",
"error OnlyProver()",
"error ProposalAlreadyCommitted(bytes32)",
"error ProposalAlreadyProven(bytes32)",
"error ProposalNotCommitted(bytes32)",
"error ProposalNotProcessed()",
"error ProposalNotProven(bytes32)",
"error TimelockDelayNotMet()",
"event Initialized(uint8)",
"event IsokratiaExecutionStrategySetUp(address indexed,uint32,uint256)",
"event IsokratiaSnapshotQueryAddressUpdated(address)",
"event MerkleRootSet(uint256)",
"event OwnershipTransferred(address indexed,address indexed)",
"event PostedAggregation(uint256,bytes32,uint256,uint256,uint256)",
"event ProposalCommitted(bytes32)",
"event ProposalExecuted(bytes32)",
"event ProposalProven(bytes32,bytes32)",
"event ProvingTimeAllownaceUpdated(uint32)",
"event QuorumUpdated(uint256)",
"event SnapshotAddressUpdated(address)",
"event SnapshotSlotUpdated(uint256)",
"event SpaceDisabled(address)",
"event SpaceEnabled(address)",
"event TransactionExecuted(tuple(address,uint256,bytes,uint8,uint256))",
"event TransactionProcessed(tuple(address,uint256,bytes,uint8,uint256),uint256)",
"function committedProposals(bytes32) view returns (bool, bool)",
"function disableSpace(address)",
"function enableSpace(address)",
"function execute(uint256,tuple(address,uint32,address,uint32,uint32,uint8,bytes32,uint256),uint256,uint256,uint256,bytes)",
"function executeFinalizedProposal(bytes,bytes32)",
"function getExecutionStrategyStatus(tuple(address,uint32,uint32,uint32,uint32,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,bytes32,bytes32,bytes32)) view returns (uint8)",
"function getProposalStatus(tuple(address,uint32,address,uint32,uint32,uint8,bytes32,uint256),uint256,uint256,uint256) view returns (uint8)",
"function getStrategyType() pure returns (string)",
"function isSpaceEnabled(address) view returns (uint256)",
"function isokratiaProposals(bytes32) view returns (address, uint32, uint32, uint32, uint32, uint256, uint256, uint256, uint256, uint256, uint256, uint256, uint256, uint256, bytes32, bytes32, bytes32)",
"function isokratiaSnapshotQueryAddress() view returns (address)",
"function owner() view returns (address)",
"function ownerAddress() view returns (address)",
"function postAggregation(bytes,bytes32,tuple(uint256[2][3],uint256[2][2][3],uint256[2][3],uint256[2][3],uint256[4][3],uint256[3],uint64[4],uint64[4],uint256,uint256,uint256,uint32,uint32,uint32))",
"function postMerkleEligibilityRoot(uint256,uint256)",
"function proposalExecutionTime(bytes32) view returns (uint256)",
"function proposalIdMerkleRoots(uint256) view returns (uint256)",
"function provingTimeAllowance() view returns (uint32)",
"function quorum() view returns (uint256)",
"function renounceOwnership()",
"function setProvingTimeAllowance(uint32)",
"function setQuorum(uint256)",
"function setUp(bytes)",
"function snapshotAddress() view returns (address)",
"function snapshotSlot() view returns (uint256)",
"function transferOwnership(address)",
"function updateSettings(tuple(address,address,uint256))"
]
58 changes: 58 additions & 0 deletions src/clients/evm/ethereum-tx/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import ProxyFactoryAbi from './abis/ProxyFactory.json';
import AvatarExecutionStrategyAbi from './abis/AvatarExecutionStrategy.json';
import TimelockExecutionStrategyAbi from './abis/TimelockExecutionStrategy.json';
import AxiomExecutionStrategyAbi from './abis/AxiomExecutionStrategy.json';
import IsokratiaExecutionStrategyAbi from './abis/IsokratiaExecutionStrategy.json';
import type { Signer } from '@ethersproject/abstract-signer';
import type { Propose, UpdateProposal, Vote, Envelope, AddressConfig } from '../types';
import type { EvmNetworkConfig } from '../../../types';
Expand Down Expand Up @@ -52,6 +53,14 @@ type AxiomExecutionStrategyParams = {
querySchema: string;
};

type IsokratiaExecutionStrategyParams = {
provingTimeAllowance: number;
quorum: bigint;
queryAddress: string;
contractAddress: string;
slotIndex: bigint;
};

type UpdateSettingsInput = {
minVotingDuration?: number;
maxVotingDuration?: number;
Expand Down Expand Up @@ -224,6 +233,55 @@ export class EthereumTx {
return { address, txId: response.hash };
}

async deployIsokratiaExecution({
signer,
params: { provingTimeAllowance, quorum, queryAddress, contractAddress, slotIndex },
saltNonce
}: {
signer: Signer;
params: IsokratiaExecutionStrategyParams;
saltNonce?: string;
}): Promise<{ txId: string; address: string }> {
saltNonce = saltNonce || `0x${randomBytes(32).toString('hex')}`;

const implementationAddress =
this.networkConfig.executionStrategiesImplementations['Isokratia'];

if (!implementationAddress) {
throw new Error('Missing Isokratia implementation address');
}

const abiCoder = new AbiCoder();
const isokratiaExecutionStrategyInterface = new Interface(IsokratiaExecutionStrategyAbi);
const proxyFactoryContract = new Contract(
this.networkConfig.proxyFactory,
ProxyFactoryAbi,
signer
);

const initParams = abiCoder.encode(
['uint32', 'uint256', 'address', 'address', 'uint256'],
[provingTimeAllowance, quorum, queryAddress, contractAddress, slotIndex]
);
const functionData = isokratiaExecutionStrategyInterface.encodeFunctionData('setUp', [
initParams
]);

const sender = await signer.getAddress();
const salt = await this.getSalt({
sender,
saltNonce
});
const address = await proxyFactoryContract.predictProxyAddress(implementationAddress, salt);
const response = await proxyFactoryContract.deployProxy(
implementationAddress,
functionData,
saltNonce
);

return { address, txId: response.hash };
}

async deploySpace({
signer,
params: {
Expand Down
2 changes: 1 addition & 1 deletion src/executors/axiom.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { AbiCoder } from '@ethersproject/abi';
import type { MetaTransaction } from '../utils/encoding/execution-hash';
import type { MetaTransaction } from '../utils/encoding';

export default function createAxiomExecutor() {
return {
Expand Down
5 changes: 5 additions & 0 deletions src/executors/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import createVanillaExecutor from './vanilla';
import createEthRelayerExecutor from './ethRelayer';
import createAvatarExecutor from './avatar';
import createAxiomExecutor from './axiom';
import createIsokratiaExecutor from './isokratia';
import { ExecutorType, ExecutionInput } from '../types';

export function getExecutionData(
Expand All @@ -27,5 +28,9 @@ export function getExecutionData(
return createAxiomExecutor().getExecutionData(executorAddress, input.transactions);
}

if (type === 'Isokratia' && input?.transactions) {
return createIsokratiaExecutor().getExecutionData(executorAddress, input.transactions);
}

throw new Error(`Not enough data to create execution for executor ${executorAddress}`);
}
21 changes: 21 additions & 0 deletions src/executors/isokratia.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { AbiCoder } from '@ethersproject/abi';
import type { MetaTransaction } from '../utils/encoding';

export default function createIsokratiaExecutor() {
return {
type: 'isokratia',
getExecutionData(executorAddress: string, transactions: MetaTransaction[]) {
const abiCoder = new AbiCoder();

const executionParams = abiCoder.encode(
['tuple(address to, uint256 value, bytes data, uint8 operation, uint256 salt)[]'],
[transactions]
);

return {
executor: executorAddress,
executionParams: [executionParams]
};
}
};
}
3 changes: 2 additions & 1 deletion src/networks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,8 @@ export const evmSepolia: EvmNetworkConfig = {
eip712ChainId: 11155111,
executionStrategiesImplementations: {
...evmGoerli.executionStrategiesImplementations,
Axiom: '0xE59405D7d40df064E85FD02a4F2F2C527172a9c1'
Axiom: '0xE59405D7d40df064E85FD02a4F2F2C527172a9c1',
Isokratia: '0xc674eCf233920aa3052738BFCDbDd0812AEE5A83'
}
};

Expand Down
3 changes: 2 additions & 1 deletion src/types/networkConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ export type ExecutorType =
| 'SimpleQuorumAvatar'
| 'SimpleQuorumTimelock'
| 'EthRelayer'
| 'Axiom';
| 'Axiom'
| 'Isokratia';

export type VanillaAuthenticatorConfig = {
type: 'vanilla';
Expand Down
Loading