diff --git a/.changeset/few-toys-deny.md b/.changeset/few-toys-deny.md new file mode 100644 index 000000000..7c2c159c0 --- /dev/null +++ b/.changeset/few-toys-deny.md @@ -0,0 +1,5 @@ +--- +"@snapshot-labs/sx": patch +--- + +add Axiom and Isokratia strategies to execution strategies instead of voting strategies diff --git a/apps/api/src/schema.gql b/apps/api/src/schema.gql index d044f6c92..06ebbb54b 100644 --- a/apps/api/src/schema.gql +++ b/apps/api/src/schema.gql @@ -118,6 +118,7 @@ type Proposal { execution_tx: String veto_tx: String vote_count: Int! + execution_ready: Boolean! executed: Boolean! vetoed: Boolean! completed: Boolean! diff --git a/apps/api/src/writer.ts b/apps/api/src/writer.ts index c16152497..e16dae1e8 100644 --- a/apps/api/src/writer.ts +++ b/apps/api/src/writer.ts @@ -337,6 +337,7 @@ export const handlePropose: CheckpointWriter = async ({ block, tx, rawEvent, eve proposal.execution_tx = null; proposal.veto_tx = null; proposal.vote_count = 0; + proposal.execution_ready = true; proposal.executed = false; proposal.vetoed = false; proposal.completed = false; diff --git a/apps/mana/src/eth/index.ts b/apps/mana/src/eth/index.ts index 7814a2cfa..ec51a77f2 100644 --- a/apps/mana/src/eth/index.ts +++ b/apps/mana/src/eth/index.ts @@ -6,7 +6,7 @@ import { getEthereumWallet, DEFAULT_INDEX, SPACES_INDICIES } from './dependencie const jsonRpcRequestSchema = z.object({ id: z.any(), - method: z.enum(['send', 'execute', 'executeQueuedProposal']), + method: z.enum(['send', 'finalizeProposal', 'execute', 'executeQueuedProposal']), params: z.any() }); diff --git a/apps/mana/src/eth/rpc.ts b/apps/mana/src/eth/rpc.ts index 0ce4a93f3..0d5ca46c2 100644 --- a/apps/mana/src/eth/rpc.ts +++ b/apps/mana/src/eth/rpc.ts @@ -10,6 +10,7 @@ import { evmLineaGoerli, EvmNetworkConfig } from '@snapshot-labs/sx'; +import fetch from 'cross-fetch'; import { createWalletProxy } from './dependencies'; import { rpcError, rpcSuccess } from '../utils'; @@ -71,6 +72,31 @@ export const createNetworkHandler = (chainId: number) => { } } + async function finalizeProposal(id: number, params: any, res: Response) { + try { + const { space, proposalId } = params; + + const response = await fetch('http://ec2-44-197-171-215.compute-1.amazonaws.com:8000/query', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ + chainId, + space, + proposalId, + feeData: { + maxFeePerGas: '50000000000' + } + }) + }); + + const result = await response.text(); + + return rpcSuccess(res, result, id); + } catch (e) { + return rpcError(res, 500, e, id); + } + } + async function execute(id: number, params: any, res: Response) { try { const { space, proposalId, executionParams } = params; @@ -106,5 +132,5 @@ export const createNetworkHandler = (chainId: number) => { } } - return { send, execute, executeQueuedProposal }; + return { send, finalizeProposal, execute, executeQueuedProposal }; }; diff --git a/apps/subgraph-api/package.json b/apps/subgraph-api/package.json index 9a9f95e62..986047934 100644 --- a/apps/subgraph-api/package.json +++ b/apps/subgraph-api/package.json @@ -1,7 +1,7 @@ { "name": "api-subgraph", "private": true, - "version": "0.0.29", + "version": "0.0.31", "scripts": { "test": "graph test", "codegen": "graph codegen", diff --git a/apps/subgraph-api/schema.graphql b/apps/subgraph-api/schema.graphql index 943239ea1..61d6568b0 100644 --- a/apps/subgraph-api/schema.graphql +++ b/apps/subgraph-api/schema.graphql @@ -117,6 +117,7 @@ type Proposal @entity { execution_tx: Bytes veto_tx: Bytes vote_count: Int! + execution_ready: Boolean! executed: Boolean! vetoed: Boolean! completed: Boolean! diff --git a/apps/subgraph-api/src/mapping.ts b/apps/subgraph-api/src/mapping.ts index 191bb3928..da773d033 100644 --- a/apps/subgraph-api/src/mapping.ts +++ b/apps/subgraph-api/src/mapping.ts @@ -1,7 +1,10 @@ import { Address, BigDecimal, BigInt, Bytes, dataSource } from '@graphprotocol/graph-ts' import { ProxyDeployed } from '../generated/ProxyFactory/ProxyFactory' import { AvatarExecutionStrategy } from '../generated/ProxyFactory/AvatarExecutionStrategy' -import { AxiomExecutionStrategy } from '../generated/ProxyFactory/AxiomExecutionStrategy' +import { + AxiomExecutionStrategy, + WriteOffchainVotes, +} from '../generated/ProxyFactory/AxiomExecutionStrategy' import { TimelockExecutionStrategy } from '../generated/ProxyFactory/TimelockExecutionStrategy' import { SpaceCreated, @@ -27,6 +30,7 @@ import { } from '../generated/templates/TimelockExecutionStrategy/TimelockExecutionStrategy' import { Space as SpaceTemplate, + AxiomExecutionStrategy as AxiomExecutionStrategyTemplate, TimelockExecutionStrategy as TimelockExecutionStrategyTemplate, SpaceMetadata as SpaceMetadataTemplate, ProposalMetadata as ProposalMetadataTemplate, @@ -98,6 +102,8 @@ export function handleProxyDeployed(event: ProxyDeployed): void { executionStrategy.treasury = toChecksumAddress(event.params.proxy.toHexString()) executionStrategy.timelock_delay = new BigInt(0) executionStrategy.save() + + AxiomExecutionStrategyTemplate.create(event.params.proxy) } else if (event.params.implementation.equals(MASTER_SIMPLE_QUORUM_TIMELOCK)) { let executionStrategyContract = TimelockExecutionStrategy.bind(event.params.proxy) let typeResult = executionStrategyContract.try_getStrategyType() @@ -232,6 +238,8 @@ export function handleProposalCreated(event: ProposalCreated): void { proposal.execution_strategy_type = 'none' } + proposal.execution_ready = proposal.execution_strategy_type != 'Axiom' + let executionHash = new ExecutionHash(proposal.execution_hash) executionHash.proposal_id = proposalId executionHash.save() @@ -300,6 +308,8 @@ export function handleProposalUpdated(event: ProposalUpdated): void { proposal.execution_strategy_type = 'none' } + proposal.execution_ready = proposal.execution_strategy_type != 'Axiom' + let executionHash = new ExecutionHash(proposal.execution_hash) executionHash.proposal_id = proposalId executionHash.save() @@ -623,6 +633,21 @@ export function handleProposalValidationStrategyUpdated( space.save() } +export function handleAxiomWriteOffchainVotes(event: WriteOffchainVotes): void { + let contract = AxiomExecutionStrategy.bind(event.address) + let spaceResult = contract.try_space() + if (spaceResult.reverted) return + + let spaceId = toChecksumAddress(spaceResult.value.toHexString()) + + let proposal = Proposal.load(`${spaceId}/${event.params.proposalId}`) + if (!proposal) return + + proposal.execution_ready = true + + proposal.save() +} + export function handleTimelockProposalExecuted(event: TimelockProposalExecuted): void { let executionHash = ExecutionHash.load(event.params.executionPayloadHash.toHexString()) if (executionHash === null) { diff --git a/apps/subgraph-api/subgraph.yaml b/apps/subgraph-api/subgraph.yaml index 310f32597..6f4f3417c 100644 --- a/apps/subgraph-api/subgraph.yaml +++ b/apps/subgraph-api/subgraph.yaml @@ -79,6 +79,24 @@ templates: - event: ProposalValidationStrategyUpdated((address,bytes),string) handler: handleProposalValidationStrategyUpdated file: ./src/mapping.ts + - kind: ethereum + name: AxiomExecutionStrategy + network: optimism + source: + abi: AxiomExecutionStrategy + mapping: + kind: ethereum/events + apiVersion: 0.0.7 + language: wasm/assemblyscript + entities: + - ProposalExecuted + abis: + - name: AxiomExecutionStrategy + file: ./abis/AxiomExecutionStrategy.json + eventHandlers: + - event: WriteOffchainVotes(uint256,uint256,uint256,uint256,uint256) + handler: handleAxiomWriteOffchainVotes + file: ./src/mapping.ts - kind: ethereum name: TimelockExecutionStrategy network: optimism diff --git a/apps/ui/.env b/apps/ui/.env index ff5d59f60..9ec141eee 100644 --- a/apps/ui/.env +++ b/apps/ui/.env @@ -1,6 +1,6 @@ VITE_ENABLED_NETWORKS= VITE_MANA_URL=https://mana.pizza -VITE_HIGHLIGHT_URL= +VITE_HIGHLIGHT_URL=https://testnet.highlight.red VITE_IPFS_GATEWAY=snapshot.4everland.link VITE_INFURA_API_KEY=46a5dd9727bf48d4a132672d3f376146 VITE_ALCHEMY_API_KEY=ombBQyf580z-jx2EVQgJu4eTjePU-a2z diff --git a/apps/ui/package.json b/apps/ui/package.json index 56a64a097..5a79c7a93 100644 --- a/apps/ui/package.json +++ b/apps/ui/package.json @@ -39,9 +39,11 @@ "@ethersproject/hash": "^5.7.0", "@ethersproject/providers": "^5.7.2", "@ethersproject/units": "^5.7.0", + "@ethersproject/wallet": "^5.7.0", "@headlessui/vue": "^1.7.16", "@openzeppelin/merkle-tree": "^1.0.5", "@snapshot-labs/eslint-config-vue": "^0.1.0-beta.13", + "@snapshot-labs/highlight": "^0.1.0-beta.2", "@snapshot-labs/lock": "^0.2.0", "@snapshot-labs/pineapple": "^1.1.0", "@snapshot-labs/prettier-config": "^0.1.0-beta.7", diff --git a/apps/ui/src/components/ProposalExecutionActions.vue b/apps/ui/src/components/ProposalExecutionActions.vue index d05d23fb7..3e3ebade4 100644 --- a/apps/ui/src/components/ProposalExecutionActions.vue +++ b/apps/ui/src/components/ProposalExecutionActions.vue @@ -7,16 +7,9 @@ import { Proposal as ProposalType } from '@/types'; const props = defineProps<{ proposal: ProposalType }>(); const { web3 } = useWeb3(); -const { - finalizeProposal, - receiveProposal, - executeTransactions, - executeQueuedProposal, - vetoProposal -} = useActions(); +const { finalizeProposal, executeTransactions, executeQueuedProposal, vetoProposal } = useActions(); const finalizeProposalSending = ref(false); -const receiveProposalSending = ref(false); const executeTransactionsSending = ref(false); const executeQueuedProposalSending = ref(false); const vetoProposalSending = ref(false); @@ -49,16 +42,6 @@ async function handleFinalizeProposalClick() { } } -async function handleReceiveProposalClick() { - receiveProposalSending.value = true; - - try { - await receiveProposal(props.proposal); - } finally { - receiveProposalSending.value = false; - } -} - async function handleExecuteTransactionsClick() { executeTransactionsSending.value = true; @@ -116,7 +99,7 @@ async function handleVetoProposalClick() {