From 95e1459969e5888ea9ec2f91960d6d17bab8b2c0 Mon Sep 17 00:00:00 2001 From: NicoSerranoP Date: Wed, 14 May 2025 13:47:43 -0500 Subject: [PATCH] chore(plugins): delete optimism and lock to vote --- .env.example | 4 - constants.ts | 7 - plugins/index.ts | 36 +- .../artifacts/LockToVetoPlugin.sol.ts | 626 ---------- .../OptimisticTokenVotingPlugin.sol.ts | 939 --------------- .../lockToVote/components/proposal/header.tsx | 101 -- .../lockToVote/components/proposal/index.tsx | 105 -- plugins/lockToVote/components/vote/tally.tsx | 35 - .../components/vote/vetoes-section.tsx | 42 - .../lockToVote/hooks/useCanCreateProposal.ts | 90 -- plugins/lockToVote/hooks/useCreateProposal.ts | 107 -- plugins/lockToVote/hooks/usePastSupply.ts | 16 - plugins/lockToVote/hooks/useProposal.ts | 137 --- .../lockToVote/hooks/useProposalClaimLock.ts | 57 - .../lockToVote/hooks/useProposalExecute.ts | 58 - .../hooks/useProposalVariantStatus.ts | 60 - plugins/lockToVote/hooks/useProposalVeto.ts | 68 -- plugins/lockToVote/hooks/useProposalVetoes.ts | 39 - plugins/lockToVote/hooks/useToken.ts | 35 - plugins/lockToVote/hooks/useUserCanVeto.ts | 28 - plugins/lockToVote/index.tsx | 21 - plugins/lockToVote/pages/new.tsx | 283 ----- plugins/lockToVote/pages/proposal-list.tsx | 100 -- plugins/lockToVote/pages/proposal.tsx | 212 ---- plugins/lockToVote/utils/types.tsx | 37 - .../artifacts/OptimisticMultisigPlugin.tsx | 429 ------- .../components/proposal/header.tsx | 75 -- .../components/proposal/index.tsx | 91 -- .../hooks/useCanCreateProposal.ts | 29 - .../opt-multisig/hooks/useCreateProposal.ts | 112 -- plugins/opt-multisig/hooks/useProposal.ts | 139 --- .../hooks/useProposalApprovals.ts | 39 - .../opt-multisig/hooks/useProposalApprove.ts | 48 - .../opt-multisig/hooks/useProposalExecute.ts | 60 - .../hooks/useProposalVariantStatus.ts | 51 - .../opt-multisig/hooks/useUserCanApprove.ts | 28 - plugins/opt-multisig/index.tsx | 21 - plugins/opt-multisig/pages/new.tsx | 283 ----- plugins/opt-multisig/pages/proposal-list.tsx | 109 -- plugins/opt-multisig/pages/proposal.tsx | 111 -- plugins/opt-multisig/utils/types.ts | 39 - .../artifacts/ERC20Votes.ts | 26 - .../MyOptimisticTokenVotingPlugin.sol.tsx | 1068 ----------------- .../OptimisticTokenVotingPlugin.sol.tsx | 939 --------------- .../components/proposal/header.tsx | 93 -- .../components/proposal/index.tsx | 105 -- .../components/vote/tally.tsx | 35 - .../components/vote/vetoes-section.tsx | 42 - .../hooks/useCanCreateProposal.ts | 90 -- .../hooks/useGovernanceSettings.ts | 43 - .../hooks/usePastSupply.ts | 17 - .../optimistic-proposals/hooks/useProposal.ts | 154 --- .../hooks/useProposalExecute.ts | 62 - .../hooks/useProposalId.ts | 22 - .../hooks/useProposalVariantStatus.ts | 76 -- .../hooks/useProposalVeto.ts | 47 - .../hooks/useProposalVetoes.ts | 37 - .../optimistic-proposals/hooks/useToken.ts | 35 - .../hooks/useTokenPastVotes.ts | 39 - .../hooks/useUserCanVeto.ts | 28 - plugins/optimistic-proposals/index.tsx | 20 - .../pages/proposal-list.tsx | 136 --- .../optimistic-proposals/pages/proposal.tsx | 210 ---- .../optimistic-proposals/utils/proposal-id.ts | 8 - plugins/optimistic-proposals/utils/types.tsx | 49 - scripts/example.ts | 28 - 66 files changed, 1 insertion(+), 8315 deletions(-) delete mode 100644 plugins/lockToVote/artifacts/LockToVetoPlugin.sol.ts delete mode 100644 plugins/lockToVote/artifacts/OptimisticTokenVotingPlugin.sol.ts delete mode 100644 plugins/lockToVote/components/proposal/header.tsx delete mode 100644 plugins/lockToVote/components/proposal/index.tsx delete mode 100644 plugins/lockToVote/components/vote/tally.tsx delete mode 100644 plugins/lockToVote/components/vote/vetoes-section.tsx delete mode 100644 plugins/lockToVote/hooks/useCanCreateProposal.ts delete mode 100644 plugins/lockToVote/hooks/useCreateProposal.ts delete mode 100644 plugins/lockToVote/hooks/usePastSupply.ts delete mode 100644 plugins/lockToVote/hooks/useProposal.ts delete mode 100644 plugins/lockToVote/hooks/useProposalClaimLock.ts delete mode 100644 plugins/lockToVote/hooks/useProposalExecute.ts delete mode 100644 plugins/lockToVote/hooks/useProposalVariantStatus.ts delete mode 100644 plugins/lockToVote/hooks/useProposalVeto.ts delete mode 100644 plugins/lockToVote/hooks/useProposalVetoes.ts delete mode 100644 plugins/lockToVote/hooks/useToken.ts delete mode 100644 plugins/lockToVote/hooks/useUserCanVeto.ts delete mode 100644 plugins/lockToVote/index.tsx delete mode 100644 plugins/lockToVote/pages/new.tsx delete mode 100644 plugins/lockToVote/pages/proposal-list.tsx delete mode 100644 plugins/lockToVote/pages/proposal.tsx delete mode 100644 plugins/lockToVote/utils/types.tsx delete mode 100644 plugins/opt-multisig/artifacts/OptimisticMultisigPlugin.tsx delete mode 100644 plugins/opt-multisig/components/proposal/header.tsx delete mode 100644 plugins/opt-multisig/components/proposal/index.tsx delete mode 100644 plugins/opt-multisig/hooks/useCanCreateProposal.ts delete mode 100644 plugins/opt-multisig/hooks/useCreateProposal.ts delete mode 100644 plugins/opt-multisig/hooks/useProposal.ts delete mode 100644 plugins/opt-multisig/hooks/useProposalApprovals.ts delete mode 100644 plugins/opt-multisig/hooks/useProposalApprove.ts delete mode 100644 plugins/opt-multisig/hooks/useProposalExecute.ts delete mode 100644 plugins/opt-multisig/hooks/useProposalVariantStatus.ts delete mode 100644 plugins/opt-multisig/hooks/useUserCanApprove.ts delete mode 100644 plugins/opt-multisig/index.tsx delete mode 100644 plugins/opt-multisig/pages/new.tsx delete mode 100644 plugins/opt-multisig/pages/proposal-list.tsx delete mode 100644 plugins/opt-multisig/pages/proposal.tsx delete mode 100644 plugins/opt-multisig/utils/types.ts delete mode 100644 plugins/optimistic-proposals/artifacts/ERC20Votes.ts delete mode 100644 plugins/optimistic-proposals/artifacts/MyOptimisticTokenVotingPlugin.sol.tsx delete mode 100644 plugins/optimistic-proposals/artifacts/OptimisticTokenVotingPlugin.sol.tsx delete mode 100644 plugins/optimistic-proposals/components/proposal/header.tsx delete mode 100644 plugins/optimistic-proposals/components/proposal/index.tsx delete mode 100644 plugins/optimistic-proposals/components/vote/tally.tsx delete mode 100644 plugins/optimistic-proposals/components/vote/vetoes-section.tsx delete mode 100644 plugins/optimistic-proposals/hooks/useCanCreateProposal.ts delete mode 100644 plugins/optimistic-proposals/hooks/useGovernanceSettings.ts delete mode 100644 plugins/optimistic-proposals/hooks/usePastSupply.ts delete mode 100644 plugins/optimistic-proposals/hooks/useProposal.ts delete mode 100644 plugins/optimistic-proposals/hooks/useProposalExecute.ts delete mode 100644 plugins/optimistic-proposals/hooks/useProposalId.ts delete mode 100644 plugins/optimistic-proposals/hooks/useProposalVariantStatus.ts delete mode 100644 plugins/optimistic-proposals/hooks/useProposalVeto.ts delete mode 100644 plugins/optimistic-proposals/hooks/useProposalVetoes.ts delete mode 100644 plugins/optimistic-proposals/hooks/useToken.ts delete mode 100644 plugins/optimistic-proposals/hooks/useTokenPastVotes.ts delete mode 100644 plugins/optimistic-proposals/hooks/useUserCanVeto.ts delete mode 100644 plugins/optimistic-proposals/index.tsx delete mode 100644 plugins/optimistic-proposals/pages/proposal-list.tsx delete mode 100644 plugins/optimistic-proposals/pages/proposal.tsx delete mode 100644 plugins/optimistic-proposals/utils/proposal-id.ts delete mode 100644 plugins/optimistic-proposals/utils/types.tsx delete mode 100644 scripts/example.ts diff --git a/.env.example b/.env.example index 3bc7707..818aea4 100644 --- a/.env.example +++ b/.env.example @@ -6,11 +6,7 @@ NEXT_PUBLIC_TOKEN_ADDRESS=0x9A3218197C77F54BB2510FBBcc7Da3A4D2bE0DeE # Plugin addresses NEXT_PUBLIC_TOKEN_VOTING_PLUGIN_ADDRESS=0x7AdF2545e746E014887916e476DfCB3Fb57D78b0 -NEXT_PUBLIC_LOCK_TO_VOTE_PLUGIN_ADDRESS= -NEXT_PUBLIC_OPT_MULTISIG_PLUGIN_ADDRESS=0xf49d54D40A331441536BDF74C44FFb527cf113c9 -NEXT_PUBLIC_DUAL_GOVERNANCE_PLUGIN_ADDRESS=0x31df2Cf73f36732c10523E4F228a458292B8F6DF NEXT_PUBLIC_PUBLIC_KEY_REGISTRY_CONTRACT_ADDRESS=0x4BA2de07E5B7FB284d363DBb4c481F330c25b2A5 -NEXT_PUBLIC_DELEGATION_WALL_CONTRACT_ADDRESS=0x78b109462dEB44A5a94000b835ebbD7F078Aa12f NEXT_PUBLIC_BRIDGE_ADDRESS=0x0000000000000000000000000000001234567890 diff --git a/constants.ts b/constants.ts index 35a9d6e..4ad29f3 100644 --- a/constants.ts +++ b/constants.ts @@ -5,16 +5,9 @@ import { type ChainName, getChain } from "./utils/chains"; export const PUB_DAO_ADDRESS = (process.env.NEXT_PUBLIC_DAO_ADDRESS ?? "") as Address; export const PUB_TOKEN_ADDRESS = (process.env.NEXT_PUBLIC_TOKEN_ADDRESS ?? "") as Address; -export const PUB_OPT_MULTISIG_PLUGIN_ADDRESS = (process.env.NEXT_PUBLIC_OPT_MULTISIG_PLUGIN_ADDRESS ?? "") as Address; - -export const PUB_DUAL_GOVERNANCE_PLUGIN_ADDRESS = (process.env.NEXT_PUBLIC_DUAL_GOVERNANCE_PLUGIN_ADDRESS ?? - "") as Address; -export const PUB_LOCK_TO_VOTE_PLUGIN_ADDRESS = (process.env.NEXT_PUBLIC_LOCK_TO_VOTE_PLUGIN_ADDRESS ?? "") as Address; export const PUB_TOKEN_VOTING_PLUGIN_ADDRESS = (process.env.NEXT_PUBLIC_TOKEN_VOTING_PLUGIN_ADDRESS ?? "") as Address; export const PUB_PUBLIC_KEY_REGISTRY_CONTRACT_ADDRESS = (process.env.NEXT_PUBLIC_PUBLIC_KEY_REGISTRY_CONTRACT_ADDRESS ?? "") as Address; -export const PUB_DELEGATION_WALL_CONTRACT_ADDRESS = (process.env.NEXT_PUBLIC_DELEGATION_WALL_CONTRACT_ADDRESS ?? - "") as Address; export const PUB_BRIDGE_ADDRESS = (process.env.NEXT_PUBLIC_BRIDGE_ADDRESS ?? "") as Address; diff --git a/plugins/index.ts b/plugins/index.ts index c830615..810b53a 100644 --- a/plugins/index.ts +++ b/plugins/index.ts @@ -1,10 +1,4 @@ -import { - PUB_DELEGATION_WALL_CONTRACT_ADDRESS, - PUB_DUAL_GOVERNANCE_PLUGIN_ADDRESS, - PUB_TOKEN_VOTING_PLUGIN_ADDRESS, - PUB_LOCK_TO_VOTE_PLUGIN_ADDRESS, - PUB_OPT_MULTISIG_PLUGIN_ADDRESS, -} from "@/constants"; +import { PUB_TOKEN_VOTING_PLUGIN_ADDRESS } from "@/constants"; import { type IconType } from "@aragon/ods"; type PluginItem = { @@ -26,32 +20,4 @@ export const plugins: PluginItem[] = [ // icon: IconType.BLOCKCHAIN_BLOCKCHAIN, pluginAddress: PUB_TOKEN_VOTING_PLUGIN_ADDRESS, }, - { - id: "lock-to-vote", - folderName: "lockToVote", - title: "Lock to vote", - // icon: IconType.BLOCKCHAIN_BLOCK, - pluginAddress: PUB_LOCK_TO_VOTE_PLUGIN_ADDRESS, - }, - { - id: "optimistic", - folderName: "optimistic-proposals", - title: "Optimistic", - // icon: IconType.APP_MEMBERS, - pluginAddress: PUB_DUAL_GOVERNANCE_PLUGIN_ADDRESS, - }, - { - id: "opt-multisig", - folderName: "opt-multisig", - title: "Multisig (Optimistic)", - // icon: IconType.BLOCKCHAIN_BLOCKCHAIN, - pluginAddress: PUB_OPT_MULTISIG_PLUGIN_ADDRESS, - }, - { - id: "members", - folderName: "members", - title: "Members", - // icon: IconType.BLOCKCHAIN_BLOCKCHAIN, - pluginAddress: PUB_DELEGATION_WALL_CONTRACT_ADDRESS, - }, ]; diff --git a/plugins/lockToVote/artifacts/LockToVetoPlugin.sol.ts b/plugins/lockToVote/artifacts/LockToVetoPlugin.sol.ts deleted file mode 100644 index 13057c2..0000000 --- a/plugins/lockToVote/artifacts/LockToVetoPlugin.sol.ts +++ /dev/null @@ -1,626 +0,0 @@ -export const LockToVetoPluginAbi = [ - { - inputs: [ - { internalType: "uint256", name: "proposalId", type: "uint256" }, - { internalType: "address", name: "account", type: "address" }, - ], - name: "ClaimLockForbidden", - type: "error", - }, - { - inputs: [ - { internalType: "address", name: "dao", type: "address" }, - { internalType: "address", name: "where", type: "address" }, - { internalType: "address", name: "who", type: "address" }, - { internalType: "bytes32", name: "permissionId", type: "bytes32" }, - ], - name: "DaoUnauthorized", - type: "error", - }, - { - inputs: [ - { internalType: "uint64", name: "limit", type: "uint64" }, - { internalType: "uint64", name: "actual", type: "uint64" }, - ], - name: "DateOutOfBounds", - type: "error", - }, - { - inputs: [ - { internalType: "uint64", name: "limit", type: "uint64" }, - { internalType: "uint64", name: "actual", type: "uint64" }, - ], - name: "MinDurationOutOfBounds", - type: "error", - }, - { - inputs: [ - { internalType: "uint256", name: "limit", type: "uint256" }, - { internalType: "uint256", name: "actual", type: "uint256" }, - ], - name: "MinProposerVotingPowerOutOfBounds", - type: "error", - }, - { inputs: [], name: "NoVotingPower", type: "error" }, - { - inputs: [{ internalType: "address", name: "sender", type: "address" }], - name: "ProposalCreationForbidden", - type: "error", - }, - { - inputs: [{ internalType: "uint256", name: "proposalId", type: "uint256" }], - name: "ProposalExecutionForbidden", - type: "error", - }, - { - inputs: [ - { internalType: "uint256", name: "proposalId", type: "uint256" }, - { internalType: "address", name: "account", type: "address" }, - ], - name: "ProposalVetoingForbidden", - type: "error", - }, - { - inputs: [ - { internalType: "uint256", name: "limit", type: "uint256" }, - { internalType: "uint256", name: "actual", type: "uint256" }, - ], - name: "RatioOutOfBounds", - type: "error", - }, - { - anonymous: false, - inputs: [ - { - indexed: false, - internalType: "address", - name: "previousAdmin", - type: "address", - }, - { - indexed: false, - internalType: "address", - name: "newAdmin", - type: "address", - }, - ], - name: "AdminChanged", - type: "event", - }, - { - anonymous: false, - inputs: [ - { - indexed: true, - internalType: "address", - name: "beacon", - type: "address", - }, - ], - name: "BeaconUpgraded", - type: "event", - }, - { - anonymous: false, - inputs: [{ indexed: false, internalType: "uint8", name: "version", type: "uint8" }], - name: "Initialized", - type: "event", - }, - { - anonymous: false, - inputs: [ - { - indexed: true, - internalType: "uint256", - name: "proposalId", - type: "uint256", - }, - { - indexed: true, - internalType: "address", - name: "voter", - type: "address", - }, - { - indexed: false, - internalType: "uint256", - name: "amount", - type: "uint256", - }, - ], - name: "LockClaimed", - type: "event", - }, - { - anonymous: false, - inputs: [ - { - indexed: false, - internalType: "address[]", - name: "members", - type: "address[]", - }, - ], - name: "MembersAdded", - type: "event", - }, - { - anonymous: false, - inputs: [ - { - indexed: false, - internalType: "address[]", - name: "members", - type: "address[]", - }, - ], - name: "MembersRemoved", - type: "event", - }, - { - anonymous: false, - inputs: [ - { - indexed: true, - internalType: "address", - name: "definingContract", - type: "address", - }, - ], - name: "MembershipContractAnnounced", - type: "event", - }, - { - anonymous: false, - inputs: [ - { - indexed: false, - internalType: "uint32", - name: "minVetoRatio", - type: "uint32", - }, - { - indexed: false, - internalType: "uint64", - name: "minDuration", - type: "uint64", - }, - { - indexed: false, - internalType: "uint256", - name: "minProposerVotingPower", - type: "uint256", - }, - ], - name: "OptimisticGovernanceSettingsUpdated", - type: "event", - }, - { - anonymous: false, - inputs: [ - { - indexed: true, - internalType: "uint256", - name: "proposalId", - type: "uint256", - }, - { - indexed: true, - internalType: "address", - name: "creator", - type: "address", - }, - { - indexed: false, - internalType: "uint64", - name: "startDate", - type: "uint64", - }, - { - indexed: false, - internalType: "uint64", - name: "endDate", - type: "uint64", - }, - { - indexed: false, - internalType: "bytes", - name: "metadata", - type: "bytes", - }, - { - components: [ - { internalType: "address", name: "to", type: "address" }, - { internalType: "uint256", name: "value", type: "uint256" }, - { internalType: "bytes", name: "data", type: "bytes" }, - ], - indexed: false, - internalType: "struct IDAO.Action[]", - name: "actions", - type: "tuple[]", - }, - { - indexed: false, - internalType: "uint256", - name: "allowFailureMap", - type: "uint256", - }, - ], - name: "ProposalCreated", - type: "event", - }, - { - anonymous: false, - inputs: [ - { - indexed: true, - internalType: "uint256", - name: "proposalId", - type: "uint256", - }, - ], - name: "ProposalExecuted", - type: "event", - }, - { - anonymous: false, - inputs: [ - { - indexed: true, - internalType: "address", - name: "implementation", - type: "address", - }, - ], - name: "Upgraded", - type: "event", - }, - { - anonymous: false, - inputs: [ - { - indexed: true, - internalType: "uint256", - name: "proposalId", - type: "uint256", - }, - { - indexed: true, - internalType: "address", - name: "voter", - type: "address", - }, - { - indexed: false, - internalType: "uint256", - name: "votingPower", - type: "uint256", - }, - ], - name: "VetoCast", - type: "event", - }, - { - inputs: [], - name: "OPTIMISTIC_GOVERNANCE_INTERFACE_ID", - outputs: [{ internalType: "bytes4", name: "", type: "bytes4" }], - stateMutability: "view", - type: "function", - }, - { - inputs: [], - name: "PROPOSER_PERMISSION_ID", - outputs: [{ internalType: "bytes32", name: "", type: "bytes32" }], - stateMutability: "view", - type: "function", - }, - { - inputs: [], - name: "UPDATE_OPTIMISTIC_GOVERNANCE_SETTINGS_PERMISSION_ID", - outputs: [{ internalType: "bytes32", name: "", type: "bytes32" }], - stateMutability: "view", - type: "function", - }, - { - inputs: [], - name: "UPGRADE_PLUGIN_PERMISSION_ID", - outputs: [{ internalType: "bytes32", name: "", type: "bytes32" }], - stateMutability: "view", - type: "function", - }, - { - inputs: [{ internalType: "uint256", name: "_proposalId", type: "uint256" }], - name: "canExecute", - outputs: [{ internalType: "bool", name: "", type: "bool" }], - stateMutability: "view", - type: "function", - }, - { - inputs: [ - { internalType: "uint256", name: "_proposalId", type: "uint256" }, - { internalType: "address", name: "_voter", type: "address" }, - ], - name: "canVeto", - outputs: [{ internalType: "bool", name: "", type: "bool" }], - stateMutability: "view", - type: "function", - }, - { - inputs: [ - { internalType: "uint256", name: "_proposalId", type: "uint256" }, - { internalType: "address", name: "_member", type: "address" }, - ], - name: "claimLock", - outputs: [], - stateMutability: "nonpayable", - type: "function", - }, - { - inputs: [ - { internalType: "bytes", name: "_metadata", type: "bytes" }, - { - components: [ - { internalType: "address", name: "to", type: "address" }, - { internalType: "uint256", name: "value", type: "uint256" }, - { internalType: "bytes", name: "data", type: "bytes" }, - ], - internalType: "struct IDAO.Action[]", - name: "_actions", - type: "tuple[]", - }, - { internalType: "uint256", name: "_allowFailureMap", type: "uint256" }, - { internalType: "uint64", name: "_startDate", type: "uint64" }, - { internalType: "uint64", name: "_endDate", type: "uint64" }, - ], - name: "createProposal", - outputs: [{ internalType: "uint256", name: "proposalId", type: "uint256" }], - stateMutability: "nonpayable", - type: "function", - }, - { - inputs: [], - name: "dao", - outputs: [{ internalType: "contract IDAO", name: "", type: "address" }], - stateMutability: "view", - type: "function", - }, - { - inputs: [{ internalType: "uint256", name: "_proposalId", type: "uint256" }], - name: "execute", - outputs: [], - stateMutability: "nonpayable", - type: "function", - }, - { - inputs: [{ internalType: "uint256", name: "_proposalId", type: "uint256" }], - name: "getProposal", - outputs: [ - { internalType: "bool", name: "open", type: "bool" }, - { internalType: "bool", name: "executed", type: "bool" }, - { - components: [ - { internalType: "uint64", name: "startDate", type: "uint64" }, - { internalType: "uint64", name: "endDate", type: "uint64" }, - { internalType: "uint64", name: "snapshotBlock", type: "uint64" }, - { - internalType: "uint256", - name: "minVetoVotingPower", - type: "uint256", - }, - ], - internalType: "struct LockToVetoPlugin.ProposalParameters", - name: "parameters", - type: "tuple", - }, - { internalType: "uint256", name: "vetoTally", type: "uint256" }, - { - components: [ - { internalType: "address", name: "to", type: "address" }, - { internalType: "uint256", name: "value", type: "uint256" }, - { internalType: "bytes", name: "data", type: "bytes" }, - ], - internalType: "struct IDAO.Action[]", - name: "actions", - type: "tuple[]", - }, - { internalType: "uint256", name: "allowFailureMap", type: "uint256" }, - ], - stateMutability: "view", - type: "function", - }, - { - inputs: [], - name: "getVotingToken", - outputs: [{ internalType: "contract IERC20Upgradeable", name: "", type: "address" }], - stateMutability: "view", - type: "function", - }, - { - inputs: [ - { internalType: "uint256", name: "_proposalId", type: "uint256" }, - { internalType: "address", name: "_voter", type: "address" }, - ], - name: "hasClaimedLock", - outputs: [{ internalType: "bool", name: "", type: "bool" }], - stateMutability: "view", - type: "function", - }, - { - inputs: [ - { internalType: "uint256", name: "_proposalId", type: "uint256" }, - { internalType: "address", name: "_voter", type: "address" }, - ], - name: "hasVetoed", - outputs: [{ internalType: "bool", name: "", type: "bool" }], - stateMutability: "view", - type: "function", - }, - { - inputs: [], - name: "implementation", - outputs: [{ internalType: "address", name: "", type: "address" }], - stateMutability: "view", - type: "function", - }, - { - inputs: [ - { internalType: "contract IDAO", name: "_dao", type: "address" }, - { - components: [ - { internalType: "uint32", name: "minVetoRatio", type: "uint32" }, - { internalType: "uint64", name: "minDuration", type: "uint64" }, - { - internalType: "uint256", - name: "minProposerVotingPower", - type: "uint256", - }, - ], - internalType: "struct LockToVetoPlugin.OptimisticGovernanceSettings", - name: "_governanceSettings", - type: "tuple", - }, - { - internalType: "contract IERC20Upgradeable", - name: "_token", - type: "address", - }, - ], - name: "initialize", - outputs: [], - stateMutability: "nonpayable", - type: "function", - }, - { - inputs: [{ internalType: "address", name: "_account", type: "address" }], - name: "isMember", - outputs: [{ internalType: "bool", name: "", type: "bool" }], - stateMutability: "view", - type: "function", - }, - { - inputs: [{ internalType: "uint256", name: "_proposalId", type: "uint256" }], - name: "isMinVetoRatioReached", - outputs: [{ internalType: "bool", name: "", type: "bool" }], - stateMutability: "view", - type: "function", - }, - { - inputs: [], - name: "minDuration", - outputs: [{ internalType: "uint64", name: "", type: "uint64" }], - stateMutability: "view", - type: "function", - }, - { - inputs: [], - name: "minProposerVotingPower", - outputs: [{ internalType: "uint256", name: "", type: "uint256" }], - stateMutability: "view", - type: "function", - }, - { - inputs: [], - name: "minVetoRatio", - outputs: [{ internalType: "uint32", name: "", type: "uint32" }], - stateMutability: "view", - type: "function", - }, - { - inputs: [], - name: "pluginType", - outputs: [{ internalType: "enum IPlugin.PluginType", name: "", type: "uint8" }], - stateMutability: "pure", - type: "function", - }, - { - inputs: [], - name: "proposalCount", - outputs: [{ internalType: "uint256", name: "", type: "uint256" }], - stateMutability: "view", - type: "function", - }, - { - inputs: [], - name: "proxiableUUID", - outputs: [{ internalType: "bytes32", name: "", type: "bytes32" }], - stateMutability: "view", - type: "function", - }, - { - inputs: [{ internalType: "bytes4", name: "_interfaceId", type: "bytes4" }], - name: "supportsInterface", - outputs: [{ internalType: "bool", name: "", type: "bool" }], - stateMutability: "view", - type: "function", - }, - { - inputs: [], - name: "totalVotingPower", - outputs: [{ internalType: "uint256", name: "", type: "uint256" }], - stateMutability: "view", - type: "function", - }, - { - inputs: [ - { - components: [ - { internalType: "uint32", name: "minVetoRatio", type: "uint32" }, - { internalType: "uint64", name: "minDuration", type: "uint64" }, - { - internalType: "uint256", - name: "minProposerVotingPower", - type: "uint256", - }, - ], - internalType: "struct LockToVetoPlugin.OptimisticGovernanceSettings", - name: "_governanceSettings", - type: "tuple", - }, - ], - name: "updateOptimisticGovernanceSettings", - outputs: [], - stateMutability: "nonpayable", - type: "function", - }, - { - inputs: [{ internalType: "address", name: "newImplementation", type: "address" }], - name: "upgradeTo", - outputs: [], - stateMutability: "nonpayable", - type: "function", - }, - { - inputs: [ - { internalType: "address", name: "newImplementation", type: "address" }, - { internalType: "bytes", name: "data", type: "bytes" }, - ], - name: "upgradeToAndCall", - outputs: [], - stateMutability: "payable", - type: "function", - }, - { - inputs: [ - { internalType: "uint256", name: "_proposalId", type: "uint256" }, - { internalType: "uint256", name: "_amountToLock", type: "uint256" }, - ], - name: "veto", - outputs: [], - stateMutability: "nonpayable", - type: "function", - }, - { - inputs: [ - { internalType: "uint256", name: "_proposalId", type: "uint256" }, - { internalType: "uint256", name: "_amountToLock", type: "uint256" }, - { internalType: "uint256", name: "deadline", type: "uint256" }, - { internalType: "uint8", name: "v", type: "uint8" }, - { internalType: "bytes32", name: "r", type: "bytes32" }, - { internalType: "bytes32", name: "s", type: "bytes32" }, - ], - name: "vetoPermit", - outputs: [], - stateMutability: "nonpayable", - type: "function", - }, -] as const; diff --git a/plugins/lockToVote/artifacts/OptimisticTokenVotingPlugin.sol.ts b/plugins/lockToVote/artifacts/OptimisticTokenVotingPlugin.sol.ts deleted file mode 100644 index 80be161..0000000 --- a/plugins/lockToVote/artifacts/OptimisticTokenVotingPlugin.sol.ts +++ /dev/null @@ -1,939 +0,0 @@ -export const OptimisticTokenVotingPluginAbi = [ - { - inputs: [ - { - internalType: "address", - name: "dao", - type: "address", - }, - { - internalType: "address", - name: "where", - type: "address", - }, - { - internalType: "address", - name: "who", - type: "address", - }, - { - internalType: "bytes32", - name: "permissionId", - type: "bytes32", - }, - ], - name: "DaoUnauthorized", - type: "error", - }, - { - inputs: [ - { - internalType: "uint64", - name: "limit", - type: "uint64", - }, - { - internalType: "uint64", - name: "actual", - type: "uint64", - }, - ], - name: "DateOutOfBounds", - type: "error", - }, - { - inputs: [ - { - internalType: "uint64", - name: "limit", - type: "uint64", - }, - { - internalType: "uint64", - name: "actual", - type: "uint64", - }, - ], - name: "MinDurationOutOfBounds", - type: "error", - }, - { - inputs: [ - { - internalType: "uint256", - name: "limit", - type: "uint256", - }, - { - internalType: "uint256", - name: "actual", - type: "uint256", - }, - ], - name: "MinProposerVotingPowerOutOfBounds", - type: "error", - }, - { - inputs: [], - name: "NoVotingPower", - type: "error", - }, - { - inputs: [ - { - internalType: "address", - name: "sender", - type: "address", - }, - ], - name: "ProposalCreationForbidden", - type: "error", - }, - { - inputs: [ - { - internalType: "uint256", - name: "proposalId", - type: "uint256", - }, - ], - name: "ProposalExecutionForbidden", - type: "error", - }, - { - inputs: [ - { - internalType: "uint256", - name: "proposalId", - type: "uint256", - }, - { - internalType: "address", - name: "account", - type: "address", - }, - ], - name: "ProposalVetoingForbidden", - type: "error", - }, - { - inputs: [ - { - internalType: "uint256", - name: "limit", - type: "uint256", - }, - { - internalType: "uint256", - name: "actual", - type: "uint256", - }, - ], - name: "RatioOutOfBounds", - type: "error", - }, - { - anonymous: false, - inputs: [ - { - indexed: false, - internalType: "address", - name: "previousAdmin", - type: "address", - }, - { - indexed: false, - internalType: "address", - name: "newAdmin", - type: "address", - }, - ], - name: "AdminChanged", - type: "event", - }, - { - anonymous: false, - inputs: [ - { - indexed: true, - internalType: "address", - name: "beacon", - type: "address", - }, - ], - name: "BeaconUpgraded", - type: "event", - }, - { - anonymous: false, - inputs: [ - { - indexed: false, - internalType: "uint8", - name: "version", - type: "uint8", - }, - ], - name: "Initialized", - type: "event", - }, - { - anonymous: false, - inputs: [ - { - indexed: false, - internalType: "address[]", - name: "members", - type: "address[]", - }, - ], - name: "MembersAdded", - type: "event", - }, - { - anonymous: false, - inputs: [ - { - indexed: false, - internalType: "address[]", - name: "members", - type: "address[]", - }, - ], - name: "MembersRemoved", - type: "event", - }, - { - anonymous: false, - inputs: [ - { - indexed: true, - internalType: "address", - name: "definingContract", - type: "address", - }, - ], - name: "MembershipContractAnnounced", - type: "event", - }, - { - anonymous: false, - inputs: [ - { - indexed: false, - internalType: "uint32", - name: "minVetoRatio", - type: "uint32", - }, - { - indexed: false, - internalType: "uint64", - name: "minDuration", - type: "uint64", - }, - { - indexed: false, - internalType: "uint256", - name: "minProposerVotingPower", - type: "uint256", - }, - ], - name: "OptimisticGovernanceSettingsUpdated", - type: "event", - }, - { - anonymous: false, - inputs: [ - { - indexed: true, - internalType: "uint256", - name: "proposalId", - type: "uint256", - }, - { - indexed: true, - internalType: "address", - name: "creator", - type: "address", - }, - { - indexed: false, - internalType: "uint64", - name: "startDate", - type: "uint64", - }, - { - indexed: false, - internalType: "uint64", - name: "endDate", - type: "uint64", - }, - { - indexed: false, - internalType: "bytes", - name: "metadata", - type: "bytes", - }, - { - components: [ - { - internalType: "address", - name: "to", - type: "address", - }, - { - internalType: "uint256", - name: "value", - type: "uint256", - }, - { - internalType: "bytes", - name: "data", - type: "bytes", - }, - ], - indexed: false, - internalType: "struct IDAO.Action[]", - name: "actions", - type: "tuple[]", - }, - { - indexed: false, - internalType: "uint256", - name: "allowFailureMap", - type: "uint256", - }, - ], - name: "ProposalCreated", - type: "event", - }, - { - anonymous: false, - inputs: [ - { - indexed: true, - internalType: "uint256", - name: "proposalId", - type: "uint256", - }, - ], - name: "ProposalExecuted", - type: "event", - }, - { - anonymous: false, - inputs: [ - { - indexed: true, - internalType: "address", - name: "implementation", - type: "address", - }, - ], - name: "Upgraded", - type: "event", - }, - { - anonymous: false, - inputs: [ - { - indexed: true, - internalType: "uint256", - name: "proposalId", - type: "uint256", - }, - { - indexed: true, - internalType: "address", - name: "voter", - type: "address", - }, - { - indexed: false, - internalType: "uint256", - name: "votingPower", - type: "uint256", - }, - ], - name: "VetoCast", - type: "event", - }, - { - inputs: [], - name: "OPTIMISTIC_GOVERNANCE_INTERFACE_ID", - outputs: [ - { - internalType: "bytes4", - name: "", - type: "bytes4", - }, - ], - stateMutability: "view", - type: "function", - }, - { - inputs: [], - name: "PROPOSER_PERMISSION_ID", - outputs: [ - { - internalType: "bytes32", - name: "", - type: "bytes32", - }, - ], - stateMutability: "view", - type: "function", - }, - { - inputs: [], - name: "UPDATE_OPTIMISTIC_GOVERNANCE_SETTINGS_PERMISSION_ID", - outputs: [ - { - internalType: "bytes32", - name: "", - type: "bytes32", - }, - ], - stateMutability: "view", - type: "function", - }, - { - inputs: [], - name: "UPGRADE_PLUGIN_PERMISSION_ID", - outputs: [ - { - internalType: "bytes32", - name: "", - type: "bytes32", - }, - ], - stateMutability: "view", - type: "function", - }, - { - inputs: [ - { - internalType: "uint256", - name: "_proposalId", - type: "uint256", - }, - ], - name: "canExecute", - outputs: [ - { - internalType: "bool", - name: "", - type: "bool", - }, - ], - stateMutability: "view", - type: "function", - }, - { - inputs: [ - { - internalType: "uint256", - name: "_proposalId", - type: "uint256", - }, - { - internalType: "address", - name: "_voter", - type: "address", - }, - ], - name: "canVeto", - outputs: [ - { - internalType: "bool", - name: "", - type: "bool", - }, - ], - stateMutability: "view", - type: "function", - }, - { - inputs: [ - { - internalType: "bytes", - name: "_metadata", - type: "bytes", - }, - { - components: [ - { - internalType: "address", - name: "to", - type: "address", - }, - { - internalType: "uint256", - name: "value", - type: "uint256", - }, - { - internalType: "bytes", - name: "data", - type: "bytes", - }, - ], - internalType: "struct IDAO.Action[]", - name: "_actions", - type: "tuple[]", - }, - { - internalType: "uint256", - name: "_allowFailureMap", - type: "uint256", - }, - { - internalType: "uint64", - name: "_startDate", - type: "uint64", - }, - { - internalType: "uint64", - name: "_endDate", - type: "uint64", - }, - ], - name: "createProposal", - outputs: [ - { - internalType: "uint256", - name: "proposalId", - type: "uint256", - }, - ], - stateMutability: "nonpayable", - type: "function", - }, - { - inputs: [], - name: "dao", - outputs: [ - { - internalType: "contract IDAO", - name: "", - type: "address", - }, - ], - stateMutability: "view", - type: "function", - }, - { - inputs: [ - { - internalType: "uint256", - name: "_proposalId", - type: "uint256", - }, - ], - name: "execute", - outputs: [], - stateMutability: "nonpayable", - type: "function", - }, - { - inputs: [ - { - internalType: "uint256", - name: "_proposalId", - type: "uint256", - }, - ], - name: "getProposal", - outputs: [ - { - internalType: "bool", - name: "open", - type: "bool", - }, - { - internalType: "bool", - name: "executed", - type: "bool", - }, - { - components: [ - { - internalType: "uint64", - name: "startDate", - type: "uint64", - }, - { - internalType: "uint64", - name: "endDate", - type: "uint64", - }, - { - internalType: "uint64", - name: "snapshotBlock", - type: "uint64", - }, - { - internalType: "uint256", - name: "minVetoVotingPower", - type: "uint256", - }, - ], - internalType: "struct OptimisticTokenVotingPlugin.ProposalParameters", - name: "parameters", - type: "tuple", - }, - { - internalType: "uint256", - name: "vetoTally", - type: "uint256", - }, - { - components: [ - { - internalType: "address", - name: "to", - type: "address", - }, - { - internalType: "uint256", - name: "value", - type: "uint256", - }, - { - internalType: "bytes", - name: "data", - type: "bytes", - }, - ], - internalType: "struct IDAO.Action[]", - name: "actions", - type: "tuple[]", - }, - { - internalType: "uint256", - name: "allowFailureMap", - type: "uint256", - }, - ], - stateMutability: "view", - type: "function", - }, - { - inputs: [], - name: "getVotingToken", - outputs: [ - { - internalType: "contract IVotesUpgradeable", - name: "", - type: "address", - }, - ], - stateMutability: "view", - type: "function", - }, - { - inputs: [ - { - internalType: "uint256", - name: "_proposalId", - type: "uint256", - }, - { - internalType: "address", - name: "_voter", - type: "address", - }, - ], - name: "hasVetoed", - outputs: [ - { - internalType: "bool", - name: "", - type: "bool", - }, - ], - stateMutability: "view", - type: "function", - }, - { - inputs: [], - name: "implementation", - outputs: [ - { - internalType: "address", - name: "", - type: "address", - }, - ], - stateMutability: "view", - type: "function", - }, - { - inputs: [ - { - internalType: "contract IDAO", - name: "_dao", - type: "address", - }, - { - components: [ - { - internalType: "uint32", - name: "minVetoRatio", - type: "uint32", - }, - { - internalType: "uint64", - name: "minDuration", - type: "uint64", - }, - { - internalType: "uint256", - name: "minProposerVotingPower", - type: "uint256", - }, - ], - internalType: "struct OptimisticTokenVotingPlugin.OptimisticGovernanceSettings", - name: "_governanceSettings", - type: "tuple", - }, - { - internalType: "contract IVotesUpgradeable", - name: "_token", - type: "address", - }, - ], - name: "initialize", - outputs: [], - stateMutability: "nonpayable", - type: "function", - }, - { - inputs: [ - { - internalType: "address", - name: "_account", - type: "address", - }, - ], - name: "isMember", - outputs: [ - { - internalType: "bool", - name: "", - type: "bool", - }, - ], - stateMutability: "view", - type: "function", - }, - { - inputs: [ - { - internalType: "uint256", - name: "_proposalId", - type: "uint256", - }, - ], - name: "isMinVetoRatioReached", - outputs: [ - { - internalType: "bool", - name: "", - type: "bool", - }, - ], - stateMutability: "view", - type: "function", - }, - { - inputs: [], - name: "minDuration", - outputs: [ - { - internalType: "uint64", - name: "", - type: "uint64", - }, - ], - stateMutability: "view", - type: "function", - }, - { - inputs: [], - name: "minProposerVotingPower", - outputs: [ - { - internalType: "uint256", - name: "", - type: "uint256", - }, - ], - stateMutability: "view", - type: "function", - }, - { - inputs: [], - name: "minVetoRatio", - outputs: [ - { - internalType: "uint32", - name: "", - type: "uint32", - }, - ], - stateMutability: "view", - type: "function", - }, - { - inputs: [], - name: "pluginType", - outputs: [ - { - internalType: "enum IPlugin.PluginType", - name: "", - type: "uint8", - }, - ], - stateMutability: "pure", - type: "function", - }, - { - inputs: [], - name: "proposalCount", - outputs: [ - { - internalType: "uint256", - name: "", - type: "uint256", - }, - ], - stateMutability: "view", - type: "function", - }, - { - inputs: [], - name: "proxiableUUID", - outputs: [ - { - internalType: "bytes32", - name: "", - type: "bytes32", - }, - ], - stateMutability: "view", - type: "function", - }, - { - inputs: [ - { - internalType: "bytes4", - name: "_interfaceId", - type: "bytes4", - }, - ], - name: "supportsInterface", - outputs: [ - { - internalType: "bool", - name: "", - type: "bool", - }, - ], - stateMutability: "view", - type: "function", - }, - { - inputs: [ - { - internalType: "uint256", - name: "_blockNumber", - type: "uint256", - }, - ], - name: "totalVotingPower", - outputs: [ - { - internalType: "uint256", - name: "", - type: "uint256", - }, - ], - stateMutability: "view", - type: "function", - }, - { - inputs: [ - { - components: [ - { - internalType: "uint32", - name: "minVetoRatio", - type: "uint32", - }, - { - internalType: "uint64", - name: "minDuration", - type: "uint64", - }, - { - internalType: "uint256", - name: "minProposerVotingPower", - type: "uint256", - }, - ], - internalType: "struct OptimisticTokenVotingPlugin.OptimisticGovernanceSettings", - name: "_governanceSettings", - type: "tuple", - }, - ], - name: "updateOptimisticGovernanceSettings", - outputs: [], - stateMutability: "nonpayable", - type: "function", - }, - { - inputs: [ - { - internalType: "address", - name: "newImplementation", - type: "address", - }, - ], - name: "upgradeTo", - outputs: [], - stateMutability: "nonpayable", - type: "function", - }, - { - inputs: [ - { - internalType: "address", - name: "newImplementation", - type: "address", - }, - { - internalType: "bytes", - name: "data", - type: "bytes", - }, - ], - name: "upgradeToAndCall", - outputs: [], - stateMutability: "payable", - type: "function", - }, - { - inputs: [ - { - internalType: "uint256", - name: "_proposalId", - type: "uint256", - }, - ], - name: "veto", - outputs: [], - stateMutability: "nonpayable", - type: "function", - }, -] as const; diff --git a/plugins/lockToVote/components/proposal/header.tsx b/plugins/lockToVote/components/proposal/header.tsx deleted file mode 100644 index 13981c0..0000000 --- a/plugins/lockToVote/components/proposal/header.tsx +++ /dev/null @@ -1,101 +0,0 @@ -import { AvatarIcon, Breadcrumbs, Button, Heading, IBreadcrumbsLink, IconType, ProposalStatus, Tag } from "@aragon/ods"; -import { Publisher } from "@/components/publisher"; -import { Proposal } from "../../utils/types"; -import { useProposalStatus } from "../../hooks/useProposalVariantStatus"; -import { Else, ElseIf, If, Then } from "@/components/if"; -import { getSimpleRelativeTimeFromDate } from "@/utils/dates"; -import { useProposalClaimLock } from "../../hooks/useProposalClaimLock"; -import { HeaderSection } from "@/components/layout/header-section"; -import { getTagVariantFromStatus } from "@/utils/ui-variants"; -import { capitalizeFirstLetter } from "@/utils/text"; -import dayjs from "dayjs"; -import { useAccount } from "wagmi"; -import { useWeb3Modal } from "@web3modal/wagmi/react"; - -const DEFAULT_PROPOSAL_TITLE = "(No proposal title)"; -const DEFAULT_PROPOSAL_SUMMARY = "(No proposal summary)"; - -interface ProposalHeaderProps { - proposalIdx: number; - proposal: Proposal; -} - -const ProposalHeader: React.FC = ({ proposalIdx, proposal }) => { - const proposalStatus = useProposalStatus(proposal); - const tagVariant = getTagVariantFromStatus(proposalStatus); - const { open } = useWeb3Modal(); - const { isConnected } = useAccount(); - const { claimLockProposal, isConfirming: isConfirmingClaimLock, hasClaimed } = useProposalClaimLock(proposalIdx); - - const breadcrumbs: IBreadcrumbsLink[] = [{ label: "Proposals", href: "#/" }, { label: proposalIdx.toString() }]; - const isEmergency = proposal.parameters.startDate === 0n; - const endDateIsInThePast = Number(proposal.parameters.endDate) * 1000 < Date.now(); - - return ( -
- {/* Wrapper */} - - - {/* Title & description */} -
-
- {proposal.title || DEFAULT_PROPOSAL_TITLE} - {isEmergency && } -
-

{proposal.summary || DEFAULT_PROPOSAL_SUMMARY}

-
- {/* Metadata */} -
-
- - -
-
- -
- - - The proposal has been defeated - - - The veto period is over - - - Active for - - {getSimpleRelativeTimeFromDate(dayjs(Number(proposal.parameters.endDate) * 1000))} - - - -
-
-
- -
- - - - - - - - - - -
-
-
- ); -}; - -export default ProposalHeader; diff --git a/plugins/lockToVote/components/proposal/index.tsx b/plugins/lockToVote/components/proposal/index.tsx deleted file mode 100644 index 6aaa588..0000000 --- a/plugins/lockToVote/components/proposal/index.tsx +++ /dev/null @@ -1,105 +0,0 @@ -import Link from "next/link"; -import { Card, ProposalStatus, ProposalDataListItem } from "@aragon/ods"; -import { PleaseWaitSpinner } from "@/components/please-wait"; -import { useProposalVeto } from "../../hooks/useProposalVeto"; -import { useProposalStatus } from "../../hooks/useProposalVariantStatus"; -import { usePastSupply } from "../../hooks/usePastSupply"; -import { useToken } from "../../hooks/useToken"; -import { PUB_TOKEN_SYMBOL } from "@/constants"; -import { useAccount } from "wagmi"; -import { formatEther } from "viem"; - -const DEFAULT_PROPOSAL_METADATA_TITLE = "(No proposal title)"; -const DEFAULT_PROPOSAL_METADATA_SUMMARY = "(The metadata of the proposal is not available)"; - -type ProposalInputs = { - proposalIndex: number; -}; - -export default function ProposalCard(props: ProposalInputs) { - const { address } = useAccount(); - const { proposal, proposalFetchStatus, vetoes } = useProposalVeto(props.proposalIndex); - const pastSupply = usePastSupply(proposal?.parameters.snapshotBlock); - const { symbol: tokenSymbol } = useToken(); - - const proposalStatus = useProposalStatus(proposal!); - const showLoading = getShowProposalLoading(proposal, proposalFetchStatus); - const hasVetoed = vetoes?.some((veto) => veto.voter === address); - - if (!proposal && showLoading) { - return ( -
- - - - - -
- ); - } else if (!proposal?.title && !proposal?.summary) { - // We have the proposal but no metadata yet - return ( - - - - - - - - ); - } else if (proposalFetchStatus.metadataReady && !proposal?.title) { - return ( - - -
-

- {Number(props.proposalIndex) + 1} - {DEFAULT_PROPOSAL_METADATA_TITLE} -

-

{DEFAULT_PROPOSAL_METADATA_SUMMARY}

-
-
- - ); - } - - let vetoPercentage = 0; - if (proposal?.vetoTally && pastSupply && proposal.parameters.minVetoVotingPower) { - vetoPercentage = Number( - (BigInt(1000) * proposal.vetoTally) / - ((pastSupply * BigInt(proposal.parameters.minVetoVotingPower)) / BigInt(10000000)) - ); - } - - return ( - - ); -} - -function getShowProposalLoading( - proposal: ReturnType["proposal"], - status: ReturnType["proposalFetchStatus"] -) { - if (!proposal || status.proposalLoading) return true; - else if (status.metadataLoading && !status.metadataError) return true; - else if (!proposal?.title && !status.metadataError) return true; - - return false; -} diff --git a/plugins/lockToVote/components/vote/tally.tsx b/plugins/lockToVote/components/vote/tally.tsx deleted file mode 100644 index 82913b1..0000000 --- a/plugins/lockToVote/components/vote/tally.tsx +++ /dev/null @@ -1,35 +0,0 @@ -import { compactNumber } from "@/utils/numbers"; -import { FC, ReactNode } from "react"; -import { formatUnits } from "viem"; - -interface VoteTallyProps { - voteCount: bigint; - votePercentage: number; -} - -const VetoTally: FC = ({ voteCount, votePercentage }) => ( - -
-

Vetoed

-

{compactNumber(formatUnits(voteCount || BigInt(0), 18))}

-
-
-
-
- -); - -// This should be encapsulated as soon as ODS exports this widget -const Card = function ({ children }: { children: ReactNode }) { - return ( -
- {children} -
- ); -}; - -export default VetoTally; diff --git a/plugins/lockToVote/components/vote/vetoes-section.tsx b/plugins/lockToVote/components/vote/vetoes-section.tsx deleted file mode 100644 index e66b52c..0000000 --- a/plugins/lockToVote/components/vote/vetoes-section.tsx +++ /dev/null @@ -1,42 +0,0 @@ -import Blockies from "react-blockies"; -import { VetoCastEvent } from "../../utils/types"; -import { formatUnits } from "viem"; -import { AddressText } from "@/components/text/address"; -import { Card } from "@aragon/ods"; -import { compactNumber } from "@/utils/numbers"; -import { If } from "@/components/if"; - -export default function VetoesSection({ vetoes }: { vetoes: Array }) { - return ( -
-
- -

The proposal has no vetoes

-
-
- {vetoes.map((veto, i) => ( - - ))} -
-
-
- ); -} - -const VetoCard = function ({ veto }: { veto: VetoCastEvent }) { - return ( - -
-
- -
- {veto?.voter} -

- {compactNumber(formatUnits(veto.votingPower ?? BigInt(0), 18))} votes -

-
-
-
-
- ); -}; diff --git a/plugins/lockToVote/hooks/useCanCreateProposal.ts b/plugins/lockToVote/hooks/useCanCreateProposal.ts deleted file mode 100644 index d19ca77..0000000 --- a/plugins/lockToVote/hooks/useCanCreateProposal.ts +++ /dev/null @@ -1,90 +0,0 @@ -import { type Address, keccak256, toHex } from "viem"; -import { useState, useEffect } from "react"; -import { useBalance, useAccount, useReadContracts, useReadContract } from "wagmi"; -import { LockToVetoPluginAbi } from "@/plugins/lockToVote/artifacts/LockToVetoPlugin.sol"; -import { DaoAbi } from "@/artifacts/DAO.sol"; -import { PUB_CHAIN, PUB_LOCK_TO_VOTE_PLUGIN_ADDRESS } from "@/constants"; -import { ADDRESS_ZERO } from "@/utils/evm"; - -export function useCanCreateProposal() { - const { address } = useAccount(); - - const [minProposerVotingPower, setMinProposerVotingPower] = useState(); - const [votingToken, setVotingToken] = useState
(); - const [daoAddress, setDaoAddress] = useState
(); - const [hasCreatePermission, setHasCreatePermission] = useState(false); - const { data: balance } = useBalance({ - address, - token: votingToken, - chainId: PUB_CHAIN.id, - query: { - enabled: !!address, - }, - }); - - const { data: contractReads } = useReadContracts({ - contracts: [ - { - chainId: PUB_CHAIN.id, - address: PUB_LOCK_TO_VOTE_PLUGIN_ADDRESS, - abi: LockToVetoPluginAbi, - functionName: "minProposerVotingPower", - }, - { - chainId: PUB_CHAIN.id, - address: PUB_LOCK_TO_VOTE_PLUGIN_ADDRESS, - abi: LockToVetoPluginAbi, - functionName: "getVotingToken", - }, - { - chainId: PUB_CHAIN.id, - address: PUB_LOCK_TO_VOTE_PLUGIN_ADDRESS, - abi: LockToVetoPluginAbi, - functionName: "dao", - }, - // TODO: This needs to be checking as well if address has the DAO permission to create props - ], - }); - - // Check if PROPOSER_PERMISSION is granted to the current wallet - const { - data: hasCreatePermissionData, - refetch: hasCreatePermissionRefetch, - status: hasCreatePermissionStatus, - } = useReadContract({ - chainId: PUB_CHAIN.id, - address: daoAddress, - abi: DaoAbi, - functionName: "hasPermission", - // where, who, permissionId, data - args: [PUB_LOCK_TO_VOTE_PLUGIN_ADDRESS, address ?? ADDRESS_ZERO, keccak256(toHex("PROPOSER_PERMISSION")), "0x"], - query: { - enabled: !!daoAddress && !!address, - }, - }); - - useEffect(() => { - if (!contractReads?.length || contractReads?.length < 2) return; - - setMinProposerVotingPower(contractReads[0].result as bigint); - setVotingToken(contractReads[1].result as Address); - setDaoAddress(contractReads[2].result as Address); - }, [contractReads?.[0]?.status, contractReads?.[1]?.status, contractReads?.[2]?.status]); - - useEffect(() => { - setHasCreatePermission(!!hasCreatePermissionData); - }, [hasCreatePermissionStatus]); - - useEffect(() => { - hasCreatePermissionRefetch(); - }, [daoAddress, address]); - - if (!address) return false; - else if (!hasCreatePermission) return false; - else if (!balance) return false; - else if (minProposerVotingPower) { - if (balance?.value < minProposerVotingPower) return false; - } - - return true; -} diff --git a/plugins/lockToVote/hooks/useCreateProposal.ts b/plugins/lockToVote/hooks/useCreateProposal.ts deleted file mode 100644 index 899bb7f..0000000 --- a/plugins/lockToVote/hooks/useCreateProposal.ts +++ /dev/null @@ -1,107 +0,0 @@ -import { useRouter } from "next/router"; -import { useState } from "react"; -import { ProposalMetadata, RawAction } from "@/utils/types"; -import { useAlerts } from "@/context/Alerts"; -import { PUB_APP_NAME, PUB_CHAIN, PUB_LOCK_TO_VOTE_PLUGIN_ADDRESS, PUB_PROJECT_URL } from "@/constants"; -import { uploadToPinata } from "@/utils/ipfs"; -import { LockToVetoPluginAbi } from "../artifacts/LockToVetoPlugin.sol"; -import { URL_PATTERN } from "@/utils/input-values"; -import { toHex } from "viem"; -import { useTransactionManager } from "@/hooks/useTransactionManager"; - -const UrlRegex = new RegExp(URL_PATTERN); - -export function useCreateProposal() { - const { push } = useRouter(); - const { addAlert } = useAlerts(); - const [isCreating, setIsCreating] = useState(false); - const [title, setTitle] = useState(""); - const [summary, setSummary] = useState(""); - const [description, setDescription] = useState(""); - const [actions, setActions] = useState([]); - const [resources, setResources] = useState<{ name: string; url: string }[]>([ - { name: PUB_APP_NAME, url: PUB_PROJECT_URL }, - ]); - - const { writeContract: createProposalWrite, isConfirming } = useTransactionManager({ - onSuccessMessage: "Proposal created", - onSuccess() { - setTimeout(() => { - push("#/"); - window.scroll(0, 0); - }, 1000 * 2); - }, - onErrorMessage: "Could not create the proposal", - onError: () => setIsCreating(false), - }); - - const submitProposal = async () => { - // Check metadata - if (!title.trim()) { - return addAlert("Invalid proposal details", { - description: "Please enter a title", - type: "error", - }); - } - - if (!summary.trim()) { - return addAlert("Invalid proposal details", { - description: "Please enter a summary of what the proposal is about", - type: "error", - }); - } - - for (const item of resources) { - if (!item.name.trim()) { - return addAlert("Invalid resource name", { - description: "Please enter a name for all the resources", - type: "error", - }); - } else if (!UrlRegex.test(item.url.trim())) { - return addAlert("Invalid resource URL", { - description: "Please enter valid URL for all the resources", - type: "error", - }); - } - } - - try { - setIsCreating(true); - const proposalMetadataJsonObject: ProposalMetadata = { - title, - summary, - description, - resources, - }; - - const ipfsPin = await uploadToPinata(JSON.stringify(proposalMetadataJsonObject)); - const startDate = BigInt(0); - const endDate = BigInt(0); - - createProposalWrite({ - chainId: PUB_CHAIN.id, - abi: LockToVetoPluginAbi, - address: PUB_LOCK_TO_VOTE_PLUGIN_ADDRESS, - functionName: "createProposal", - args: [toHex(ipfsPin), actions, BigInt(0), startDate, endDate], - }); - } catch (err) { - setIsCreating(false); - } - }; - - return { - isCreating: isCreating || isConfirming || status === "pending", - title, - summary, - description, - actions, - resources, - setTitle, - setSummary, - setDescription, - setActions, - setResources, - submitProposal, - }; -} diff --git a/plugins/lockToVote/hooks/usePastSupply.ts b/plugins/lockToVote/hooks/usePastSupply.ts deleted file mode 100644 index caec6bc..0000000 --- a/plugins/lockToVote/hooks/usePastSupply.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { PUB_TOKEN_ADDRESS } from "@/constants"; -import { useReadContract } from "wagmi"; -import { parseAbi } from "viem"; - -const erc20Votes = parseAbi(["function getPastTotalSupply(uint256 blockNumber) view returns (uint256)"]); - -export function usePastSupply(snapshotBlock: bigint | undefined) { - const { data: pastSupply } = useReadContract({ - address: PUB_TOKEN_ADDRESS, - abi: erc20Votes, - functionName: "getPastTotalSupply", - args: [BigInt(snapshotBlock || 0)], - }); - - return pastSupply || BigInt(0); -} diff --git a/plugins/lockToVote/hooks/useProposal.ts b/plugins/lockToVote/hooks/useProposal.ts deleted file mode 100644 index ce527b8..0000000 --- a/plugins/lockToVote/hooks/useProposal.ts +++ /dev/null @@ -1,137 +0,0 @@ -import { useState, useEffect } from "react"; -import { useBlockNumber, usePublicClient, useReadContract } from "wagmi"; -import { getAbiItem } from "viem"; -import { ProposalMetadata, RawAction } from "@/utils/types"; -import { Proposal, ProposalParameters } from "@/plugins/lockToVote/utils/types"; -import { PUB_CHAIN, PUB_LOCK_TO_VOTE_PLUGIN_ADDRESS } from "@/constants"; -import { useMetadata } from "@/hooks/useMetadata"; -import { LockToVetoPluginAbi } from "../artifacts/LockToVetoPlugin.sol"; - -type ProposalCreatedLogResponse = { - args: { - actions: RawAction[]; - allowFailureMap: bigint; - creator: string; - endDate: bigint; - startDate: bigint; - metadata: string; - proposalId: bigint; - }; -}; - -const ProposalCreatedEvent = getAbiItem({ - abi: LockToVetoPluginAbi, - name: "ProposalCreated", -}); - -export function useProposal(proposalIdx: number, autoRefresh = false) { - const publicClient = usePublicClient(); - const [proposalCreationEvent, setProposalCreationEvent] = useState(); - const [metadataUri, setMetadataUri] = useState(); - const { data: blockNumber } = useBlockNumber({ watch: true }); - - // Proposal on-chain data - const { - data: proposalResult, - error: proposalError, - fetchStatus: proposalFetchStatus, - refetch: proposalRefetch, - } = useReadContract({ - address: PUB_LOCK_TO_VOTE_PLUGIN_ADDRESS, - abi: LockToVetoPluginAbi, - functionName: "getProposal", - args: [BigInt(proposalIdx)], - chainId: PUB_CHAIN.id, - }); - const proposalData = decodeProposalResultData(proposalResult as any); - - useEffect(() => { - if (autoRefresh) proposalRefetch(); - }, [!blockNumber || blockNumber % BigInt(3) === BigInt(0)]); - - // Creation event - useEffect(() => { - if (!proposalData || !publicClient) return; - - publicClient - .getLogs({ - address: PUB_LOCK_TO_VOTE_PLUGIN_ADDRESS, - event: ProposalCreatedEvent, - args: { - proposalId: BigInt(proposalIdx), - }, - fromBlock: proposalData.parameters.snapshotBlock, - toBlock: proposalData.parameters.startDate, - }) - .then((logs) => { - if (!logs || !logs.length) throw new Error("No creation logs"); - - const log: ProposalCreatedLogResponse = logs[0] as any; - setProposalCreationEvent(log.args); - setMetadataUri(log.args.metadata); - }) - .catch((err) => { - console.error("Could not fetch the proposal details", err); - return null; - }); - }, [proposalData?.vetoTally, !!publicClient]); - - // JSON metadata - const { - data: metadataContent, - isLoading: metadataLoading, - error: metadataError, - } = useMetadata(metadataUri); - - const proposal = arrangeProposalData(proposalData, proposalCreationEvent, metadataContent); - - return { - proposal, - refetch: proposalRefetch, - status: { - proposalReady: proposalFetchStatus === "idle", - proposalLoading: proposalFetchStatus === "fetching", - proposalError, - metadataReady: !metadataError && !metadataLoading && !!metadataContent, - metadataLoading, - metadataError: metadataError !== undefined, - }, - }; -} - -// Helpers - -function decodeProposalResultData(data?: Array) { - if (!data?.length || data.length < 6) return null; - - return { - active: data[0] as boolean, - executed: data[1] as boolean, - parameters: data[2] as ProposalParameters, - vetoTally: data[3] as bigint, - actions: data[4] as Array, - allowFailureMap: data[5] as bigint, - }; -} - -function arrangeProposalData( - proposalData?: ReturnType, - creationEvent?: ProposalCreatedLogResponse["args"], - metadata?: ProposalMetadata -): Proposal | null { - if (!proposalData) return null; - - return { - actions: proposalData.actions, - active: proposalData.active, - executed: proposalData.executed, - parameters: proposalData.parameters, - vetoTally: proposalData.vetoTally, - allowFailureMap: proposalData.allowFailureMap, - creator: creationEvent?.creator || "", - title: metadata?.title || "", - summary: metadata?.summary || "", - description: metadata?.description || "", - resources: metadata?.resources || [], - }; -} diff --git a/plugins/lockToVote/hooks/useProposalClaimLock.ts b/plugins/lockToVote/hooks/useProposalClaimLock.ts deleted file mode 100644 index 02958e7..0000000 --- a/plugins/lockToVote/hooks/useProposalClaimLock.ts +++ /dev/null @@ -1,57 +0,0 @@ -import { useAccount, useReadContract, useWaitForTransactionReceipt, useWriteContract } from "wagmi"; -import { useRouter } from "next/router"; -import { PUB_CHAIN, PUB_LOCK_TO_VOTE_PLUGIN_ADDRESS } from "@/constants"; -import { LockToVetoPluginAbi } from "../artifacts/LockToVetoPlugin.sol"; -import { useTransactionManager } from "@/hooks/useTransactionManager"; -import { useState } from "react"; - -export function useProposalClaimLock(proposalIdx: number) { - const { reload } = useRouter(); - const account = useAccount(); - const [isClaiming, setIsClaiming] = useState(false); - - const { data: hasClaimed } = useReadContract({ - address: PUB_LOCK_TO_VOTE_PLUGIN_ADDRESS, - abi: LockToVetoPluginAbi, - chainId: PUB_CHAIN.id, - functionName: "hasClaimedLock", - args: [BigInt(proposalIdx), account.address!], - query: { - enabled: !!account.address, - }, - }); - - const { writeContract, isConfirming, isConfirmed } = useTransactionManager({ - onSuccessMessage: "Claim executed", - onSuccess() { - reload(); - setIsClaiming(false); - }, - onErrorMessage: "Could not claim the locked tokens", - onErrorDescription: "Please get in touch with us", - onError() { - setIsClaiming(false); - }, - }); - - const claimLockProposal = () => { - if (hasClaimed) return; - - setIsClaiming(true); - - writeContract({ - chainId: PUB_CHAIN.id, - abi: LockToVetoPluginAbi, - address: PUB_LOCK_TO_VOTE_PLUGIN_ADDRESS, - functionName: "claimLock", - args: [BigInt(proposalIdx), account.address!], - }); - }; - - return { - claimLockProposal, - hasClaimed: !!hasClaimed, - isConfirming: isConfirming || isClaiming, - isConfirmed, - }; -} diff --git a/plugins/lockToVote/hooks/useProposalExecute.ts b/plugins/lockToVote/hooks/useProposalExecute.ts deleted file mode 100644 index 0955017..0000000 --- a/plugins/lockToVote/hooks/useProposalExecute.ts +++ /dev/null @@ -1,58 +0,0 @@ -import { useState } from "react"; -import { useReadContract } from "wagmi"; -import { useRouter } from "next/router"; -import { PUB_CHAIN, PUB_LOCK_TO_VOTE_PLUGIN_ADDRESS } from "@/constants"; -import { LockToVetoPluginAbi } from "../artifacts/LockToVetoPlugin.sol"; -import { useTransactionManager } from "@/hooks/useTransactionManager"; -import { DaoAbi } from "@/artifacts/DAO.sol"; - -export function useProposalExecute(proposalIdx: number) { - const { reload } = useRouter(); - const [isExecuting, setIsExecuting] = useState(false); - - const { - data: canExecute, - isError: isCanVoteError, - isLoading: isCanVoteLoading, - } = useReadContract({ - address: PUB_LOCK_TO_VOTE_PLUGIN_ADDRESS, - abi: LockToVetoPluginAbi, - chainId: PUB_CHAIN.id, - functionName: "canExecute", - args: [BigInt(proposalIdx)], - }); - - const { writeContract, isConfirming, isConfirmed } = useTransactionManager({ - onSuccessMessage: "Proposal executed", - onSuccess() { - setTimeout(() => reload(), 1000 * 2); - }, - onErrorMessage: "Could not execute the proposal", - onErrorDescription: "The proposal may contain actions with invalid operations", - onError() { - setIsExecuting(false); - }, - }); - - const executeProposal = () => { - if (!canExecute) return; - else if (typeof proposalIdx === "undefined") return; - - setIsExecuting(true); - - writeContract({ - chainId: PUB_CHAIN.id, - abi: LockToVetoPluginAbi.concat(DaoAbi as any), - address: PUB_LOCK_TO_VOTE_PLUGIN_ADDRESS, - functionName: "execute", - args: [BigInt(proposalIdx)], - }); - }; - - return { - executeProposal, - canExecute: !isCanVoteError && !isCanVoteLoading && !isConfirmed && !!canExecute, - isConfirming: isExecuting || isConfirming, - isConfirmed, - }; -} diff --git a/plugins/lockToVote/hooks/useProposalVariantStatus.ts b/plugins/lockToVote/hooks/useProposalVariantStatus.ts deleted file mode 100644 index a1c9875..0000000 --- a/plugins/lockToVote/hooks/useProposalVariantStatus.ts +++ /dev/null @@ -1,60 +0,0 @@ -import { useState, useEffect } from "react"; -import { Proposal } from "../utils/types"; -import { ProposalStatus } from "@aragon/ods"; -import { useToken } from "./useToken"; - -export const useProposalVariantStatus = (proposal: Proposal) => { - const [status, setStatus] = useState({ variant: "", label: "" }); - const { tokenSupply: totalSupply } = useToken(); - - useEffect(() => { - if (!proposal || !proposal?.parameters || !totalSupply) return; - const minVetoVotingPower = (totalSupply * BigInt(proposal.parameters.minVetoVotingPower)) / BigInt(1_000_000); - - if (proposal?.active) { - setStatus({ variant: "info", label: "Active" }); - } else if (proposal?.executed) { - setStatus({ variant: "primary", label: "Executed" }); - } else if (proposal?.vetoTally >= minVetoVotingPower) { - setStatus({ variant: "critical", label: "Defeated" }); - } else { - setStatus({ variant: "success", label: "Executable" }); - } - }, [ - proposal?.vetoTally, - proposal?.active, - proposal?.executed, - proposal?.parameters?.minVetoVotingPower, - totalSupply, - ]); - - return status; -}; - -export const useProposalStatus = (proposal: Proposal) => { - const [status, setStatus] = useState(); - const { tokenSupply: totalSupply } = useToken(); - useEffect(() => { - if (!proposal || !proposal?.parameters || !totalSupply) return; - - const minVetoVotingPower = (totalSupply * BigInt(proposal.parameters.minVetoVotingPower)) / BigInt(1_000_000); - - if (proposal?.active) { - setStatus(ProposalStatus.ACTIVE); - } else if (proposal?.executed) { - setStatus(ProposalStatus.EXECUTED); - } else if (proposal?.vetoTally >= minVetoVotingPower) { - setStatus(ProposalStatus.VETOED); - } else { - setStatus(ProposalStatus.ACCEPTED); - } - }, [ - proposal?.vetoTally, - proposal?.active, - proposal?.executed, - proposal?.parameters?.minVetoVotingPower, - totalSupply, - ]); - - return status; -}; diff --git a/plugins/lockToVote/hooks/useProposalVeto.ts b/plugins/lockToVote/hooks/useProposalVeto.ts deleted file mode 100644 index 8124ce9..0000000 --- a/plugins/lockToVote/hooks/useProposalVeto.ts +++ /dev/null @@ -1,68 +0,0 @@ -import { useReadContract, useAccount } from "wagmi"; -import { Address } from "viem"; -import { ERC20PermitAbi } from "@/artifacts/ERC20Permit.sol"; -import { useProposal } from "./useProposal"; -import { useProposalVetoes } from "./useProposalVetoes"; -import { useUserCanVeto } from "./useUserCanVeto"; -import { LockToVetoPluginAbi } from "../artifacts/LockToVetoPlugin.sol"; -import { usePermit } from "@/hooks/usePermit"; -import { PUB_TOKEN_ADDRESS, PUB_LOCK_TO_VOTE_PLUGIN_ADDRESS } from "@/constants"; -import { useTransactionManager } from "@/hooks/useTransactionManager"; -import { ADDRESS_ZERO } from "@/utils/evm"; - -export function useProposalVeto(proposalId: number) { - const { proposal, status: proposalFetchStatus, refetch: refetchProposal } = useProposal(proposalId, true); - const vetoes = useProposalVetoes(PUB_LOCK_TO_VOTE_PLUGIN_ADDRESS, proposalId, proposal); - const { signPermit, refetchPermitData } = usePermit(); - const { address } = useAccount(); - - const { data: balanceData } = useReadContract({ - address: PUB_TOKEN_ADDRESS, - abi: ERC20PermitAbi, - functionName: "balanceOf", - args: [address || ADDRESS_ZERO], - }); - const { canVeto, refetch: refetchCanVeto } = useUserCanVeto(proposalId); - - const { - writeContract, - status: vetoingStatus, - isConfirming, - isConfirmed, - } = useTransactionManager({ - onSuccessMessage: "Veto registered", - onSuccess() { - refetchCanVeto(); - refetchProposal(); - refetchPermitData(); - }, - onErrorMessage: "Could not submit the veto", - }); - - const vetoProposal = () => { - const dest: Address = PUB_LOCK_TO_VOTE_PLUGIN_ADDRESS; - const value = BigInt(Number(balanceData)); - const deadline = BigInt(Math.floor(Date.now() / 1000) + 60 * 60); // 1 hour from now - - signPermit(dest, value, deadline).then((sig) => { - if (!sig?.yParity) throw new Error("Invalid signature"); - - writeContract({ - abi: LockToVetoPluginAbi, - address: dest, - functionName: "vetoPermit", - args: [BigInt(proposalId), value, deadline, sig.yParity, sig.r, sig.s], - }); - }); - }; - - return { - proposal, - proposalFetchStatus, - vetoes, - canVeto: !!canVeto, - isConfirming: vetoingStatus === "pending" || isConfirming, - isConfirmed, - vetoProposal, - }; -} diff --git a/plugins/lockToVote/hooks/useProposalVetoes.ts b/plugins/lockToVote/hooks/useProposalVetoes.ts deleted file mode 100644 index 285324e..0000000 --- a/plugins/lockToVote/hooks/useProposalVetoes.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { useState, useEffect } from "react"; -import { Address, getAbiItem } from "viem"; -import { LockToVetoPluginAbi } from "../artifacts/LockToVetoPlugin.sol"; -import { Proposal, VetoCastEvent } from "../utils/types"; -import { usePublicClient } from "wagmi"; -import { PUB_CHAIN } from "@/constants"; - -const event = getAbiItem({ - abi: LockToVetoPluginAbi, - name: "VetoCast", -}); - -export function useProposalVetoes(pluginAddress: Address, proposalId: number, proposal: Proposal | null) { - const publicClient = usePublicClient({ chainId: PUB_CHAIN.id }); - const [proposalLogs, setLogs] = useState([]); - - async function getLogs() { - if (!publicClient || !proposal?.parameters?.snapshotBlock) return; - - const logs = await publicClient.getLogs({ - address: pluginAddress, - event, - args: { - proposalId: BigInt(proposalId), - }, - fromBlock: proposal.parameters.snapshotBlock, - toBlock: "latest", // TODO: Make this variable between 'latest' and proposal last block - }); - - const newLogs = logs.flatMap((log) => log.args); - if (newLogs.length > proposalLogs.length) setLogs(newLogs); - } - - useEffect(() => { - getLogs(); - }, [!!publicClient, proposal?.parameters?.snapshotBlock]); - - return proposalLogs; -} diff --git a/plugins/lockToVote/hooks/useToken.ts b/plugins/lockToVote/hooks/useToken.ts deleted file mode 100644 index dd4f6dc..0000000 --- a/plugins/lockToVote/hooks/useToken.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { erc20Abi } from "viem"; -import { useReadContract } from "wagmi"; -import { PUB_TOKEN_ADDRESS } from "@/constants"; - -export function useToken() { - const { - data: tokenSupply, - isError: isError1, - isLoading: isLoading1, - } = useReadContract({ - address: PUB_TOKEN_ADDRESS, - abi: erc20Abi, - functionName: "totalSupply", - }); - - const { - data: tokenSymbol, - isError: isError2, - isLoading: isLoading2, - } = useReadContract({ - address: PUB_TOKEN_ADDRESS, - abi: erc20Abi, - functionName: "symbol", - }); - - return { - address: PUB_TOKEN_ADDRESS, - tokenSupply, - symbol: tokenSymbol, - status: { - isLoading: isLoading1 || isLoading2, - isError: isError1 || isError2, - }, - }; -} diff --git a/plugins/lockToVote/hooks/useUserCanVeto.ts b/plugins/lockToVote/hooks/useUserCanVeto.ts deleted file mode 100644 index df5b2a3..0000000 --- a/plugins/lockToVote/hooks/useUserCanVeto.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { useAccount, useBlockNumber, useReadContract } from "wagmi"; -import { LockToVetoPluginAbi } from "../artifacts/LockToVetoPlugin.sol"; -import { useEffect } from "react"; -import { PUB_CHAIN, PUB_LOCK_TO_VOTE_PLUGIN_ADDRESS } from "@/constants"; - -export function useUserCanVeto(proposalId: number) { - const { address } = useAccount(); - const { data: blockNumber } = useBlockNumber({ watch: true }); - - const { data: canVeto, refetch } = useReadContract({ - chainId: PUB_CHAIN.id, - address: PUB_LOCK_TO_VOTE_PLUGIN_ADDRESS, - abi: LockToVetoPluginAbi, - functionName: "canVeto", - args: [BigInt(proposalId), address!], - query: { - enabled: !!address, - }, - }); - - useEffect(() => { - if (Number(blockNumber) % 2 === 0) { - refetch(); - } - }, [blockNumber]); - - return { canVeto, refetch }; -} diff --git a/plugins/lockToVote/index.tsx b/plugins/lockToVote/index.tsx deleted file mode 100644 index 5d029fb..0000000 --- a/plugins/lockToVote/index.tsx +++ /dev/null @@ -1,21 +0,0 @@ -import { NotFound } from "@/components/not-found"; -import ProposalCreate from "./pages/new"; -import ProposalList from "./pages/proposal-list"; -import ProposalDetail from "./pages/proposal"; -import { useUrl } from "@/hooks/useUrl"; - -export default function PluginPage() { - // Select the inner pages to display depending on the URL hash - const { hash } = useUrl(); - - if (!hash || hash === "#/") return ; - else if (hash === "#/new") return ; - else if (hash.startsWith("#/proposals/")) { - const id = hash.replace("#/proposals/", ""); - - return ; - } - - // Default not found page - return ; -} diff --git a/plugins/lockToVote/pages/new.tsx b/plugins/lockToVote/pages/new.tsx deleted file mode 100644 index 76329cb..0000000 --- a/plugins/lockToVote/pages/new.tsx +++ /dev/null @@ -1,283 +0,0 @@ -import { Button, IconType, InputText, TextAreaRichText, Tag } from "@aragon/ods"; -import React, { ReactNode, useState } from "react"; -import { RawAction } from "@/utils/types"; -import { Else, ElseIf, If, Then } from "@/components/if"; -import { MainSection } from "@/components/layout/main-section"; -import { useCreateProposal } from "../hooks/useCreateProposal"; -import { useAccount } from "wagmi"; -import { useCanCreateProposal } from "../hooks/useCanCreateProposal"; -import { MissingContentView } from "@/components/MissingContentView"; -import { useWeb3Modal } from "@web3modal/wagmi/react"; -import { Address } from "viem"; -import { NewActionDialog, NewActionType } from "@/components/dialogs/NewActionDialog"; -import { AddActionCard } from "@/components/cards/AddActionCard"; -import { ProposalActions } from "@/components/proposalActions/proposalActions"; -import { downloadAsFile } from "@/utils/download-as-file"; -import { encodeActionsAsJson } from "@/utils/json-actions"; - -export default function Create() { - const { address: selfAddress, isConnected } = useAccount(); - const canCreate = useCanCreateProposal(); - const [addActionType, setAddActionType] = useState(""); - const { - title, - summary, - description, - actions, - resources, - setTitle, - setSummary, - setDescription, - setActions, - setResources, - isCreating, - submitProposal, - } = useCreateProposal(); - - const handleTitleInput = (event: React.ChangeEvent) => { - setTitle(event?.target?.value); - }; - const handleSummaryInput = (event: React.ChangeEvent) => { - setSummary(event?.target?.value); - }; - const handleNewActionDialogClose = (newAction: RawAction[] | null) => { - if (!newAction) { - setAddActionType(""); - return; - } - - setActions(actions.concat(newAction)); - setAddActionType(""); - }; - const onRemoveAction = (idx: number) => { - actions.splice(idx, 1); - setActions([].concat(actions as any)); - }; - const removeResource = (idx: number) => { - resources.splice(idx, 1); - setResources([].concat(resources as any)); - }; - const onResourceNameChange = (event: React.ChangeEvent, idx: number) => { - resources[idx].name = event.target.value; - setResources([].concat(resources as any)); - }; - const onResourceUrlChange = (event: React.ChangeEvent, idx: number) => { - resources[idx].url = event.target.value; - setResources([].concat(resources as any)); - }; - - const exportAsJson = () => { - if (!actions.length) return; - - const strResult = encodeActionsAsJson(actions); - downloadAsFile("actions.json", strResult, "text/json"); - }; - - return ( - -
-

- Create Proposal -

- - -
- -
-
- -
-
- -
- -
-
-
-

Resources

- -
-

- Add links to external resources -

-
-
- -

- There are no resources yet. Click the button below to add the first one. -

-
- {resources.map((resource, idx) => { - return ( -
-
- onResourceNameChange(e, idx)} - placeholder="GitHub, Twitter, etc." - /> -
- onResourceUrlChange(e, idx)} - placeholder="https://..." - readOnly={isCreating} - /> -
- ); - })} -
- - - -
- - {/* Actions */} - - onRemoveAction(idx)} - /> - - - - - -
- setAddActionType("withdrawal")} - /> - setAddActionType("select-abi-function")} - /> - setAddActionType("calldata")} - /> - setAddActionType("import-json")} - /> -
- - {/* Dialog */} - - handleNewActionDialogClose(newActions)} - /> - - {/* Submit */} - -
- -
-
-
-
- ); -} - -const PlaceHolderOr = ({ - selfAddress, - isConnected, - canCreate, - children, -}: { - selfAddress: Address | undefined; - isConnected: boolean; - canCreate: boolean | undefined; - children: ReactNode; -}) => { - const { open } = useWeb3Modal(); - return ( - - - {/* Not connected */} - open()}> - Please connect your wallet to continue. - - - - {/* Not a member */} - - You cannot create proposals on the multisig because you are not currently defined as a member. - - - {children} - - ); -}; diff --git a/plugins/lockToVote/pages/proposal-list.tsx b/plugins/lockToVote/pages/proposal-list.tsx deleted file mode 100644 index 22d4a16..0000000 --- a/plugins/lockToVote/pages/proposal-list.tsx +++ /dev/null @@ -1,100 +0,0 @@ -import { useAccount, useBlockNumber, useReadContract } from "wagmi"; -import { type ReactNode, useEffect } from "react"; -import ProposalCard from "../components/proposal"; -import { LockToVetoPluginAbi } from "../artifacts/LockToVetoPlugin.sol"; -import { Button, DataList, IconType, ProposalDataListItemSkeleton, type DataListState } from "@aragon/ods"; -import { useCanCreateProposal } from "../hooks/useCanCreateProposal"; -import Link from "next/link"; -import { Else, ElseIf, If, Then } from "@/components/if"; -import { PUB_LOCK_TO_VOTE_PLUGIN_ADDRESS, PUB_CHAIN } from "@/constants"; -import { MainSection } from "@/components/layout/main-section"; -import { MissingContentView } from "@/components/MissingContentView"; - -const DEFAULT_PAGE_SIZE = 6; - -export default function Proposals() { - const { isConnected } = useAccount(); - const canCreate = useCanCreateProposal(); - const { data: blockNumber } = useBlockNumber({ watch: true }); - - const { - data: proposalCountResponse, - error: isError, - isLoading, - isFetching: isFetchingNextPage, - refetch, - } = useReadContract({ - address: PUB_LOCK_TO_VOTE_PLUGIN_ADDRESS, - abi: LockToVetoPluginAbi, - functionName: "proposalCount", - chainId: PUB_CHAIN.id, - }); - const proposalCount = Number(proposalCountResponse); - - useEffect(() => { - refetch(); - }, [blockNumber]); - - const entityLabel = proposalCount === 1 ? "Proposal" : "Proposals"; - - let dataListState: DataListState = "idle"; - if (isLoading && !proposalCount) { - dataListState = "initialLoading"; - } else if (isError) { - dataListState = "error"; - } else if (isFetchingNextPage) { - dataListState = "fetchingNextPage"; - } - - return ( - - -

- Proposals -

-
- - - - - -
-
- - - - - No proposals have been created yet. Here you will see the available proposals.{" "} - Create your first proposal. - - - - - - {proposalCount && - Array.from(Array(proposalCount || 0)?.keys()) - .reverse() - ?.map((proposalIndex) => ( - // TODO: update with router agnostic ODS DataListItem - - ))} - - - - - -
- ); -} - -function SectionView({ children }: { children: ReactNode }) { - return
{children}
; -} diff --git a/plugins/lockToVote/pages/proposal.tsx b/plugins/lockToVote/pages/proposal.tsx deleted file mode 100644 index 268ddb3..0000000 --- a/plugins/lockToVote/pages/proposal.tsx +++ /dev/null @@ -1,212 +0,0 @@ -import type { useProposal } from "../hooks/useProposal"; -import ProposalHeader from "../components/proposal/header"; -import { PleaseWaitSpinner } from "@/components/please-wait"; -import { useProposalVeto } from "../hooks/useProposalVeto"; -import { useProposalExecute } from "../hooks/useProposalExecute"; -import { BodySection } from "@/components/proposal/proposalBodySection"; -import { type IBreakdownMajorityVotingResult, ProposalVoting } from "@/components/proposalVoting"; -import type { ITransformedStage, IVote } from "@/utils/types"; -import { ProposalStages } from "@/utils/types"; -import { useProposalStatus } from "../hooks/useProposalVariantStatus"; -import dayjs from "dayjs"; -import { ProposalActions } from "@/components/proposalActions/proposalActions"; -import { CardResources } from "@/components/proposal/cardResources"; -import { type Address, formatEther } from "viem"; -import { useToken } from "../hooks/useToken"; -import { usePastSupply } from "../hooks/usePastSupply"; -import { ElseIf, If, Then } from "@/components/if"; -import { AlertCard, ProposalStatus } from "@aragon/ods"; -import { PUB_TOKEN_SYMBOL } from "@/constants"; -import { useAccount } from "wagmi"; -import { ADDRESS_ZERO } from "@/utils/evm"; -import { AddressText } from "@/components/text/address"; -import Link from "next/link"; - -const ZERO = BigInt(0); - -export default function ProposalDetail({ index: proposalIdx }: { index: number }) { - const { address } = useAccount(); - const { - proposal, - proposalFetchStatus, - canVeto, - vetoes, - isConfirming: isConfirmingVeto, - vetoProposal, - } = useProposalVeto(proposalIdx); - const pastSupply = usePastSupply(proposal?.parameters.snapshotBlock); - const { symbol: tokenSymbol } = useToken(); - const balance = 0; - const delegatesTo = "0x0" as Address; - - const { executeProposal, canExecute, isConfirming: isConfirmingExecution } = useProposalExecute(proposalIdx); - - const startDate = dayjs(Number(proposal?.parameters.startDate) * 1000).toString(); - const endDate = dayjs(Number(proposal?.parameters.endDate) * 1000).toString(); - - const showProposalLoading = getShowProposalLoading(proposal, proposalFetchStatus); - const proposalStatus = useProposalStatus(proposal!); - let vetoPercentage = 0; - if (proposal?.vetoTally && pastSupply && proposal.parameters.minVetoVotingPower) { - vetoPercentage = Number( - (BigInt(1000) * proposal.vetoTally) / - ((pastSupply * BigInt(proposal.parameters.minVetoVotingPower)) / BigInt(10000000)) - ); - } - - let cta: IBreakdownMajorityVotingResult["cta"]; - if (proposal?.executed) { - cta = { - disabled: true, - label: "Executed", - }; - } else if (proposalStatus === ProposalStatus.ACCEPTED) { - cta = { - disabled: !canExecute || !proposal?.actions.length, - isLoading: isConfirmingExecution, - label: proposal?.actions.length ? "Execute" : "No actions to execute", - onClick: executeProposal, - }; - } else if (proposalStatus === ProposalStatus.ACTIVE) { - cta = { - disabled: !canVeto, - isLoading: isConfirmingVeto, - label: "Veto", - onClick: vetoProposal, - }; - } - // TODO: CHECK has claimed + add claim() - - const proposalStage: ITransformedStage[] = [ - { - id: "1", - type: ProposalStages.OPTIMISTIC_EXECUTION, - variant: "majorityVoting", - title: "Optimistic voting", - status: proposalStatus!, - disabled: false, - proposalId: proposalIdx.toString(), - providerId: "1", - result: { - cta, - votingScores: [ - { - option: "Veto", - voteAmount: formatEther(proposal?.vetoTally || BigInt(0)), - votePercentage: vetoPercentage, - tokenSymbol: tokenSymbol || PUB_TOKEN_SYMBOL, - }, - ], - proposalId: proposalIdx.toString(), - }, - details: { - censusTimestamp: Number(proposal?.parameters.snapshotBlock || 0) || 0, - startDate, - endDate, - strategy: "Optimistic voting", - options: "Veto", - }, - votes: vetoes.map(({ voter }) => ({ address: voter, variant: "no" }) as IVote), - }, - ]; - - const hasBalance = !!balance && balance > ZERO; - const delegatingToSomeoneElse = !!delegatesTo && delegatesTo !== address && delegatesTo !== ADDRESS_ZERO; - const delegatedToZero = !!delegatesTo && delegatesTo === ADDRESS_ZERO; - - if (!proposal || showProposalLoading) { - return ( -
- -
- ); - } - - return ( -
- - -
-
-
- - - - - - -
-
- -
-
-
-
- ); -} - -const NoVetoPowerWarning = ({ - delegatingToSomeoneElse, - delegatesTo, - delegatedToZero, - address, - canVeto, -}: { - delegatingToSomeoneElse: boolean; - delegatesTo: Address | undefined; - delegatedToZero: boolean; - address: Address | undefined; - canVeto: boolean; -}) => { - return ( - - - - You are currently delegating your voting power to {delegatesTo}. - If you wish to participate by yourself in future proposals, - - - You have not self delegated your voting power to participate in the DAO. If you wish to participate in - future proposals, - - -  make sure that{" "} - - your voting power is self delegated - - . - - } - message={ - delegatingToSomeoneElse - ? "Your voting power is currently delegated" - : canVeto - ? "You cannot veto on new proposals" - : "You cannot veto" - } - variant="info" - /> - ); -}; - -function getShowProposalLoading( - proposal: ReturnType["proposal"], - status: ReturnType["status"] -) { - if (!proposal && status.proposalLoading) return true; - else if (status.metadataLoading && !status.metadataError) return true; - else if (!proposal?.title && !status.metadataError) return true; - - return false; -} diff --git a/plugins/lockToVote/utils/types.tsx b/plugins/lockToVote/utils/types.tsx deleted file mode 100644 index 1a6ba26..0000000 --- a/plugins/lockToVote/utils/types.tsx +++ /dev/null @@ -1,37 +0,0 @@ -import { Address } from "viem"; -import type { IProposalResource, RawAction } from "@/utils/types"; - -export type ProposalInputs = { - proposalId: bigint; -}; - -export type ProposalParameters = { - startDate: bigint; - endDate: bigint; - snapshotBlock: bigint; - minVetoVotingPower: bigint; -}; - -export type Proposal = { - active: boolean; - executed: boolean; - parameters: ProposalParameters; - vetoTally: bigint; - actions: RawAction[]; - allowFailureMap: bigint; - creator: string; - title: string; - summary: string; - description: string; - resources: IProposalResource[]; -}; - -export type VoteCastResponse = { - args: VetoCastEvent[]; -}; - -export type VetoCastEvent = { - voter?: Address; - proposalId?: bigint; - votingPower?: bigint; -}; diff --git a/plugins/opt-multisig/artifacts/OptimisticMultisigPlugin.tsx b/plugins/opt-multisig/artifacts/OptimisticMultisigPlugin.tsx deleted file mode 100644 index a4a8423..0000000 --- a/plugins/opt-multisig/artifacts/OptimisticMultisigPlugin.tsx +++ /dev/null @@ -1,429 +0,0 @@ -export const OptimisticMultisigPluginAbi = [ - { - inputs: [ - { internalType: "uint16", name: "limit", type: "uint16" }, - { internalType: "uint256", name: "actual", type: "uint256" }, - ], - name: "AddresslistLengthOutOfBounds", - type: "error", - }, - { - inputs: [ - { internalType: "uint256", name: "proposalId", type: "uint256" }, - { internalType: "address", name: "sender", type: "address" }, - ], - name: "ApprovalCastForbidden", - type: "error", - }, - { - inputs: [ - { internalType: "address", name: "dao", type: "address" }, - { internalType: "address", name: "where", type: "address" }, - { internalType: "address", name: "who", type: "address" }, - { internalType: "bytes32", name: "permissionId", type: "bytes32" }, - ], - name: "DaoUnauthorized", - type: "error", - }, - { - inputs: [{ internalType: "address", name: "member", type: "address" }], - name: "InvalidAddresslistUpdate", - type: "error", - }, - { - inputs: [ - { internalType: "uint16", name: "limit", type: "uint16" }, - { internalType: "uint16", name: "actual", type: "uint16" }, - ], - name: "MinApprovalsOutOfBounds", - type: "error", - }, - { - inputs: [{ internalType: "address", name: "sender", type: "address" }], - name: "ProposalCreationForbidden", - type: "error", - }, - { - inputs: [{ internalType: "uint256", name: "proposalId", type: "uint256" }], - name: "ProposalExecutionForbidden", - type: "error", - }, - { - anonymous: false, - inputs: [ - { indexed: false, internalType: "address", name: "previousAdmin", type: "address" }, - { indexed: false, internalType: "address", name: "newAdmin", type: "address" }, - ], - name: "AdminChanged", - type: "event", - }, - { - anonymous: false, - inputs: [ - { indexed: true, internalType: "uint256", name: "proposalId", type: "uint256" }, - { indexed: true, internalType: "address", name: "approver", type: "address" }, - ], - name: "Approved", - type: "event", - }, - { - anonymous: false, - inputs: [{ indexed: true, internalType: "address", name: "beacon", type: "address" }], - name: "BeaconUpgraded", - type: "event", - }, - { - anonymous: false, - inputs: [{ indexed: true, internalType: "uint256", name: "proposalId", type: "uint256" }], - name: "Executed", - type: "event", - }, - { - anonymous: false, - inputs: [{ indexed: false, internalType: "uint8", name: "version", type: "uint8" }], - name: "Initialized", - type: "event", - }, - { - anonymous: false, - inputs: [{ indexed: false, internalType: "address[]", name: "members", type: "address[]" }], - name: "MembersAdded", - type: "event", - }, - { - anonymous: false, - inputs: [{ indexed: false, internalType: "address[]", name: "members", type: "address[]" }], - name: "MembersRemoved", - type: "event", - }, - { - anonymous: false, - inputs: [{ indexed: true, internalType: "address", name: "definingContract", type: "address" }], - name: "MembershipContractAnnounced", - type: "event", - }, - { - anonymous: false, - inputs: [ - { indexed: false, internalType: "bool", name: "onlyListed", type: "bool" }, - { indexed: true, internalType: "uint16", name: "minApprovals", type: "uint16" }, - { indexed: false, internalType: "uint64", name: "destinationProposalDuration", type: "uint64" }, - ], - name: "MultisigSettingsUpdated", - type: "event", - }, - { - anonymous: false, - inputs: [ - { indexed: true, internalType: "uint256", name: "proposalId", type: "uint256" }, - { indexed: true, internalType: "address", name: "creator", type: "address" }, - { indexed: false, internalType: "uint64", name: "startDate", type: "uint64" }, - { indexed: false, internalType: "uint64", name: "endDate", type: "uint64" }, - { indexed: false, internalType: "bytes", name: "metadata", type: "bytes" }, - { - components: [ - { internalType: "address", name: "to", type: "address" }, - { internalType: "uint256", name: "value", type: "uint256" }, - { internalType: "bytes", name: "data", type: "bytes" }, - ], - indexed: false, - internalType: "struct IDAO.Action[]", - name: "actions", - type: "tuple[]", - }, - { indexed: false, internalType: "uint256", name: "allowFailureMap", type: "uint256" }, - ], - name: "ProposalCreated", - type: "event", - }, - { - anonymous: false, - inputs: [{ indexed: true, internalType: "uint256", name: "proposalId", type: "uint256" }], - name: "ProposalExecuted", - type: "event", - }, - { - anonymous: false, - inputs: [{ indexed: true, internalType: "address", name: "implementation", type: "address" }], - name: "Upgraded", - type: "event", - }, - { - inputs: [], - name: "UPDATE_MULTISIG_SETTINGS_PERMISSION_ID", - outputs: [{ internalType: "bytes32", name: "", type: "bytes32" }], - stateMutability: "view", - type: "function", - }, - { - inputs: [], - name: "UPGRADE_PLUGIN_PERMISSION_ID", - outputs: [{ internalType: "bytes32", name: "", type: "bytes32" }], - stateMutability: "view", - type: "function", - }, - { - inputs: [{ internalType: "address[]", name: "_members", type: "address[]" }], - name: "addAddresses", - outputs: [], - stateMutability: "nonpayable", - type: "function", - }, - { - inputs: [], - name: "addresslistLength", - outputs: [{ internalType: "uint256", name: "", type: "uint256" }], - stateMutability: "view", - type: "function", - }, - { - inputs: [{ internalType: "uint256", name: "_blockNumber", type: "uint256" }], - name: "addresslistLengthAtBlock", - outputs: [{ internalType: "uint256", name: "", type: "uint256" }], - stateMutability: "view", - type: "function", - }, - { - inputs: [ - { internalType: "uint256", name: "_proposalId", type: "uint256" }, - { internalType: "bool", name: "_tryExecution", type: "bool" }, - ], - name: "approve", - outputs: [], - stateMutability: "nonpayable", - type: "function", - }, - { - inputs: [ - { internalType: "uint256", name: "_proposalId", type: "uint256" }, - { internalType: "address", name: "_account", type: "address" }, - ], - name: "canApprove", - outputs: [{ internalType: "bool", name: "", type: "bool" }], - stateMutability: "view", - type: "function", - }, - { - inputs: [{ internalType: "uint256", name: "_proposalId", type: "uint256" }], - name: "canExecute", - outputs: [{ internalType: "bool", name: "", type: "bool" }], - stateMutability: "view", - type: "function", - }, - { - inputs: [ - { internalType: "bytes", name: "_metadataURI", type: "bytes" }, - { - components: [ - { internalType: "address", name: "to", type: "address" }, - { internalType: "uint256", name: "value", type: "uint256" }, - { internalType: "bytes", name: "data", type: "bytes" }, - ], - internalType: "struct IDAO.Action[]", - name: "_destinationActions", - type: "tuple[]", - }, - { internalType: "contract OptimisticTokenVotingPlugin", name: "_destinationPlugin", type: "address" }, - { internalType: "bool", name: "_approveProposal", type: "bool" }, - ], - name: "createProposal", - outputs: [{ internalType: "uint256", name: "proposalId", type: "uint256" }], - stateMutability: "nonpayable", - type: "function", - }, - { - inputs: [], - name: "dao", - outputs: [{ internalType: "contract IDAO", name: "", type: "address" }], - stateMutability: "view", - type: "function", - }, - { - inputs: [{ internalType: "uint256", name: "_proposalId", type: "uint256" }], - name: "execute", - outputs: [], - stateMutability: "nonpayable", - type: "function", - }, - { - inputs: [{ internalType: "uint256", name: "_proposalId", type: "uint256" }], - name: "getProposal", - outputs: [ - { internalType: "bool", name: "executed", type: "bool" }, - { internalType: "uint16", name: "approvals", type: "uint16" }, - { - components: [ - { internalType: "uint16", name: "minApprovals", type: "uint16" }, - { internalType: "uint64", name: "snapshotBlock", type: "uint64" }, - { internalType: "uint64", name: "expirationDate", type: "uint64" }, - ], - internalType: "struct Multisig.ProposalParameters", - name: "parameters", - type: "tuple", - }, - { internalType: "bytes", name: "metadataURI", type: "bytes" }, - { - components: [ - { internalType: "address", name: "to", type: "address" }, - { internalType: "uint256", name: "value", type: "uint256" }, - { internalType: "bytes", name: "data", type: "bytes" }, - ], - internalType: "struct IDAO.Action[]", - name: "destinationActions", - type: "tuple[]", - }, - { internalType: "contract OptimisticTokenVotingPlugin", name: "destinationPlugin", type: "address" }, - ], - stateMutability: "view", - type: "function", - }, - { - inputs: [ - { internalType: "uint256", name: "_proposalId", type: "uint256" }, - { internalType: "address", name: "_account", type: "address" }, - ], - name: "hasApproved", - outputs: [{ internalType: "bool", name: "", type: "bool" }], - stateMutability: "view", - type: "function", - }, - { - inputs: [], - name: "implementation", - outputs: [{ internalType: "address", name: "", type: "address" }], - stateMutability: "view", - type: "function", - }, - { - inputs: [ - { internalType: "contract IDAO", name: "_dao", type: "address" }, - { internalType: "address[]", name: "_members", type: "address[]" }, - { - components: [ - { internalType: "bool", name: "onlyListed", type: "bool" }, - { internalType: "uint16", name: "minApprovals", type: "uint16" }, - { internalType: "uint64", name: "destinationProposalDuration", type: "uint64" }, - ], - internalType: "struct Multisig.MultisigSettings", - name: "_multisigSettings", - type: "tuple", - }, - ], - name: "initialize", - outputs: [], - stateMutability: "nonpayable", - type: "function", - }, - { - inputs: [{ internalType: "address", name: "_account", type: "address" }], - name: "isListed", - outputs: [{ internalType: "bool", name: "", type: "bool" }], - stateMutability: "view", - type: "function", - }, - { - inputs: [ - { internalType: "address", name: "_account", type: "address" }, - { internalType: "uint256", name: "_blockNumber", type: "uint256" }, - ], - name: "isListedAtBlock", - outputs: [{ internalType: "bool", name: "", type: "bool" }], - stateMutability: "view", - type: "function", - }, - { - inputs: [{ internalType: "address", name: "_account", type: "address" }], - name: "isMember", - outputs: [{ internalType: "bool", name: "", type: "bool" }], - stateMutability: "view", - type: "function", - }, - { - inputs: [], - name: "lastMultisigSettingsChange", - outputs: [{ internalType: "uint64", name: "", type: "uint64" }], - stateMutability: "view", - type: "function", - }, - { - inputs: [], - name: "multisigSettings", - outputs: [ - { internalType: "bool", name: "onlyListed", type: "bool" }, - { internalType: "uint16", name: "minApprovals", type: "uint16" }, - { internalType: "uint64", name: "destinationProposalDuration", type: "uint64" }, - ], - stateMutability: "view", - type: "function", - }, - { - inputs: [], - name: "pluginType", - outputs: [{ internalType: "enum IPlugin.PluginType", name: "", type: "uint8" }], - stateMutability: "pure", - type: "function", - }, - { - inputs: [], - name: "proposalCount", - outputs: [{ internalType: "uint256", name: "", type: "uint256" }], - stateMutability: "view", - type: "function", - }, - { - inputs: [], - name: "proxiableUUID", - outputs: [{ internalType: "bytes32", name: "", type: "bytes32" }], - stateMutability: "view", - type: "function", - }, - { - inputs: [{ internalType: "address[]", name: "_members", type: "address[]" }], - name: "removeAddresses", - outputs: [], - stateMutability: "nonpayable", - type: "function", - }, - { - inputs: [{ internalType: "bytes4", name: "_interfaceId", type: "bytes4" }], - name: "supportsInterface", - outputs: [{ internalType: "bool", name: "", type: "bool" }], - stateMutability: "view", - type: "function", - }, - { - inputs: [ - { - components: [ - { internalType: "bool", name: "onlyListed", type: "bool" }, - { internalType: "uint16", name: "minApprovals", type: "uint16" }, - { internalType: "uint64", name: "destinationProposalDuration", type: "uint64" }, - ], - internalType: "struct Multisig.MultisigSettings", - name: "_multisigSettings", - type: "tuple", - }, - ], - name: "updateMultisigSettings", - outputs: [], - stateMutability: "nonpayable", - type: "function", - }, - { - inputs: [{ internalType: "address", name: "newImplementation", type: "address" }], - name: "upgradeTo", - outputs: [], - stateMutability: "nonpayable", - type: "function", - }, - { - inputs: [ - { internalType: "address", name: "newImplementation", type: "address" }, - { internalType: "bytes", name: "data", type: "bytes" }, - ], - name: "upgradeToAndCall", - outputs: [], - stateMutability: "payable", - type: "function", - }, -] as const; diff --git a/plugins/opt-multisig/components/proposal/header.tsx b/plugins/opt-multisig/components/proposal/header.tsx deleted file mode 100644 index 9cce525..0000000 --- a/plugins/opt-multisig/components/proposal/header.tsx +++ /dev/null @@ -1,75 +0,0 @@ -import { AvatarIcon, Breadcrumbs, Heading, IBreadcrumbsLink, IconType, ProposalStatus, TagVariant } from "@aragon/ods"; -import { MultisigProposal } from "@/plugins/opt-multisig/utils/types"; -import { useProposalStatus } from "@/plugins/opt-multisig/hooks/useProposalVariantStatus"; -import dayjs from "dayjs"; -import { HeaderSection } from "@/components/layout/header-section"; -import { Publisher } from "@/components/publisher"; -import { getSimpleRelativeTimeFromDate } from "@/utils/dates"; -import { Else, ElseIf, If, Then } from "@/components/if"; -import { getTagVariantFromStatus } from "@/utils/ui-variants"; -import { capitalizeFirstLetter } from "@/utils/text"; - -interface ProposalHeaderProps { - proposalId: string; - proposal: MultisigProposal; -} - -const ProposalHeader: React.FC = ({ proposalId, proposal }) => { - const proposalStatus = useProposalStatus(proposal); - const tagVariant = getTagVariantFromStatus(proposalStatus); - const breadcrumbs: IBreadcrumbsLink[] = [{ label: "Proposals", href: "#/" }, { label: proposalId.toString() }]; - const expired = Number(proposal.parameters.expirationDate) * 1000 <= Date.now(); - - return ( -
- {/* Wrapper */} - - - {/* Title & description */} -
-
- {proposal.title} - {/* && */} -
-

{proposal.summary}

-
- {/* Metadata */} -
-
- - -
-
- -
- - - The proposal was sent to the community stage - - - The proposal expired - - - - {getSimpleRelativeTimeFromDate(dayjs(Number(proposal.parameters.expirationDate) * 1000))} - - left until expiration - - -
-
-
-
-
- ); -}; - -export default ProposalHeader; diff --git a/plugins/opt-multisig/components/proposal/index.tsx b/plugins/opt-multisig/components/proposal/index.tsx deleted file mode 100644 index b3409c2..0000000 --- a/plugins/opt-multisig/components/proposal/index.tsx +++ /dev/null @@ -1,91 +0,0 @@ -import Link from "next/link"; -import { useProposalApprove } from "@/plugins/opt-multisig/hooks/useProposalApprove"; -import { Card, ProposalStatus } from "@aragon/ods"; -import { ProposalDataListItem } from "@aragon/ods"; -import { PleaseWaitSpinner } from "@/components/please-wait"; -import { useProposalStatus } from "../../hooks/useProposalVariantStatus"; -import { useAccount } from "wagmi"; - -const DEFAULT_PROPOSAL_METADATA_TITLE = "(No proposal title)"; -const DEFAULT_PROPOSAL_METADATA_SUMMARY = "(The metadata of the proposal is not available)"; - -type ProposalInputs = { - proposalId: bigint; -}; - -export default function ProposalCard(props: ProposalInputs) { - const { address } = useAccount(); - const { proposal, proposalFetchStatus, approvals } = useProposalApprove(props.proposalId.toString()); - - const proposalStatus = useProposalStatus(proposal!); - const showLoading = getShowProposalLoading(proposal, proposalFetchStatus); - const hasApproved = approvals?.some((veto) => veto.approver === address); - - if (!proposal && showLoading) { - return ( -
- - - - - -
- ); - } else if (!proposal?.title && !proposal?.summary) { - // We have the proposal but no metadata yet - return ( - - - - - - - - ); - } else if (proposalFetchStatus.metadataReady && !proposal?.title) { - return ( - - -
-

- {Number(props.proposalId) + 1} - {DEFAULT_PROPOSAL_METADATA_TITLE} -

-

{DEFAULT_PROPOSAL_METADATA_SUMMARY}

-
-
- - ); - } - - return ( - - ); -} - -function getShowProposalLoading( - proposal: ReturnType["proposal"], - status: ReturnType["proposalFetchStatus"] -) { - if (!proposal || status.proposalLoading) return true; - else if (status.metadataLoading && !status.metadataError) return true; - else if (!proposal?.title && !status.metadataError) return true; - - return false; -} diff --git a/plugins/opt-multisig/hooks/useCanCreateProposal.ts b/plugins/opt-multisig/hooks/useCanCreateProposal.ts deleted file mode 100644 index 0c974fb..0000000 --- a/plugins/opt-multisig/hooks/useCanCreateProposal.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { useAccount, useReadContract } from "wagmi"; -import { PUB_OPT_MULTISIG_PLUGIN_ADDRESS } from "@/constants"; -import { OptimisticMultisigPluginAbi } from "../artifacts/OptimisticMultisigPlugin"; - -export function useCanCreateProposal() { - const { address } = useAccount(); - const { - data: canCreate, - isLoading, - error, - refetch, - } = useReadContract({ - abi: OptimisticMultisigPluginAbi, - address: PUB_OPT_MULTISIG_PLUGIN_ADDRESS, - functionName: "isMember", - args: [address!], - - query: { - retry: true, - refetchOnMount: false, - refetchOnReconnect: false, - retryOnMount: true, - enabled: !!address, - staleTime: 1000 * 60 * 5, - }, - }); - - return { canCreate, isLoading, error, refetch }; -} diff --git a/plugins/opt-multisig/hooks/useCreateProposal.ts b/plugins/opt-multisig/hooks/useCreateProposal.ts deleted file mode 100644 index f7b703c..0000000 --- a/plugins/opt-multisig/hooks/useCreateProposal.ts +++ /dev/null @@ -1,112 +0,0 @@ -import { useRouter } from "next/router"; -import { useEffect, useState } from "react"; -import { ProposalMetadata, RawAction } from "@/utils/types"; -import { useWaitForTransactionReceipt, useWriteContract } from "wagmi"; -import { useAlerts } from "@/context/Alerts"; -import { - PUB_APP_NAME, - PUB_CHAIN, - PUB_DUAL_GOVERNANCE_PLUGIN_ADDRESS, - PUB_OPT_MULTISIG_PLUGIN_ADDRESS, - PUB_PROJECT_URL, -} from "@/constants"; -import { uploadToPinata } from "@/utils/ipfs"; -import { OptimisticMultisigPluginAbi } from "../artifacts/OptimisticMultisigPlugin"; -import { URL_PATTERN } from "@/utils/input-values"; -import { toHex } from "viem"; -import { useTransactionManager } from "@/hooks/useTransactionManager"; - -const UrlRegex = new RegExp(URL_PATTERN); - -export function useCreateProposal() { - const { push } = useRouter(); - const { addAlert } = useAlerts(); - const [isCreating, setIsCreating] = useState(false); - const [title, setTitle] = useState(""); - const [summary, setSummary] = useState(""); - const [description, setDescription] = useState(""); - const [actions, setActions] = useState([]); - const [resources, setResources] = useState<{ name: string; url: string }[]>([ - { name: PUB_APP_NAME, url: PUB_PROJECT_URL }, - ]); - - const { writeContract: createProposalWrite, isConfirming } = useTransactionManager({ - onSuccessMessage: "Proposal created", - onSuccess() { - setTimeout(() => { - push("#/"); - window.scroll(0, 0); - }, 1000 * 2); - }, - onErrorMessage: "Could not create the proposal", - onError: () => setIsCreating(false), - }); - - const submitProposal = async () => { - // Check metadata - if (!title.trim()) { - return addAlert("Invalid proposal details", { - description: "Please enter a title", - type: "error", - }); - } - - if (!summary.trim()) { - return addAlert("Invalid proposal details", { - description: "Please enter a summary of what the proposal is about", - type: "error", - }); - } - - for (const item of resources) { - if (!item.name.trim()) { - return addAlert("Invalid resource name", { - description: "Please enter a name for all the resources", - type: "error", - }); - } else if (!UrlRegex.test(item.url.trim())) { - return addAlert("Invalid resource URL", { - description: "Please enter valid URL for all the resources", - type: "error", - }); - } - } - - try { - setIsCreating(true); - const proposalMetadataJsonObject: ProposalMetadata = { - title, - summary, - description, - resources, - }; - - const ipfsPin = await uploadToPinata(JSON.stringify(proposalMetadataJsonObject)); - - createProposalWrite({ - chainId: PUB_CHAIN.id, - abi: OptimisticMultisigPluginAbi, - address: PUB_OPT_MULTISIG_PLUGIN_ADDRESS, - functionName: "createProposal", - args: [toHex(ipfsPin), actions, PUB_DUAL_GOVERNANCE_PLUGIN_ADDRESS, false], - }); - } catch (err) { - setIsCreating(false); - } - }; - - return { - isCreating: isCreating || isConfirming || status === "pending", - title, - summary, - description, - actions, - resources, - setTitle, - setSummary, - setDescription, - setActions, - setResources, - submitProposal, - }; -} diff --git a/plugins/opt-multisig/hooks/useProposal.ts b/plugins/opt-multisig/hooks/useProposal.ts deleted file mode 100644 index 94a91f4..0000000 --- a/plugins/opt-multisig/hooks/useProposal.ts +++ /dev/null @@ -1,139 +0,0 @@ -import { useState, useEffect } from "react"; -import { useBlockNumber, usePublicClient, useReadContract } from "wagmi"; -import { getAbiItem } from "viem"; -import { OptimisticMultisigPluginAbi } from "@/plugins/opt-multisig/artifacts/OptimisticMultisigPlugin"; -import { RawAction, ProposalMetadata } from "@/utils/types"; -import { - MultisigProposal, - MultisigProposalParameters, - MultisigProposalResultType, -} from "@/plugins/opt-multisig/utils/types"; -import { PUB_CHAIN, PUB_OPT_MULTISIG_PLUGIN_ADDRESS } from "@/constants"; -import { useMetadata } from "@/hooks/useMetadata"; - -const ProposalCreatedEvent = getAbiItem({ - abi: OptimisticMultisigPluginAbi, - name: "ProposalCreated", -}); - -type ProposalCreatedLogResponse = { - args: { - actions: RawAction[]; - allowFailureMap: bigint; - creator: string; - endDate: bigint; - startDate: bigint; - metadata: string; - proposalId: bigint; - }; -}; - -export function useProposal(proposalId: string, autoRefresh = false) { - const publicClient = usePublicClient(); - const [proposalCreationEvent, setProposalCreationEvent] = useState(); - const { data: blockNumber } = useBlockNumber({ watch: true }); - - // Proposal onchain data - const { - data: proposalResult, - error: proposalError, - fetchStatus: proposalFetchStatus, - refetch: proposalRefetch, - } = useReadContract({ - address: PUB_OPT_MULTISIG_PLUGIN_ADDRESS, - abi: OptimisticMultisigPluginAbi, - functionName: "getProposal", - args: [BigInt(proposalId)], - chainId: PUB_CHAIN.id, - }); - - const proposalData = decodeProposalResultData(proposalResult); - - useEffect(() => { - if (autoRefresh) proposalRefetch(); - }, [blockNumber]); - - // JSON metadata - const { - data: metadataContent, - isLoading: metadataLoading, - error: metadataError, - } = useMetadata(proposalData?.metadataUri); - - const proposal = arrangeProposalData(proposalData, proposalCreationEvent, metadataContent); - - useEffect(() => { - if (!proposalData || !publicClient || proposalCreationEvent) return; - - publicClient - .getLogs({ - address: PUB_OPT_MULTISIG_PLUGIN_ADDRESS, - event: ProposalCreatedEvent, - args: { proposalId: BigInt(proposalId) }, - fromBlock: proposalData.parameters.snapshotBlock, - toBlock: "latest", - }) - .then((logs) => { - if (!logs || !logs.length) throw new Error("No creation logs"); - - const log: ProposalCreatedLogResponse = logs[0] as any; - setProposalCreationEvent(log.args); - }) - .catch((err) => { - console.error("Could not fetch the proposal details", err); - return null; - }); - }, [proposalData, !!publicClient]); - - return { - proposal, - refetch: proposalRefetch, - status: { - proposalReady: proposalFetchStatus === "idle", - proposalLoading: proposalFetchStatus === "fetching", - proposalError, - metadataReady: !metadataError && !metadataLoading && !!metadataContent, - metadataLoading, - metadataError: metadataError !== undefined, - }, - }; -} - -// Helpers - -function decodeProposalResultData(data?: MultisigProposalResultType) { - if (!data?.length) return null; - - return { - executed: data[0] as boolean, - approvals: data[1] as number, - parameters: data[2] as MultisigProposalParameters, - metadataUri: data[3] as string, - actions: data[4] as Array, - }; -} - -function arrangeProposalData( - proposalData?: ReturnType, - creationEvent?: ProposalCreatedLogResponse["args"], - metadata?: ProposalMetadata -): MultisigProposal | null { - if (!proposalData) return null; - - return { - actions: proposalData.actions, - executed: proposalData.executed, - parameters: { - expirationDate: proposalData.parameters.expirationDate, - snapshotBlock: proposalData.parameters.snapshotBlock, - minApprovals: proposalData.parameters.minApprovals, - }, - approvals: proposalData.approvals, - allowFailureMap: BigInt(0), - creator: creationEvent?.creator || "", - title: metadata?.title || "", - summary: metadata?.summary || "", - description: metadata?.description || "", - resources: metadata?.resources || [], - }; -} diff --git a/plugins/opt-multisig/hooks/useProposalApprovals.ts b/plugins/opt-multisig/hooks/useProposalApprovals.ts deleted file mode 100644 index cb64525..0000000 --- a/plugins/opt-multisig/hooks/useProposalApprovals.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { useState, useEffect } from "react"; -import { Address, getAbiItem } from "viem"; -import { usePublicClient } from "wagmi"; -import { MultisigProposal, ApprovedEvent } from "../utils/types"; -import { OptimisticMultisigPluginAbi } from "../artifacts/OptimisticMultisigPlugin"; -import { PUB_CHAIN } from "@/constants"; - -const event = getAbiItem({ - abi: OptimisticMultisigPluginAbi, - name: "Approved", -}); - -export function useProposalApprovals(pluginAddress: Address, proposalId: string, proposal: MultisigProposal | null) { - const publicClient = usePublicClient({ chainId: PUB_CHAIN.id }); - const [proposalLogs, setLogs] = useState([]); - - async function getLogs() { - if (!publicClient || !proposal?.parameters?.snapshotBlock) return; - - const logs = await publicClient.getLogs({ - address: pluginAddress, - event: event, - args: { - proposalId: BigInt(proposalId), - }, - fromBlock: proposal.parameters.snapshotBlock, - toBlock: "latest", // TODO: Make this variable between 'latest' and proposal last block - }); - - const newLogs = logs.flatMap((log) => log.args); - if (newLogs.length > proposalLogs.length) setLogs(newLogs); - } - - useEffect(() => { - getLogs(); - }, [!!publicClient, proposal?.parameters?.snapshotBlock]); - - return proposalLogs; -} diff --git a/plugins/opt-multisig/hooks/useProposalApprove.ts b/plugins/opt-multisig/hooks/useProposalApprove.ts deleted file mode 100644 index d0b622e..0000000 --- a/plugins/opt-multisig/hooks/useProposalApprove.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { useProposal } from "./useProposal"; -import { useUserCanApprove } from "./useUserCanApprove"; -import { OptimisticMultisigPluginAbi } from "../artifacts/OptimisticMultisigPlugin"; -import { PUB_OPT_MULTISIG_PLUGIN_ADDRESS } from "@/constants"; -import { useProposalApprovals } from "./useProposalApprovals"; -import { useRouter } from "next/router"; -import { useTransactionManager } from "@/hooks/useTransactionManager"; - -export function useProposalApprove(proposalId: string) { - const { push } = useRouter(); - - const { proposal, status: proposalFetchStatus, refetch: refetchProposal } = useProposal(proposalId, true); - const { canApprove, refetch: refetchCanApprove } = useUserCanApprove(proposalId); - const approvals = useProposalApprovals(PUB_OPT_MULTISIG_PLUGIN_ADDRESS, proposalId, proposal); - - const { writeContract, status, isConfirming, isConfirmed } = useTransactionManager({ - onSuccessMessage: "Approval registered", - onSuccess() { - setTimeout(() => { - push("#/"); - window.scroll(0, 0); - }, 1000 * 2); - refetchCanApprove(); - refetchProposal(); - }, - onErrorMessage: "Could not approve the proposal", - onErrorDescription: "Check that you were part of the multisig when the proposal was created", - }); - - const approveProposal = () => { - writeContract({ - abi: OptimisticMultisigPluginAbi, - address: PUB_OPT_MULTISIG_PLUGIN_ADDRESS, - functionName: "approve", - args: [BigInt(proposalId), true], - }); - }; - - return { - proposal, - proposalFetchStatus, - approvals, - canApprove: !!canApprove, - isConfirming: status === "pending" || isConfirming, - isConfirmed, - approveProposal, - }; -} diff --git a/plugins/opt-multisig/hooks/useProposalExecute.ts b/plugins/opt-multisig/hooks/useProposalExecute.ts deleted file mode 100644 index e8f1283..0000000 --- a/plugins/opt-multisig/hooks/useProposalExecute.ts +++ /dev/null @@ -1,60 +0,0 @@ -import { useState } from "react"; -import { useReadContract } from "wagmi"; -import { useRouter } from "next/router"; -import { PUB_CHAIN, PUB_OPT_MULTISIG_PLUGIN_ADDRESS } from "@/constants"; -import { OptimisticMultisigPluginAbi } from "../artifacts/OptimisticMultisigPlugin"; -import { useTransactionManager } from "@/hooks/useTransactionManager"; -import { DaoAbi } from "@/artifacts/DAO.sol"; - -export function useProposalExecute(proposalId: string) { - const { push } = useRouter(); - const [isExecuting, setIsExecuting] = useState(false); - - const { - data: canExecute, - isError: isCanVoteError, - isLoading: isCanVoteLoading, - } = useReadContract({ - address: PUB_OPT_MULTISIG_PLUGIN_ADDRESS, - abi: OptimisticMultisigPluginAbi, - chainId: PUB_CHAIN.id, - functionName: "canExecute", - args: [BigInt(proposalId)], - }); - - const { writeContract, isConfirming, isConfirmed } = useTransactionManager({ - onSuccessMessage: "Proposal executed", - onSuccess() { - setTimeout(() => { - push("#/"); - window.scroll(0, 0); - }, 1000 * 2); - }, - onErrorMessage: "Could not execute the proposal", - onErrorDescription: "The proposal may contain actions with invalid operations", - onError() { - setIsExecuting(false); - }, - }); - - const executeProposal = () => { - if (!canExecute) return; - - setIsExecuting(true); - - writeContract({ - chainId: PUB_CHAIN.id, - abi: OptimisticMultisigPluginAbi.concat(DaoAbi as any), - address: PUB_OPT_MULTISIG_PLUGIN_ADDRESS, - functionName: "execute", - args: [BigInt(proposalId)], - }); - }; - - return { - executeProposal, - canExecute: !isCanVoteError && !isCanVoteLoading && !isConfirmed && !!canExecute, - isConfirming: isExecuting || isConfirming, - isConfirmed, - }; -} diff --git a/plugins/opt-multisig/hooks/useProposalVariantStatus.ts b/plugins/opt-multisig/hooks/useProposalVariantStatus.ts deleted file mode 100644 index 6d6b22f..0000000 --- a/plugins/opt-multisig/hooks/useProposalVariantStatus.ts +++ /dev/null @@ -1,51 +0,0 @@ -import { useState, useEffect } from "react"; -import { MultisigProposal } from "@/plugins/opt-multisig/utils/types"; -import { ProposalStatus } from "@aragon/ods"; - -export const useProposalVariantStatus = (proposal: MultisigProposal) => { - const [status, setStatus] = useState({ variant: "", label: "" }); - - useEffect(() => { - if (!proposal || !proposal?.parameters) return; - - if (proposal?.executed) { - setStatus({ variant: "primary", label: "Executed" }); - } else if (Math.floor(Date.now() / 1000) >= proposal.parameters.expirationDate) { - if (proposal.approvals < proposal.parameters.minApprovals) { - setStatus({ variant: "critical", label: "Defeated" }); - } else { - setStatus({ variant: "critical", label: "Expired" }); - } - } else if (proposal.approvals >= proposal.parameters.minApprovals) { - setStatus({ variant: "success", label: "Executable" }); - } else { - setStatus({ variant: "info", label: "Active" }); - } - }, [proposal, proposal?.approvals, proposal?.executed, proposal?.parameters?.minApprovals]); - - return status; -}; - -export const useProposalStatus = (proposal: MultisigProposal) => { - const [status, setStatus] = useState(); - - useEffect(() => { - if (!proposal || !proposal?.parameters) return; - - if (proposal?.executed) { - setStatus(ProposalStatus.EXECUTED); - } else if (Math.floor(Date.now() / 1000) >= proposal.parameters.expirationDate) { - if (proposal.approvals < proposal.parameters.minApprovals) { - setStatus(ProposalStatus.REJECTED); - } else { - setStatus(ProposalStatus.EXPIRED); - } - } else if (proposal.approvals >= proposal.parameters.minApprovals) { - setStatus(ProposalStatus.EXECUTABLE); - } else { - setStatus(ProposalStatus.ACTIVE); - } - }, [proposal, proposal?.approvals, proposal?.executed, proposal?.parameters?.minApprovals]); - - return status; -}; diff --git a/plugins/opt-multisig/hooks/useUserCanApprove.ts b/plugins/opt-multisig/hooks/useUserCanApprove.ts deleted file mode 100644 index 6924702..0000000 --- a/plugins/opt-multisig/hooks/useUserCanApprove.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { useAccount, useBlockNumber, useReadContract } from "wagmi"; -import { useEffect } from "react"; -import { PUB_CHAIN, PUB_OPT_MULTISIG_PLUGIN_ADDRESS } from "@/constants"; -import { OptimisticMultisigPluginAbi } from "../artifacts/OptimisticMultisigPlugin"; - -export function useUserCanApprove(proposalId: string | bigint | number) { - const { address } = useAccount(); - const { data: blockNumber } = useBlockNumber({ watch: true }); - - const { data: canApprove, refetch } = useReadContract({ - chainId: PUB_CHAIN.id, - address: PUB_OPT_MULTISIG_PLUGIN_ADDRESS, - abi: OptimisticMultisigPluginAbi, - functionName: "canApprove", - args: [BigInt(proposalId), address!], - query: { - enabled: !!address, - }, - }); - - useEffect(() => { - if (Number(blockNumber) % 2 === 0) { - refetch(); - } - }, [blockNumber]); - - return { canApprove, refetch }; -} diff --git a/plugins/opt-multisig/index.tsx b/plugins/opt-multisig/index.tsx deleted file mode 100644 index 8566156..0000000 --- a/plugins/opt-multisig/index.tsx +++ /dev/null @@ -1,21 +0,0 @@ -import { NotFound } from "@/components/not-found"; -import ProposalCreate from "./pages/new"; -import ProposalList from "./pages/proposal-list"; -import ProposalDetail from "./pages/proposal"; -import { useUrl } from "@/hooks/useUrl"; - -export default function PluginPage() { - // Select the inner pages to display depending on the URL hash - const { hash } = useUrl(); - - if (!hash || hash === "#/") return ; - else if (hash === "#/new") return ; - else if (hash.startsWith("#/proposals/")) { - const id = hash.replace("#/proposals/", ""); - - return ; - } - - // Default not found page - return ; -} diff --git a/plugins/opt-multisig/pages/new.tsx b/plugins/opt-multisig/pages/new.tsx deleted file mode 100644 index d7b783f..0000000 --- a/plugins/opt-multisig/pages/new.tsx +++ /dev/null @@ -1,283 +0,0 @@ -import { Button, IconType, InputText, Tag, TextAreaRichText } from "@aragon/ods"; -import React, { ReactNode, useState } from "react"; -import { RawAction } from "@/utils/types"; -import { Else, ElseIf, If, Then } from "@/components/if"; -import { MainSection } from "@/components/layout/main-section"; -import { useCreateProposal } from "../hooks/useCreateProposal"; -import { useAccount } from "wagmi"; -import { useCanCreateProposal } from "../hooks/useCanCreateProposal"; -import { MissingContentView } from "@/components/MissingContentView"; -import { useWeb3Modal } from "@web3modal/wagmi/react"; -import { Address } from "viem"; -import { NewActionDialog, NewActionType } from "@/components/dialogs/NewActionDialog"; -import { AddActionCard } from "@/components/cards/AddActionCard"; -import { ProposalActions } from "@/components/proposalActions/proposalActions"; -import { downloadAsFile } from "@/utils/download-as-file"; -import { encodeActionsAsJson } from "@/utils/json-actions"; - -export default function Create() { - const { address: selfAddress, isConnected } = useAccount(); - const { canCreate } = useCanCreateProposal(); - const [addActionType, setAddActionType] = useState(""); - const { - title, - summary, - description, - actions, - resources, - setTitle, - setSummary, - setDescription, - setActions, - setResources, - isCreating, - submitProposal, - } = useCreateProposal(); - - const handleTitleInput = (event: React.ChangeEvent) => { - setTitle(event?.target?.value); - }; - const handleSummaryInput = (event: React.ChangeEvent) => { - setSummary(event?.target?.value); - }; - const handleNewActionDialogClose = (newAction: RawAction[] | null) => { - if (!newAction) { - setAddActionType(""); - return; - } - - setActions(actions.concat(newAction)); - setAddActionType(""); - }; - const onRemoveAction = (idx: number) => { - actions.splice(idx, 1); - setActions([].concat(actions as any)); - }; - const removeResource = (idx: number) => { - resources.splice(idx, 1); - setResources([].concat(resources as any)); - }; - const onResourceNameChange = (event: React.ChangeEvent, idx: number) => { - resources[idx].name = event.target.value; - setResources([].concat(resources as any)); - }; - const onResourceUrlChange = (event: React.ChangeEvent, idx: number) => { - resources[idx].url = event.target.value; - setResources([].concat(resources as any)); - }; - - const exportAsJson = () => { - if (!actions.length) return; - - const strResult = encodeActionsAsJson(actions); - downloadAsFile("actions.json", strResult, "text/json"); - }; - - return ( - -
-

- Create Proposal -

- - -
- -
-
- -
-
- -
- -
-
-
-

Resources

- -
-

- Add links to external resources -

-
-
- -

- There are no resources yet. Click the button below to add the first one. -

-
- {resources.map((resource, idx) => { - return ( -
-
- onResourceNameChange(e, idx)} - placeholder="GitHub, Twitter, etc." - /> -
- onResourceUrlChange(e, idx)} - placeholder="https://..." - readOnly={isCreating} - /> -
- ); - })} -
- - - -
- - {/* Actions */} - - onRemoveAction(idx)} - /> - - - - - -
- setAddActionType("withdrawal")} - /> - setAddActionType("select-abi-function")} - /> - setAddActionType("calldata")} - /> - setAddActionType("import-json")} - /> -
- - {/* Dialog */} - - handleNewActionDialogClose(newActions)} - /> - - {/* Submit */} - -
- -
-
-
-
- ); -} - -const PlaceHolderOr = ({ - selfAddress, - isConnected, - canCreate, - children, -}: { - selfAddress: Address | undefined; - isConnected: boolean; - canCreate: boolean | undefined; - children: ReactNode; -}) => { - const { open } = useWeb3Modal(); - return ( - - - {/* Not connected */} - open()}> - Please connect your wallet to continue. - - - - {/* Not a member */} - - You cannot create proposals on the multisig because you are not currently defined as a member. - - - {children} - - ); -}; diff --git a/plugins/opt-multisig/pages/proposal-list.tsx b/plugins/opt-multisig/pages/proposal-list.tsx deleted file mode 100644 index 3d810d2..0000000 --- a/plugins/opt-multisig/pages/proposal-list.tsx +++ /dev/null @@ -1,109 +0,0 @@ -import { useAccount, useBlockNumber, useReadContract } from "wagmi"; -import { type ReactNode, useEffect } from "react"; -import ProposalCard from "@/plugins/opt-multisig/components/proposal"; -import { OptimisticMultisigPluginAbi } from "@/plugins/opt-multisig/artifacts/OptimisticMultisigPlugin"; -import { Button, DataList, IconType, ProposalDataListItemSkeleton, type DataListState } from "@aragon/ods"; -import { useCanCreateProposal } from "@/plugins/opt-multisig/hooks/useCanCreateProposal"; -import Link from "next/link"; -import { Else, ElseIf, If, Then } from "@/components/if"; -import { PUB_OPT_MULTISIG_PLUGIN_ADDRESS, PUB_CHAIN } from "@/constants"; -import { MainSection } from "@/components/layout/main-section"; -import { useWeb3Modal } from "@web3modal/wagmi/react"; -import { MissingContentView } from "@/components/MissingContentView"; - -const DEFAULT_PAGE_SIZE = 6; - -export default function Proposals() { - const { isConnected } = useAccount(); - const { canCreate } = useCanCreateProposal(); - const { open } = useWeb3Modal(); - - const { data: blockNumber } = useBlockNumber({ watch: true }); - - const { - data: proposalCountResponse, - error: isError, - isLoading, - isFetching: isFetchingNextPage, - refetch, - } = useReadContract({ - address: PUB_OPT_MULTISIG_PLUGIN_ADDRESS, - abi: OptimisticMultisigPluginAbi, - functionName: "proposalCount", - chainId: PUB_CHAIN.id, - }); - const proposalCount = Number(proposalCountResponse); - - useEffect(() => { - refetch(); - }, [blockNumber]); - - const entityLabel = proposalCount === 1 ? "Proposal" : "Proposals"; - - let dataListState: DataListState = "idle"; - if (isLoading && !proposalCount) { - dataListState = "initialLoading"; - } else if (isError) { - dataListState = "error"; - } else if (isFetchingNextPage) { - dataListState = "fetchingNextPage"; - } - - return ( - - -

- Proposals -

-
- - - - - -
-
- - - - open()}> - Please connect your wallet to access the proposals section. - - - - - No proposals have been created yet.
- Here you will see the proposals created by the Council before they can be submitted to the community veto - stage. Create your first proposal. -
-
- - - - {proposalCount && - Array.from(Array(proposalCount || 0)?.keys()) - .reverse() - ?.map((proposalIndex) => ( - // TODO: update with router agnostic ODS DataListItem - - ))} - - - - -
-
- ); -} - -function SectionView({ children }: { children: ReactNode }) { - return
{children}
; -} diff --git a/plugins/opt-multisig/pages/proposal.tsx b/plugins/opt-multisig/pages/proposal.tsx deleted file mode 100644 index 6d8ad31..0000000 --- a/plugins/opt-multisig/pages/proposal.tsx +++ /dev/null @@ -1,111 +0,0 @@ -import { type useProposal } from "@/plugins/opt-multisig/hooks/useProposal"; -import ProposalHeader from "@/plugins/opt-multisig/components/proposal/header"; -import { PleaseWaitSpinner } from "@/components/please-wait"; -import { useProposalApprove } from "@/plugins/opt-multisig/hooks/useProposalApprove"; -import { useProposalExecute } from "@/plugins/opt-multisig/hooks/useProposalExecute"; -import { BodySection } from "@/components/proposal/proposalBodySection"; -import { ProposalVoting } from "@/components/proposalVoting"; -import { type ITransformedStage, type IVote, ProposalStages } from "@/utils/types"; -import { useProposalStatus } from "../hooks/useProposalVariantStatus"; -import dayjs from "dayjs"; -import { ProposalActions } from "@/components/proposalActions/proposalActions"; -import { CardResources } from "@/components/proposal/cardResources"; - -export default function ProposalDetail({ id: proposalId }: { id: string }) { - const { - proposal, - proposalFetchStatus, - canApprove, - approvals, - isConfirming: isConfirmingApproval, - approveProposal, - } = useProposalApprove(proposalId); - - const { executeProposal, canExecute, isConfirming: isConfirmingExecution } = useProposalExecute(proposalId); - - const showProposalLoading = getShowProposalLoading(proposal, proposalFetchStatus); - const proposalStatus = useProposalStatus(proposal!); - - const proposalStage: ITransformedStage[] = [ - { - id: "1", - type: ProposalStages.MULTISIG_APPROVAL, - variant: "approvalThreshold", - title: "Onchain multisig", - status: proposalStatus!, - disabled: false, - proposalId: proposalId, - providerId: "1", - result: { - cta: proposal?.executed - ? { - disabled: true, - label: "Executed", - } - : canExecute - ? { - isLoading: isConfirmingExecution, - label: "Execute", - onClick: executeProposal, - } - : { - disabled: !canApprove, - isLoading: isConfirmingApproval, - label: "Approve", - onClick: approveProposal, - }, - approvalAmount: proposal?.approvals || 0, - approvalThreshold: proposal?.parameters.minApprovals || 0, - }, - details: { - censusBlock: Number(proposal?.parameters.snapshotBlock), - startDate: "", - endDate: dayjs(Number(proposal?.parameters.expirationDate) * 1000).toString(), - strategy: "Approval threshold", - options: "Approve", - }, - votes: approvals.map(({ approver }) => ({ address: approver, variant: "approve" }) as IVote), - }, - ]; - - if (!proposal || showProposalLoading) { - return ( -
- -
- ); - } - - return ( -
- - -
-
-
- - - -
-
- -
-
-
-
- ); -} - -function getShowProposalLoading( - proposal: ReturnType["proposal"], - status: ReturnType["status"] -) { - if (!proposal && status.proposalLoading) return true; - else if (status.metadataLoading && !status.metadataError) return true; - else if (!proposal?.title && !status.metadataError) return true; - - return false; -} diff --git a/plugins/opt-multisig/utils/types.ts b/plugins/opt-multisig/utils/types.ts deleted file mode 100644 index 0ecb313..0000000 --- a/plugins/opt-multisig/utils/types.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { Address } from "viem"; -import { IProposalResource, RawAction } from "@/utils/types"; - -export type ProposalInputs = { - proposalId: bigint; -}; - -export type MultisigProposalResultType = readonly [ - boolean, - number, - MultisigProposalParameters, - string, - readonly RawAction[], - Address, -]; - -export type MultisigProposalParameters = { - expirationDate: bigint; - snapshotBlock: bigint; - minApprovals: number; -}; - -export type MultisigProposal = { - executed: boolean; - parameters: MultisigProposalParameters; - approvals: number; - actions: RawAction[]; - allowFailureMap: bigint; - creator: string; - title: string; - summary: string; - description: string; - resources: IProposalResource[]; -}; - -export type ApprovedEvent = { - proposalId?: bigint; - approver?: Address; -}; diff --git a/plugins/optimistic-proposals/artifacts/ERC20Votes.ts b/plugins/optimistic-proposals/artifacts/ERC20Votes.ts deleted file mode 100644 index 7616891..0000000 --- a/plugins/optimistic-proposals/artifacts/ERC20Votes.ts +++ /dev/null @@ -1,26 +0,0 @@ -export const Erc20VotesAbi = [ - { - type: "function", - name: "getPastVotes", - inputs: [ - { - name: "account", - type: "address", - internalType: "address", - }, - { - name: "timepoint", - type: "uint256", - internalType: "uint256", - }, - ], - outputs: [ - { - name: "", - type: "uint256", - internalType: "uint256", - }, - ], - stateMutability: "view", - }, -] as const; diff --git a/plugins/optimistic-proposals/artifacts/MyOptimisticTokenVotingPlugin.sol.tsx b/plugins/optimistic-proposals/artifacts/MyOptimisticTokenVotingPlugin.sol.tsx deleted file mode 100644 index afdb7b1..0000000 --- a/plugins/optimistic-proposals/artifacts/MyOptimisticTokenVotingPlugin.sol.tsx +++ /dev/null @@ -1,1068 +0,0 @@ -export const MyOptimisticTokenVotingPluginAbi = [ - { - type: "function", - name: "PROPOSER_PERMISSION_ID", - inputs: [], - outputs: [ - { - name: "", - type: "bytes32", - internalType: "bytes32", - }, - ], - stateMutability: "view", - }, - { - type: "function", - name: "UPDATE_OPTIMISTIC_GOVERNANCE_SETTINGS_PERMISSION_ID", - inputs: [], - outputs: [ - { - name: "", - type: "bytes32", - internalType: "bytes32", - }, - ], - stateMutability: "view", - }, - { - type: "function", - name: "UPGRADE_PLUGIN_PERMISSION_ID", - inputs: [], - outputs: [ - { - name: "", - type: "bytes32", - internalType: "bytes32", - }, - ], - stateMutability: "view", - }, - { - type: "function", - name: "bridgedVotingPower", - inputs: [ - { - name: "_timestamp", - type: "uint256", - internalType: "uint256", - }, - ], - outputs: [ - { - name: "", - type: "uint256", - internalType: "uint256", - }, - ], - stateMutability: "view", - }, - { - type: "function", - name: "canExecute", - inputs: [ - { - name: "_proposalId", - type: "uint256", - internalType: "uint256", - }, - ], - outputs: [ - { - name: "", - type: "bool", - internalType: "bool", - }, - ], - stateMutability: "view", - }, - { - type: "function", - name: "canVeto", - inputs: [ - { - name: "_proposalId", - type: "uint256", - internalType: "uint256", - }, - { - name: "_voter", - type: "address", - internalType: "address", - }, - ], - outputs: [ - { - name: "", - type: "bool", - internalType: "bool", - }, - ], - stateMutability: "view", - }, - { - type: "function", - name: "createProposal", - inputs: [ - { - name: "_metadata", - type: "bytes", - internalType: "bytes", - }, - { - name: "_actions", - type: "tuple[]", - internalType: "struct IDAO.Action[]", - components: [ - { - name: "to", - type: "address", - internalType: "address", - }, - { - name: "value", - type: "uint256", - internalType: "uint256", - }, - { - name: "data", - type: "bytes", - internalType: "bytes", - }, - ], - }, - { - name: "_allowFailureMap", - type: "uint256", - internalType: "uint256", - }, - { - name: "_duration", - type: "uint64", - internalType: "uint64", - }, - ], - outputs: [ - { - name: "proposalId", - type: "uint256", - internalType: "uint256", - }, - ], - stateMutability: "nonpayable", - }, - { - type: "function", - name: "dao", - inputs: [], - outputs: [ - { - name: "", - type: "address", - internalType: "contract IDAO", - }, - ], - stateMutability: "view", - }, - { - type: "function", - name: "effectiveVotingPower", - inputs: [ - { - name: "_timestamp", - type: "uint256", - internalType: "uint256", - }, - { - name: "_includeL2VotingPower", - type: "bool", - internalType: "bool", - }, - ], - outputs: [ - { - name: "", - type: "uint256", - internalType: "uint256", - }, - ], - stateMutability: "view", - }, - { - type: "function", - name: "execute", - inputs: [ - { - name: "_proposalId", - type: "uint256", - internalType: "uint256", - }, - ], - outputs: [], - stateMutability: "nonpayable", - }, - { - type: "function", - name: "getProposal", - inputs: [ - { - name: "_proposalId", - type: "uint256", - internalType: "uint256", - }, - ], - outputs: [ - { - name: "open", - type: "bool", - internalType: "bool", - }, - { - name: "executed", - type: "bool", - internalType: "bool", - }, - { - name: "parameters", - type: "tuple", - internalType: "struct OptimisticTokenVotingPlugin.ProposalParameters", - components: [ - { - name: "vetoEndDate", - type: "uint64", - internalType: "uint64", - }, - { - name: "snapshotTimestamp", - type: "uint64", - internalType: "uint64", - }, - { - name: "minVetoRatio", - type: "uint32", - internalType: "uint32", - }, - { - name: "skipL2", - type: "bool", - internalType: "bool", - }, - ], - }, - { - name: "vetoTally", - type: "uint256", - internalType: "uint256", - }, - { - name: "metadataURI", - type: "bytes", - internalType: "bytes", - }, - { - name: "actions", - type: "tuple[]", - internalType: "struct IDAO.Action[]", - components: [ - { - name: "to", - type: "address", - internalType: "address", - }, - { - name: "value", - type: "uint256", - internalType: "uint256", - }, - { - name: "data", - type: "bytes", - internalType: "bytes", - }, - ], - }, - { - name: "allowFailureMap", - type: "uint256", - internalType: "uint256", - }, - ], - stateMutability: "view", - }, - { - type: "function", - name: "governanceSettings", - inputs: [], - outputs: [ - { - name: "minVetoRatio", - type: "uint32", - internalType: "uint32", - }, - { - name: "minDuration", - type: "uint64", - internalType: "uint64", - }, - { - name: "l2InactivityPeriod", - type: "uint64", - internalType: "uint64", - }, - { - name: "l2AggregationGracePeriod", - type: "uint64", - internalType: "uint64", - }, - ], - stateMutability: "view", - }, - { - type: "function", - name: "hasVetoed", - inputs: [ - { - name: "_proposalId", - type: "uint256", - internalType: "uint256", - }, - { - name: "_voter", - type: "address", - internalType: "address", - }, - ], - outputs: [ - { - name: "", - type: "bool", - internalType: "bool", - }, - ], - stateMutability: "view", - }, - { - type: "function", - name: "implementation", - inputs: [], - outputs: [ - { - name: "", - type: "address", - internalType: "address", - }, - ], - stateMutability: "view", - }, - { - type: "function", - name: "initialize", - inputs: [ - { - name: "_dao", - type: "address", - internalType: "contract IDAO", - }, - { - name: "_governanceSettings", - type: "tuple", - internalType: "struct OptimisticTokenVotingPlugin.OptimisticGovernanceSettings", - components: [ - { - name: "minVetoRatio", - type: "uint32", - internalType: "uint32", - }, - { - name: "minDuration", - type: "uint64", - internalType: "uint64", - }, - { - name: "l2InactivityPeriod", - type: "uint64", - internalType: "uint64", - }, - { - name: "l2AggregationGracePeriod", - type: "uint64", - internalType: "uint64", - }, - ], - }, - { - name: "_token", - type: "address", - internalType: "contract IVotesUpgradeable", - }, - { - name: "_l1", - type: "address", - internalType: "address", - }, - { - name: "_bridge", - type: "address", - internalType: "address", - }, - ], - outputs: [], - stateMutability: "nonpayable", - }, - { - type: "function", - name: "isL2Available", - inputs: [], - outputs: [ - { - name: "", - type: "bool", - internalType: "bool", - }, - ], - stateMutability: "view", - }, - { - type: "function", - name: "isMember", - inputs: [ - { - name: "_account", - type: "address", - internalType: "address", - }, - ], - outputs: [ - { - name: "", - type: "bool", - internalType: "bool", - }, - ], - stateMutability: "view", - }, - { - type: "function", - name: "isMinVetoRatioReached", - inputs: [ - { - name: "_proposalId", - type: "uint256", - internalType: "uint256", - }, - ], - outputs: [ - { - name: "", - type: "bool", - internalType: "bool", - }, - ], - stateMutability: "view", - }, - { - type: "function", - name: "minVetoRatio", - inputs: [], - outputs: [ - { - name: "", - type: "uint32", - internalType: "uint32", - }, - ], - stateMutability: "view", - }, - { - type: "function", - name: "parseProposalId", - inputs: [ - { - name: "_proposalId", - type: "uint256", - internalType: "uint256", - }, - ], - outputs: [ - { - name: "counter", - type: "uint256", - internalType: "uint256", - }, - { - name: "startDate", - type: "uint64", - internalType: "uint64", - }, - { - name: "endDate", - type: "uint64", - internalType: "uint64", - }, - ], - stateMutability: "pure", - }, - { - type: "function", - name: "pluginType", - inputs: [], - outputs: [ - { - name: "", - type: "uint8", - internalType: "enum IPlugin.PluginType", - }, - ], - stateMutability: "pure", - }, - { - type: "function", - name: "proposalCount", - inputs: [], - outputs: [ - { - name: "", - type: "uint256", - internalType: "uint256", - }, - ], - stateMutability: "view", - }, - { - type: "function", - name: "proposalIds", - inputs: [ - { - name: "", - type: "uint256", - internalType: "uint256", - }, - ], - outputs: [ - { - name: "", - type: "uint256", - internalType: "uint256", - }, - ], - stateMutability: "view", - }, - { - type: "function", - name: "proxiableUUID", - inputs: [], - outputs: [ - { - name: "", - type: "bytes32", - internalType: "bytes32", - }, - ], - stateMutability: "view", - }, - { - type: "function", - name: "supportsInterface", - inputs: [ - { - name: "_interfaceId", - type: "bytes4", - internalType: "bytes4", - }, - ], - outputs: [ - { - name: "", - type: "bool", - internalType: "bool", - }, - ], - stateMutability: "view", - }, - { - type: "function", - name: "bridge", - inputs: [], - outputs: [ - { - name: "", - type: "address", - internalType: "address", - }, - ], - stateMutability: "view", - }, - { - type: "function", - name: "l1", - inputs: [], - outputs: [ - { - name: "", - type: "address", - internalType: "contract l1", - }, - ], - stateMutability: "view", - }, - { - type: "function", - name: "totalVotingPower", - inputs: [ - { - name: "_timestamp", - type: "uint256", - internalType: "uint256", - }, - ], - outputs: [ - { - name: "", - type: "uint256", - internalType: "uint256", - }, - ], - stateMutability: "view", - }, - { - type: "function", - name: "updateOptimisticGovernanceSettings", - inputs: [ - { - name: "_governanceSettings", - type: "tuple", - internalType: "struct OptimisticTokenVotingPlugin.OptimisticGovernanceSettings", - components: [ - { - name: "minVetoRatio", - type: "uint32", - internalType: "uint32", - }, - { - name: "minDuration", - type: "uint64", - internalType: "uint64", - }, - { - name: "l2InactivityPeriod", - type: "uint64", - internalType: "uint64", - }, - { - name: "l2AggregationGracePeriod", - type: "uint64", - internalType: "uint64", - }, - ], - }, - ], - outputs: [], - stateMutability: "nonpayable", - }, - { - type: "function", - name: "upgradeTo", - inputs: [ - { - name: "newImplementation", - type: "address", - internalType: "address", - }, - ], - outputs: [], - stateMutability: "nonpayable", - }, - { - type: "function", - name: "upgradeToAndCall", - inputs: [ - { - name: "newImplementation", - type: "address", - internalType: "address", - }, - { - name: "data", - type: "bytes", - internalType: "bytes", - }, - ], - outputs: [], - stateMutability: "payable", - }, - { - type: "function", - name: "veto", - inputs: [ - { - name: "_proposalId", - type: "uint256", - internalType: "uint256", - }, - ], - outputs: [], - stateMutability: "nonpayable", - }, - { - type: "function", - name: "votingToken", - inputs: [], - outputs: [ - { - name: "", - type: "address", - internalType: "contract IVotesUpgradeable", - }, - ], - stateMutability: "view", - }, - { - type: "event", - name: "AdminChanged", - inputs: [ - { - name: "previousAdmin", - type: "address", - indexed: false, - internalType: "address", - }, - { - name: "newAdmin", - type: "address", - indexed: false, - internalType: "address", - }, - ], - anonymous: false, - }, - { - type: "event", - name: "BeaconUpgraded", - inputs: [ - { - name: "beacon", - type: "address", - indexed: true, - internalType: "address", - }, - ], - anonymous: false, - }, - { - type: "event", - name: "Initialized", - inputs: [ - { - name: "version", - type: "uint8", - indexed: false, - internalType: "uint8", - }, - ], - anonymous: false, - }, - { - type: "event", - name: "MembersAdded", - inputs: [ - { - name: "members", - type: "address[]", - indexed: false, - internalType: "address[]", - }, - ], - anonymous: false, - }, - { - type: "event", - name: "MembersRemoved", - inputs: [ - { - name: "members", - type: "address[]", - indexed: false, - internalType: "address[]", - }, - ], - anonymous: false, - }, - { - type: "event", - name: "MembershipContractAnnounced", - inputs: [ - { - name: "definingContract", - type: "address", - indexed: true, - internalType: "address", - }, - ], - anonymous: false, - }, - { - type: "event", - name: "OptimisticGovernanceSettingsUpdated", - inputs: [ - { - name: "minVetoRatio", - type: "uint32", - indexed: false, - internalType: "uint32", - }, - { - name: "minDuration", - type: "uint64", - indexed: false, - internalType: "uint64", - }, - { - name: "l2AggregationGracePeriod", - type: "uint64", - indexed: false, - internalType: "uint64", - }, - { - name: "l2InactivityPeriod", - type: "uint64", - indexed: false, - internalType: "uint64", - }, - ], - anonymous: false, - }, - { - type: "event", - name: "ProposalCreated", - inputs: [ - { - name: "proposalId", - type: "uint256", - indexed: true, - internalType: "uint256", - }, - { - name: "creator", - type: "address", - indexed: true, - internalType: "address", - }, - { - name: "startDate", - type: "uint64", - indexed: false, - internalType: "uint64", - }, - { - name: "endDate", - type: "uint64", - indexed: false, - internalType: "uint64", - }, - { - name: "metadata", - type: "bytes", - indexed: false, - internalType: "bytes", - }, - { - name: "actions", - type: "tuple[]", - indexed: false, - internalType: "struct IDAO.Action[]", - components: [ - { - name: "to", - type: "address", - internalType: "address", - }, - { - name: "value", - type: "uint256", - internalType: "uint256", - }, - { - name: "data", - type: "bytes", - internalType: "bytes", - }, - ], - }, - { - name: "allowFailureMap", - type: "uint256", - indexed: false, - internalType: "uint256", - }, - ], - anonymous: false, - }, - { - type: "event", - name: "ProposalExecuted", - inputs: [ - { - name: "proposalId", - type: "uint256", - indexed: true, - internalType: "uint256", - }, - ], - anonymous: false, - }, - { - type: "event", - name: "Upgraded", - inputs: [ - { - name: "implementation", - type: "address", - indexed: true, - internalType: "address", - }, - ], - anonymous: false, - }, - { - type: "event", - name: "VetoCast", - inputs: [ - { - name: "proposalId", - type: "uint256", - indexed: true, - internalType: "uint256", - }, - { - name: "voter", - type: "address", - indexed: true, - internalType: "address", - }, - { - name: "votingPower", - type: "uint256", - indexed: false, - internalType: "uint256", - }, - ], - anonymous: false, - }, - { - type: "error", - name: "DaoUnauthorized", - inputs: [ - { - name: "dao", - type: "address", - internalType: "address", - }, - { - name: "where", - type: "address", - internalType: "address", - }, - { - name: "who", - type: "address", - internalType: "address", - }, - { - name: "permissionId", - type: "bytes32", - internalType: "bytes32", - }, - ], - }, - { - type: "error", - name: "DurationOutOfBounds", - inputs: [ - { - name: "limit", - type: "uint64", - internalType: "uint64", - }, - { - name: "actual", - type: "uint64", - internalType: "uint64", - }, - ], - }, - { - type: "error", - name: "MinDurationOutOfBounds", - inputs: [ - { - name: "limit", - type: "uint64", - internalType: "uint64", - }, - { - name: "actual", - type: "uint64", - internalType: "uint64", - }, - ], - }, - { - type: "error", - name: "NoVotingPower", - inputs: [], - }, - { - type: "error", - name: "ProposalCreationForbidden", - inputs: [ - { - name: "sender", - type: "address", - internalType: "address", - }, - ], - }, - { - type: "error", - name: "ProposalExecutionForbidden", - inputs: [ - { - name: "proposalId", - type: "uint256", - internalType: "uint256", - }, - ], - }, - { - type: "error", - name: "ProposalVetoingForbidden", - inputs: [ - { - name: "proposalId", - type: "uint256", - internalType: "uint256", - }, - { - name: "account", - type: "address", - internalType: "address", - }, - ], - }, - { - type: "error", - name: "RatioOutOfBounds", - inputs: [ - { - name: "limit", - type: "uint256", - internalType: "uint256", - }, - { - name: "actual", - type: "uint256", - internalType: "uint256", - }, - ], - }, -] as const; diff --git a/plugins/optimistic-proposals/artifacts/OptimisticTokenVotingPlugin.sol.tsx b/plugins/optimistic-proposals/artifacts/OptimisticTokenVotingPlugin.sol.tsx deleted file mode 100644 index 80be161..0000000 --- a/plugins/optimistic-proposals/artifacts/OptimisticTokenVotingPlugin.sol.tsx +++ /dev/null @@ -1,939 +0,0 @@ -export const OptimisticTokenVotingPluginAbi = [ - { - inputs: [ - { - internalType: "address", - name: "dao", - type: "address", - }, - { - internalType: "address", - name: "where", - type: "address", - }, - { - internalType: "address", - name: "who", - type: "address", - }, - { - internalType: "bytes32", - name: "permissionId", - type: "bytes32", - }, - ], - name: "DaoUnauthorized", - type: "error", - }, - { - inputs: [ - { - internalType: "uint64", - name: "limit", - type: "uint64", - }, - { - internalType: "uint64", - name: "actual", - type: "uint64", - }, - ], - name: "DateOutOfBounds", - type: "error", - }, - { - inputs: [ - { - internalType: "uint64", - name: "limit", - type: "uint64", - }, - { - internalType: "uint64", - name: "actual", - type: "uint64", - }, - ], - name: "MinDurationOutOfBounds", - type: "error", - }, - { - inputs: [ - { - internalType: "uint256", - name: "limit", - type: "uint256", - }, - { - internalType: "uint256", - name: "actual", - type: "uint256", - }, - ], - name: "MinProposerVotingPowerOutOfBounds", - type: "error", - }, - { - inputs: [], - name: "NoVotingPower", - type: "error", - }, - { - inputs: [ - { - internalType: "address", - name: "sender", - type: "address", - }, - ], - name: "ProposalCreationForbidden", - type: "error", - }, - { - inputs: [ - { - internalType: "uint256", - name: "proposalId", - type: "uint256", - }, - ], - name: "ProposalExecutionForbidden", - type: "error", - }, - { - inputs: [ - { - internalType: "uint256", - name: "proposalId", - type: "uint256", - }, - { - internalType: "address", - name: "account", - type: "address", - }, - ], - name: "ProposalVetoingForbidden", - type: "error", - }, - { - inputs: [ - { - internalType: "uint256", - name: "limit", - type: "uint256", - }, - { - internalType: "uint256", - name: "actual", - type: "uint256", - }, - ], - name: "RatioOutOfBounds", - type: "error", - }, - { - anonymous: false, - inputs: [ - { - indexed: false, - internalType: "address", - name: "previousAdmin", - type: "address", - }, - { - indexed: false, - internalType: "address", - name: "newAdmin", - type: "address", - }, - ], - name: "AdminChanged", - type: "event", - }, - { - anonymous: false, - inputs: [ - { - indexed: true, - internalType: "address", - name: "beacon", - type: "address", - }, - ], - name: "BeaconUpgraded", - type: "event", - }, - { - anonymous: false, - inputs: [ - { - indexed: false, - internalType: "uint8", - name: "version", - type: "uint8", - }, - ], - name: "Initialized", - type: "event", - }, - { - anonymous: false, - inputs: [ - { - indexed: false, - internalType: "address[]", - name: "members", - type: "address[]", - }, - ], - name: "MembersAdded", - type: "event", - }, - { - anonymous: false, - inputs: [ - { - indexed: false, - internalType: "address[]", - name: "members", - type: "address[]", - }, - ], - name: "MembersRemoved", - type: "event", - }, - { - anonymous: false, - inputs: [ - { - indexed: true, - internalType: "address", - name: "definingContract", - type: "address", - }, - ], - name: "MembershipContractAnnounced", - type: "event", - }, - { - anonymous: false, - inputs: [ - { - indexed: false, - internalType: "uint32", - name: "minVetoRatio", - type: "uint32", - }, - { - indexed: false, - internalType: "uint64", - name: "minDuration", - type: "uint64", - }, - { - indexed: false, - internalType: "uint256", - name: "minProposerVotingPower", - type: "uint256", - }, - ], - name: "OptimisticGovernanceSettingsUpdated", - type: "event", - }, - { - anonymous: false, - inputs: [ - { - indexed: true, - internalType: "uint256", - name: "proposalId", - type: "uint256", - }, - { - indexed: true, - internalType: "address", - name: "creator", - type: "address", - }, - { - indexed: false, - internalType: "uint64", - name: "startDate", - type: "uint64", - }, - { - indexed: false, - internalType: "uint64", - name: "endDate", - type: "uint64", - }, - { - indexed: false, - internalType: "bytes", - name: "metadata", - type: "bytes", - }, - { - components: [ - { - internalType: "address", - name: "to", - type: "address", - }, - { - internalType: "uint256", - name: "value", - type: "uint256", - }, - { - internalType: "bytes", - name: "data", - type: "bytes", - }, - ], - indexed: false, - internalType: "struct IDAO.Action[]", - name: "actions", - type: "tuple[]", - }, - { - indexed: false, - internalType: "uint256", - name: "allowFailureMap", - type: "uint256", - }, - ], - name: "ProposalCreated", - type: "event", - }, - { - anonymous: false, - inputs: [ - { - indexed: true, - internalType: "uint256", - name: "proposalId", - type: "uint256", - }, - ], - name: "ProposalExecuted", - type: "event", - }, - { - anonymous: false, - inputs: [ - { - indexed: true, - internalType: "address", - name: "implementation", - type: "address", - }, - ], - name: "Upgraded", - type: "event", - }, - { - anonymous: false, - inputs: [ - { - indexed: true, - internalType: "uint256", - name: "proposalId", - type: "uint256", - }, - { - indexed: true, - internalType: "address", - name: "voter", - type: "address", - }, - { - indexed: false, - internalType: "uint256", - name: "votingPower", - type: "uint256", - }, - ], - name: "VetoCast", - type: "event", - }, - { - inputs: [], - name: "OPTIMISTIC_GOVERNANCE_INTERFACE_ID", - outputs: [ - { - internalType: "bytes4", - name: "", - type: "bytes4", - }, - ], - stateMutability: "view", - type: "function", - }, - { - inputs: [], - name: "PROPOSER_PERMISSION_ID", - outputs: [ - { - internalType: "bytes32", - name: "", - type: "bytes32", - }, - ], - stateMutability: "view", - type: "function", - }, - { - inputs: [], - name: "UPDATE_OPTIMISTIC_GOVERNANCE_SETTINGS_PERMISSION_ID", - outputs: [ - { - internalType: "bytes32", - name: "", - type: "bytes32", - }, - ], - stateMutability: "view", - type: "function", - }, - { - inputs: [], - name: "UPGRADE_PLUGIN_PERMISSION_ID", - outputs: [ - { - internalType: "bytes32", - name: "", - type: "bytes32", - }, - ], - stateMutability: "view", - type: "function", - }, - { - inputs: [ - { - internalType: "uint256", - name: "_proposalId", - type: "uint256", - }, - ], - name: "canExecute", - outputs: [ - { - internalType: "bool", - name: "", - type: "bool", - }, - ], - stateMutability: "view", - type: "function", - }, - { - inputs: [ - { - internalType: "uint256", - name: "_proposalId", - type: "uint256", - }, - { - internalType: "address", - name: "_voter", - type: "address", - }, - ], - name: "canVeto", - outputs: [ - { - internalType: "bool", - name: "", - type: "bool", - }, - ], - stateMutability: "view", - type: "function", - }, - { - inputs: [ - { - internalType: "bytes", - name: "_metadata", - type: "bytes", - }, - { - components: [ - { - internalType: "address", - name: "to", - type: "address", - }, - { - internalType: "uint256", - name: "value", - type: "uint256", - }, - { - internalType: "bytes", - name: "data", - type: "bytes", - }, - ], - internalType: "struct IDAO.Action[]", - name: "_actions", - type: "tuple[]", - }, - { - internalType: "uint256", - name: "_allowFailureMap", - type: "uint256", - }, - { - internalType: "uint64", - name: "_startDate", - type: "uint64", - }, - { - internalType: "uint64", - name: "_endDate", - type: "uint64", - }, - ], - name: "createProposal", - outputs: [ - { - internalType: "uint256", - name: "proposalId", - type: "uint256", - }, - ], - stateMutability: "nonpayable", - type: "function", - }, - { - inputs: [], - name: "dao", - outputs: [ - { - internalType: "contract IDAO", - name: "", - type: "address", - }, - ], - stateMutability: "view", - type: "function", - }, - { - inputs: [ - { - internalType: "uint256", - name: "_proposalId", - type: "uint256", - }, - ], - name: "execute", - outputs: [], - stateMutability: "nonpayable", - type: "function", - }, - { - inputs: [ - { - internalType: "uint256", - name: "_proposalId", - type: "uint256", - }, - ], - name: "getProposal", - outputs: [ - { - internalType: "bool", - name: "open", - type: "bool", - }, - { - internalType: "bool", - name: "executed", - type: "bool", - }, - { - components: [ - { - internalType: "uint64", - name: "startDate", - type: "uint64", - }, - { - internalType: "uint64", - name: "endDate", - type: "uint64", - }, - { - internalType: "uint64", - name: "snapshotBlock", - type: "uint64", - }, - { - internalType: "uint256", - name: "minVetoVotingPower", - type: "uint256", - }, - ], - internalType: "struct OptimisticTokenVotingPlugin.ProposalParameters", - name: "parameters", - type: "tuple", - }, - { - internalType: "uint256", - name: "vetoTally", - type: "uint256", - }, - { - components: [ - { - internalType: "address", - name: "to", - type: "address", - }, - { - internalType: "uint256", - name: "value", - type: "uint256", - }, - { - internalType: "bytes", - name: "data", - type: "bytes", - }, - ], - internalType: "struct IDAO.Action[]", - name: "actions", - type: "tuple[]", - }, - { - internalType: "uint256", - name: "allowFailureMap", - type: "uint256", - }, - ], - stateMutability: "view", - type: "function", - }, - { - inputs: [], - name: "getVotingToken", - outputs: [ - { - internalType: "contract IVotesUpgradeable", - name: "", - type: "address", - }, - ], - stateMutability: "view", - type: "function", - }, - { - inputs: [ - { - internalType: "uint256", - name: "_proposalId", - type: "uint256", - }, - { - internalType: "address", - name: "_voter", - type: "address", - }, - ], - name: "hasVetoed", - outputs: [ - { - internalType: "bool", - name: "", - type: "bool", - }, - ], - stateMutability: "view", - type: "function", - }, - { - inputs: [], - name: "implementation", - outputs: [ - { - internalType: "address", - name: "", - type: "address", - }, - ], - stateMutability: "view", - type: "function", - }, - { - inputs: [ - { - internalType: "contract IDAO", - name: "_dao", - type: "address", - }, - { - components: [ - { - internalType: "uint32", - name: "minVetoRatio", - type: "uint32", - }, - { - internalType: "uint64", - name: "minDuration", - type: "uint64", - }, - { - internalType: "uint256", - name: "minProposerVotingPower", - type: "uint256", - }, - ], - internalType: "struct OptimisticTokenVotingPlugin.OptimisticGovernanceSettings", - name: "_governanceSettings", - type: "tuple", - }, - { - internalType: "contract IVotesUpgradeable", - name: "_token", - type: "address", - }, - ], - name: "initialize", - outputs: [], - stateMutability: "nonpayable", - type: "function", - }, - { - inputs: [ - { - internalType: "address", - name: "_account", - type: "address", - }, - ], - name: "isMember", - outputs: [ - { - internalType: "bool", - name: "", - type: "bool", - }, - ], - stateMutability: "view", - type: "function", - }, - { - inputs: [ - { - internalType: "uint256", - name: "_proposalId", - type: "uint256", - }, - ], - name: "isMinVetoRatioReached", - outputs: [ - { - internalType: "bool", - name: "", - type: "bool", - }, - ], - stateMutability: "view", - type: "function", - }, - { - inputs: [], - name: "minDuration", - outputs: [ - { - internalType: "uint64", - name: "", - type: "uint64", - }, - ], - stateMutability: "view", - type: "function", - }, - { - inputs: [], - name: "minProposerVotingPower", - outputs: [ - { - internalType: "uint256", - name: "", - type: "uint256", - }, - ], - stateMutability: "view", - type: "function", - }, - { - inputs: [], - name: "minVetoRatio", - outputs: [ - { - internalType: "uint32", - name: "", - type: "uint32", - }, - ], - stateMutability: "view", - type: "function", - }, - { - inputs: [], - name: "pluginType", - outputs: [ - { - internalType: "enum IPlugin.PluginType", - name: "", - type: "uint8", - }, - ], - stateMutability: "pure", - type: "function", - }, - { - inputs: [], - name: "proposalCount", - outputs: [ - { - internalType: "uint256", - name: "", - type: "uint256", - }, - ], - stateMutability: "view", - type: "function", - }, - { - inputs: [], - name: "proxiableUUID", - outputs: [ - { - internalType: "bytes32", - name: "", - type: "bytes32", - }, - ], - stateMutability: "view", - type: "function", - }, - { - inputs: [ - { - internalType: "bytes4", - name: "_interfaceId", - type: "bytes4", - }, - ], - name: "supportsInterface", - outputs: [ - { - internalType: "bool", - name: "", - type: "bool", - }, - ], - stateMutability: "view", - type: "function", - }, - { - inputs: [ - { - internalType: "uint256", - name: "_blockNumber", - type: "uint256", - }, - ], - name: "totalVotingPower", - outputs: [ - { - internalType: "uint256", - name: "", - type: "uint256", - }, - ], - stateMutability: "view", - type: "function", - }, - { - inputs: [ - { - components: [ - { - internalType: "uint32", - name: "minVetoRatio", - type: "uint32", - }, - { - internalType: "uint64", - name: "minDuration", - type: "uint64", - }, - { - internalType: "uint256", - name: "minProposerVotingPower", - type: "uint256", - }, - ], - internalType: "struct OptimisticTokenVotingPlugin.OptimisticGovernanceSettings", - name: "_governanceSettings", - type: "tuple", - }, - ], - name: "updateOptimisticGovernanceSettings", - outputs: [], - stateMutability: "nonpayable", - type: "function", - }, - { - inputs: [ - { - internalType: "address", - name: "newImplementation", - type: "address", - }, - ], - name: "upgradeTo", - outputs: [], - stateMutability: "nonpayable", - type: "function", - }, - { - inputs: [ - { - internalType: "address", - name: "newImplementation", - type: "address", - }, - { - internalType: "bytes", - name: "data", - type: "bytes", - }, - ], - name: "upgradeToAndCall", - outputs: [], - stateMutability: "payable", - type: "function", - }, - { - inputs: [ - { - internalType: "uint256", - name: "_proposalId", - type: "uint256", - }, - ], - name: "veto", - outputs: [], - stateMutability: "nonpayable", - type: "function", - }, -] as const; diff --git a/plugins/optimistic-proposals/components/proposal/header.tsx b/plugins/optimistic-proposals/components/proposal/header.tsx deleted file mode 100644 index 263c488..0000000 --- a/plugins/optimistic-proposals/components/proposal/header.tsx +++ /dev/null @@ -1,93 +0,0 @@ -import { AvatarIcon, Breadcrumbs, Heading, IBreadcrumbsLink, IconType, ProposalStatus, Tag } from "@aragon/ods"; -import { Publisher } from "@/components/publisher"; -import { OptimisticProposal } from "@/plugins/optimistic-proposals/utils/types"; -import { useProposalStatus } from "@/plugins/optimistic-proposals/hooks/useProposalVariantStatus"; -import { Else, ElseIf, If, Then } from "@/components/if"; -import { getSimpleRelativeTimeFromDate } from "@/utils/dates"; -import dayjs from "dayjs"; -import { HeaderSection } from "@/components/layout/header-section"; -import { useGovernanceSettings } from "../../hooks/useGovernanceSettings"; -import { getTagVariantFromStatus } from "@/utils/ui-variants"; -import { capitalizeFirstLetter } from "@/utils/text"; - -const DEFAULT_PROPOSAL_TITLE = "(No proposal title)"; -const DEFAULT_PROPOSAL_SUMMARY = "(No proposal summary)"; - -interface ProposalHeaderProps { - proposalIdx: number; - proposal: OptimisticProposal; -} - -const ProposalHeader: React.FC = ({ proposalIdx, proposal }) => { - const proposalStatus = useProposalStatus(proposal); - const tagVariant = getTagVariantFromStatus(proposalStatus); - const { governanceSettings } = useGovernanceSettings(); - - const breadcrumbs: IBreadcrumbsLink[] = [{ label: "Proposals", href: "#/" }, { label: proposalIdx.toString() }]; - const isEmergency = proposal.parameters.vetoStartDate === 0n; - const endDateIsInThePast = Number(proposal.parameters.vetoEndDate) * 1000 < Date.now(); - - let isL2GracePeriod = false; - if (!proposal.parameters.skipL2 && governanceSettings.l2AggregationGracePeriod) { - const gracePeriodEnd = - (Number(proposal.parameters.vetoEndDate) + Number(governanceSettings.l2AggregationGracePeriod)) * 1000; - - isL2GracePeriod = endDateIsInThePast && Date.now() < gracePeriodEnd; - } - - return ( -
- {/* Wrapper */} - - - {/* Title & description */} -
-
- {proposal.title || DEFAULT_PROPOSAL_TITLE} - {isEmergency && } -
-

{proposal.summary || DEFAULT_PROPOSAL_SUMMARY}

-
- {/* Metadata */} -
-
- - -
-
- -
- - - The proposal has been defeated - - - The veto period is over, waiting for L2 vetoes - - - The veto period is over - - - Active for - - {getSimpleRelativeTimeFromDate(dayjs(Number(proposal.parameters.vetoEndDate) * 1000))} - - - -
-
-
-
-
- ); -}; - -export default ProposalHeader; diff --git a/plugins/optimistic-proposals/components/proposal/index.tsx b/plugins/optimistic-proposals/components/proposal/index.tsx deleted file mode 100644 index cdd18c8..0000000 --- a/plugins/optimistic-proposals/components/proposal/index.tsx +++ /dev/null @@ -1,105 +0,0 @@ -import Link from "next/link"; -import { useProposalVeto } from "@/plugins/optimistic-proposals/hooks/useProposalVeto"; -import { Card, ProposalStatus } from "@aragon/ods"; -import { ProposalDataListItem } from "@aragon/ods"; -import { PleaseWaitSpinner } from "@/components/please-wait"; -import { useProposalStatus } from "../../hooks/useProposalVariantStatus"; -import { PUB_TOKEN_SYMBOL } from "@/constants"; -import { useAccount } from "wagmi"; -import { formatEther } from "viem"; -import { usePastSupply } from "../../hooks/usePastSupply"; -import { useToken } from "../../hooks/useToken"; - -const DEFAULT_PROPOSAL_METADATA_TITLE = "(No proposal title)"; -const DEFAULT_PROPOSAL_METADATA_SUMMARY = "(The metadata of the proposal is not available)"; - -type ProposalInputs = { - proposalIndex: number; -}; - -export default function ProposalCard(props: ProposalInputs) { - const { address } = useAccount(); - const { proposal, proposalFetchStatus, vetoes } = useProposalVeto(props.proposalIndex); - const pastSupply = usePastSupply(proposal); - const { symbol: tokenSymbol } = useToken(); - - const proposalStatus = useProposalStatus(proposal!); - const showLoading = getShowProposalLoading(proposal, proposalFetchStatus); - const hasVetoed = vetoes?.some((veto) => veto.voter === address); - - if (!proposal && showLoading) { - return ( -
- - - - - -
- ); - } else if (!proposal?.title && !proposal?.summary) { - // We have the proposal but no metadata yet - return ( - - - - - - - - ); - } else if (proposalFetchStatus.metadataReady && !proposal?.title) { - return ( - - -
-

- {Number(props.proposalIndex) + 1} - {DEFAULT_PROPOSAL_METADATA_TITLE} -

-

{DEFAULT_PROPOSAL_METADATA_SUMMARY}

-
-
- - ); - } - - let vetoPercentage = 0; - if (proposal?.vetoTally && pastSupply && proposal.parameters.minVetoRatio) { - vetoPercentage = Number( - (BigInt(1000) * proposal.vetoTally) / ((pastSupply * BigInt(proposal.parameters.minVetoRatio)) / BigInt(10000000)) - ); - } - - return ( - - ); -} - -function getShowProposalLoading( - proposal: ReturnType["proposal"], - status: ReturnType["proposalFetchStatus"] -) { - if (!proposal || status.proposalLoading) return true; - else if (status.metadataLoading && !status.metadataError) return true; - else if (!proposal?.title && !status.metadataError) return true; - - return false; -} diff --git a/plugins/optimistic-proposals/components/vote/tally.tsx b/plugins/optimistic-proposals/components/vote/tally.tsx deleted file mode 100644 index 82913b1..0000000 --- a/plugins/optimistic-proposals/components/vote/tally.tsx +++ /dev/null @@ -1,35 +0,0 @@ -import { compactNumber } from "@/utils/numbers"; -import { FC, ReactNode } from "react"; -import { formatUnits } from "viem"; - -interface VoteTallyProps { - voteCount: bigint; - votePercentage: number; -} - -const VetoTally: FC = ({ voteCount, votePercentage }) => ( - -
-

Vetoed

-

{compactNumber(formatUnits(voteCount || BigInt(0), 18))}

-
-
-
-
- -); - -// This should be encapsulated as soon as ODS exports this widget -const Card = function ({ children }: { children: ReactNode }) { - return ( -
- {children} -
- ); -}; - -export default VetoTally; diff --git a/plugins/optimistic-proposals/components/vote/vetoes-section.tsx b/plugins/optimistic-proposals/components/vote/vetoes-section.tsx deleted file mode 100644 index c31adf5..0000000 --- a/plugins/optimistic-proposals/components/vote/vetoes-section.tsx +++ /dev/null @@ -1,42 +0,0 @@ -import Blockies from "react-blockies"; -import { VetoCastEvent } from "@/plugins/optimistic-proposals/utils/types"; -import { formatUnits } from "viem"; -import { AddressText } from "@/components/text/address"; -import { Card } from "@aragon/ods"; -import { compactNumber } from "@/utils/numbers"; -import { If } from "@/components/if"; - -export default function VetoesSection({ vetoes }: { vetoes: Array }) { - return ( -
-
- -

The proposal has no vetoes

-
-
- {vetoes.map((veto, i) => ( - - ))} -
-
-
- ); -} - -const VetoCard = function ({ veto }: { veto: VetoCastEvent }) { - return ( - -
-
- -
- {veto?.voter} -

- {compactNumber(formatUnits(veto.votingPower || BigInt(0), 18))} votes -

-
-
-
-
- ); -}; diff --git a/plugins/optimistic-proposals/hooks/useCanCreateProposal.ts b/plugins/optimistic-proposals/hooks/useCanCreateProposal.ts deleted file mode 100644 index 6eb5dc2..0000000 --- a/plugins/optimistic-proposals/hooks/useCanCreateProposal.ts +++ /dev/null @@ -1,90 +0,0 @@ -import { type Address, keccak256, toHex } from "viem"; -import { useState, useEffect } from "react"; -import { useBalance, useAccount, useReadContracts, useReadContract } from "wagmi"; -import { OptimisticTokenVotingPluginAbi } from "@/plugins/optimistic-proposals/artifacts/OptimisticTokenVotingPlugin.sol"; -import { DaoAbi } from "@/artifacts/DAO.sol"; -import { PUB_CHAIN, PUB_DUAL_GOVERNANCE_PLUGIN_ADDRESS } from "@/constants"; -import { ADDRESS_ZERO } from "@/utils/evm"; - -export function useCanCreateProposal() { - const { address } = useAccount(); - - const [minProposerVotingPower, setMinProposerVotingPower] = useState(); - const [votingToken, setVotingToken] = useState
(); - const [daoAddress, setDaoAddress] = useState
(); - const [hasCreatePermission, setHasCreatePermission] = useState(false); - const { data: balance } = useBalance({ - address, - token: votingToken, - chainId: PUB_CHAIN.id, - query: { - enabled: !!address, - }, - }); - - const { data: contractReads } = useReadContracts({ - contracts: [ - { - chainId: PUB_CHAIN.id, - address: PUB_DUAL_GOVERNANCE_PLUGIN_ADDRESS, - abi: OptimisticTokenVotingPluginAbi, - functionName: "minProposerVotingPower", - }, - { - chainId: PUB_CHAIN.id, - address: PUB_DUAL_GOVERNANCE_PLUGIN_ADDRESS, - abi: OptimisticTokenVotingPluginAbi, - functionName: "getVotingToken", - }, - { - chainId: PUB_CHAIN.id, - address: PUB_DUAL_GOVERNANCE_PLUGIN_ADDRESS, - abi: OptimisticTokenVotingPluginAbi, - functionName: "dao", - }, - // TODO: This needs to be checking as well if address has the DAO permission to create props - ], - }); - - // Check if PROPOSER_PERMISSION is granted to the current wallet - const { - data: hasCreatePermissionData, - refetch: hasCreatePermissionRefetch, - status: hasCreatePermissionStatus, - } = useReadContract({ - chainId: PUB_CHAIN.id, - address: daoAddress, - abi: DaoAbi, - functionName: "hasPermission", - // where, who, permissionId, data - args: [PUB_DUAL_GOVERNANCE_PLUGIN_ADDRESS, address ?? ADDRESS_ZERO, keccak256(toHex("PROPOSER_PERMISSION")), "0x"], - query: { - enabled: !!daoAddress && !!address, - }, - }); - - useEffect(() => { - if (!contractReads?.length || contractReads?.length < 2) return; - - setMinProposerVotingPower(contractReads[0].result as bigint); - setVotingToken(contractReads[1].result as Address); - setDaoAddress(contractReads[2].result as Address); - }, [contractReads?.[0]?.status, contractReads?.[1]?.status, contractReads?.[2]?.status]); - - useEffect(() => { - setHasCreatePermission(!!hasCreatePermissionData); - }, [hasCreatePermissionStatus]); - - useEffect(() => { - hasCreatePermissionRefetch(); - }, [daoAddress, address]); - - if (!address) return false; - else if (!hasCreatePermission) return false; - else if (!balance) return false; - else if (minProposerVotingPower) { - if (balance?.value < minProposerVotingPower) return false; - } - - return true; -} diff --git a/plugins/optimistic-proposals/hooks/useGovernanceSettings.ts b/plugins/optimistic-proposals/hooks/useGovernanceSettings.ts deleted file mode 100644 index 83cd206..0000000 --- a/plugins/optimistic-proposals/hooks/useGovernanceSettings.ts +++ /dev/null @@ -1,43 +0,0 @@ -import { PUB_DUAL_GOVERNANCE_PLUGIN_ADDRESS } from "@/constants"; -import { useConfig } from "wagmi"; -import { MyOptimisticTokenVotingPluginAbi } from "../artifacts/MyOptimisticTokenVotingPlugin.sol"; -import { useQuery } from "@tanstack/react-query"; -import { readContract } from "@wagmi/core"; - -export function useGovernanceSettings() { - const config = useConfig(); - - const { - data: governanceSettings, - isLoading, - error, - refetch, - } = useQuery({ - queryKey: ["governance-settings", PUB_DUAL_GOVERNANCE_PLUGIN_ADDRESS], - queryFn: () => { - return readContract(config, { - abi: MyOptimisticTokenVotingPluginAbi, - address: PUB_DUAL_GOVERNANCE_PLUGIN_ADDRESS, - functionName: "governanceSettings", - args: [], - }); - }, - retry: true, - refetchOnMount: false, - refetchOnReconnect: false, - retryOnMount: true, - staleTime: 1000 * 60 * 60, - }); - - return { - governanceSettings: { - minVetoRatio: governanceSettings?.[0], - minDuration: governanceSettings?.[1], - l2InactivityPeriod: governanceSettings?.[2], - l2AggregationGracePeriod: governanceSettings?.[3], - }, - isLoading, - error, - refetch, - }; -} diff --git a/plugins/optimistic-proposals/hooks/usePastSupply.ts b/plugins/optimistic-proposals/hooks/usePastSupply.ts deleted file mode 100644 index 8a207d0..0000000 --- a/plugins/optimistic-proposals/hooks/usePastSupply.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { PUB_TOKEN_ADDRESS } from "@/constants"; -import { useReadContract } from "wagmi"; -import { parseAbi } from "viem"; -import { OptimisticProposal } from "../utils/types"; - -const erc20Votes = parseAbi(["function getPastTotalSupply(uint256 blockNumber) view returns (uint256)"]); - -export function usePastSupply(proposal: OptimisticProposal | null) { - const { data: pastSupply } = useReadContract({ - address: PUB_TOKEN_ADDRESS, - abi: erc20Votes, - functionName: "getPastTotalSupply", - args: [proposal?.parameters.snapshotTimestamp || BigInt(0)], - }); - - return pastSupply || BigInt(0); -} diff --git a/plugins/optimistic-proposals/hooks/useProposal.ts b/plugins/optimistic-proposals/hooks/useProposal.ts deleted file mode 100644 index ab77091..0000000 --- a/plugins/optimistic-proposals/hooks/useProposal.ts +++ /dev/null @@ -1,154 +0,0 @@ -import { useState, useEffect } from "react"; -import { useBlockNumber, usePublicClient, useReadContract } from "wagmi"; -import { Address, Hex, getAbiItem } from "viem"; -import { ProposalMetadata, type RawAction, type DecodedAction } from "@/utils/types"; -import { - type OptimisticProposal, - type OptimisticProposalParameters, - type OptimisticProposalResultType, -} from "@/plugins/optimistic-proposals/utils/types"; -import { PUB_CHAIN, PUB_DUAL_GOVERNANCE_PLUGIN_ADDRESS } from "@/constants"; -import { useMetadata } from "@/hooks/useMetadata"; -import { MyOptimisticTokenVotingPluginAbi } from "../artifacts/MyOptimisticTokenVotingPlugin.sol"; -import { parseProposalId } from "../utils/proposal-id"; - -type ProposalCreatedLogResponse = { - args: { - actions: RawAction[]; - allowFailureMap: bigint; - creator: Address; - endDate: bigint; - startDate: bigint; - metadata: Hex; - proposalId: bigint; - }; -}; - -const ProposalCreatedEvent = getAbiItem({ - abi: MyOptimisticTokenVotingPluginAbi, - name: "ProposalCreated", -}); - -export function useProposal(proposalId?: bigint, autoRefresh = false) { - const publicClient = usePublicClient(); - const [proposalCreationEvent, setProposalCreationEvent] = useState(); - const { data: blockNumber } = useBlockNumber({ watch: true }); - - // Proposal onchain data - const { - data: proposalResult, - error: proposalError, - fetchStatus: proposalFetchStatus, - refetch: proposalRefetch, - } = useReadContract({ - address: PUB_DUAL_GOVERNANCE_PLUGIN_ADDRESS, - abi: MyOptimisticTokenVotingPluginAbi, - functionName: "getProposal", - args: [proposalId ?? BigInt(0)], - chainId: PUB_CHAIN.id, - }); - - const proposalData = decodeProposalResultData(proposalResult); - - useEffect(() => { - if (autoRefresh) proposalRefetch(); - }, [blockNumber]); - - // Creation event - useEffect(() => { - if (!proposalData || !publicClient) return; - - publicClient - .getLogs({ - address: PUB_DUAL_GOVERNANCE_PLUGIN_ADDRESS, - event: ProposalCreatedEvent, - args: { - proposalId, - }, - fromBlock: BigInt(0), - toBlock: "latest", - }) - .then((logs: any) => { - if (!logs || !logs.length) throw new Error("No creation logs"); - - const event = logs.find((item: any) => item.args.proposalId === proposalId); - - if (!event) return; - setProposalCreationEvent((event as any).args); - }) - .catch((err) => { - console.error("Could not fetch the proposal details", err); - return null; - }); - }, [proposalId, !!proposalData, publicClient?.chain.id]); - - // JSON metadata - const { - data: metadataContent, - isLoading: metadataLoading, - error: metadataError, - } = useMetadata(proposalData?.metadataUri); - - const proposal = arrangeProposalData(proposalId, proposalData, proposalCreationEvent, metadataContent); - - return { - proposal, - refetch: proposalRefetch, - status: { - proposalReady: proposalFetchStatus === "idle", - proposalLoading: proposalFetchStatus === "fetching", - proposalError, - metadataReady: !metadataError && !metadataLoading && !!metadataContent, - metadataLoading, - metadataError: metadataError !== undefined, - }, - }; -} - -// Helpers - -function decodeProposalResultData(data?: OptimisticProposalResultType) { - if (!data?.length || data.length < 6) return null; - - return { - active: data[0] as boolean, - executed: data[1] as boolean, - parameters: data[2] as OptimisticProposalParameters, - vetoTally: data[3] as bigint, - metadataUri: data[4] as string, - actions: data[5] as Array, - allowFailureMap: data[6] as bigint, - }; -} - -function arrangeProposalData( - proposalId?: bigint, - proposalData?: ReturnType, - creationEvent?: ProposalCreatedLogResponse["args"], - metadata?: ProposalMetadata -): OptimisticProposal | null { - if (!proposalData || !proposalId) return null; - - const { index, startDate: vetoStartDate, endDate: vetoEndDate } = parseProposalId(proposalId); - - return { - index, - actions: proposalData.actions, - active: proposalData.active, - executed: proposalData.executed, - parameters: { - minVetoRatio: proposalData.parameters.minVetoRatio, - skipL2: proposalData.parameters.skipL2, - snapshotTimestamp: proposalData.parameters.snapshotTimestamp, - vetoStartDate, - vetoEndDate, - }, - vetoTally: proposalData.vetoTally, - allowFailureMap: proposalData.allowFailureMap, - creator: creationEvent?.creator ?? "", - title: metadata?.title ?? "", - summary: metadata?.summary ?? "", - description: metadata?.description ?? "", - resources: metadata?.resources ?? [], - }; -} diff --git a/plugins/optimistic-proposals/hooks/useProposalExecute.ts b/plugins/optimistic-proposals/hooks/useProposalExecute.ts deleted file mode 100644 index df38db4..0000000 --- a/plugins/optimistic-proposals/hooks/useProposalExecute.ts +++ /dev/null @@ -1,62 +0,0 @@ -import { useState } from "react"; -import { useReadContract } from "wagmi"; -import { OptimisticTokenVotingPluginAbi } from "../artifacts/OptimisticTokenVotingPlugin.sol"; -import { AlertContextProps, useAlerts } from "@/context/Alerts"; -import { useRouter } from "next/router"; -import { PUB_CHAIN, PUB_DUAL_GOVERNANCE_PLUGIN_ADDRESS } from "@/constants"; -import { useProposalId } from "./useProposalId"; -import { useTransactionManager } from "@/hooks/useTransactionManager"; -import { DaoAbi } from "@/artifacts/DAO.sol"; - -export function useProposalExecute(index: number) { - const { reload } = useRouter(); - const { addAlert } = useAlerts() as AlertContextProps; - const { proposalId } = useProposalId(index); - const [isExecuting, setIsExecuting] = useState(false); - - const { - data: canExecute, - isError: isCanVoteError, - isLoading: isCanVoteLoading, - } = useReadContract({ - address: PUB_DUAL_GOVERNANCE_PLUGIN_ADDRESS, - abi: OptimisticTokenVotingPluginAbi, - chainId: PUB_CHAIN.id, - functionName: "canExecute", - args: [proposalId ?? BigInt("0")], - }); - - const { writeContract, isConfirming, isConfirmed } = useTransactionManager({ - onSuccessMessage: "Proposal executed", - onSuccess() { - setTimeout(() => reload(), 1000 * 2); - }, - onErrorMessage: "Could not execute the proposal", - onErrorDescription: "The proposal may contain actions with invalid operations", - onError() { - setIsExecuting(false); - }, - }); - - const executeProposal = () => { - if (!canExecute) return; - else if (typeof proposalId === "undefined") return; - - setIsExecuting(true); - - writeContract({ - chainId: PUB_CHAIN.id, - abi: OptimisticTokenVotingPluginAbi.concat(DaoAbi as any), - address: PUB_DUAL_GOVERNANCE_PLUGIN_ADDRESS, - functionName: "execute", - args: [BigInt(proposalId)], - }); - }; - - return { - executeProposal, - canExecute: !isCanVoteError && !isCanVoteLoading && !isConfirmed && !!canExecute, - isConfirming: isExecuting || isConfirming, - isConfirmed, - }; -} diff --git a/plugins/optimistic-proposals/hooks/useProposalId.ts b/plugins/optimistic-proposals/hooks/useProposalId.ts deleted file mode 100644 index 5822f0a..0000000 --- a/plugins/optimistic-proposals/hooks/useProposalId.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { useReadContract } from "wagmi"; -import { PUB_CHAIN, PUB_DUAL_GOVERNANCE_PLUGIN_ADDRESS } from "@/constants"; -import { MyOptimisticTokenVotingPluginAbi } from "../artifacts/MyOptimisticTokenVotingPlugin.sol"; - -export function useProposalId(index: number) { - const { - data: proposalId, - error: proposalIdError, - fetchStatus: proposalIdFetchStatus, - } = useReadContract({ - address: PUB_DUAL_GOVERNANCE_PLUGIN_ADDRESS, - abi: MyOptimisticTokenVotingPluginAbi, - functionName: "proposalIds", - args: [BigInt(index)], - chainId: PUB_CHAIN.id, - }); - return { - proposalId, - proposalIdError, - proposalIdFetchStatus, - }; -} diff --git a/plugins/optimistic-proposals/hooks/useProposalVariantStatus.ts b/plugins/optimistic-proposals/hooks/useProposalVariantStatus.ts deleted file mode 100644 index ae9eae3..0000000 --- a/plugins/optimistic-proposals/hooks/useProposalVariantStatus.ts +++ /dev/null @@ -1,76 +0,0 @@ -import { useState, useEffect } from "react"; -import { OptimisticProposal } from "../utils/types"; -import { ProposalStatus } from "@aragon/ods"; -import { useToken } from "./useToken"; -import { PUB_BRIDGE_ADDRESS } from "@/constants"; -import { useTokenPastVotes } from "./useTokenPastVotes"; - -export const useProposalVariantStatus = (proposal: OptimisticProposal) => { - const [status, setStatus] = useState({ variant: "", label: "" }); - const { tokenSupply: totalSupply } = useToken(); - const { votes: bridgedBalance } = useTokenPastVotes( - PUB_BRIDGE_ADDRESS, - proposal?.parameters.snapshotTimestamp || BigInt(0) - ); - - useEffect(() => { - if (!proposal || !proposal?.parameters || !totalSupply || typeof bridgedBalance === "undefined") return; - - const effectiveSupply = proposal.parameters.skipL2 ? totalSupply - bridgedBalance : totalSupply; - const minVetoVotingPower = (effectiveSupply * BigInt(proposal.parameters.minVetoRatio)) / BigInt(1_000_000); - - if (proposal?.active) { - setStatus({ variant: "info", label: "Active" }); - } else if (proposal?.executed) { - setStatus({ variant: "primary", label: "Executed" }); - } else if (proposal?.vetoTally >= minVetoVotingPower) { - setStatus({ variant: "critical", label: "Defeated" }); - } else { - setStatus({ variant: "success", label: "Executable" }); - } - }, [ - proposal?.vetoTally, - proposal?.active, - proposal?.executed, - proposal?.parameters?.minVetoRatio, - totalSupply, - bridgedBalance, - ]); - - return status; -}; - -export const useProposalStatus = (proposal: OptimisticProposal) => { - const [status, setStatus] = useState(); - const { tokenSupply: totalSupply } = useToken(); - const { votes: bridgedBalance } = useTokenPastVotes( - PUB_BRIDGE_ADDRESS, - proposal?.parameters.snapshotTimestamp || BigInt(0) - ); - - useEffect(() => { - if (!proposal || !proposal?.parameters || !totalSupply || typeof bridgedBalance === "undefined") return; - - const effectiveSupply = proposal.parameters.skipL2 ? totalSupply - bridgedBalance : totalSupply; - const minVetoVotingPower = (effectiveSupply * BigInt(proposal.parameters.minVetoRatio)) / BigInt(1_000_000); - - if (proposal?.active) { - setStatus(ProposalStatus.ACTIVE); - } else if (proposal?.executed) { - setStatus(ProposalStatus.EXECUTED); - } else if (proposal?.vetoTally >= minVetoVotingPower) { - setStatus(ProposalStatus.VETOED); - } else { - setStatus(ProposalStatus.ACCEPTED); - } - }, [ - proposal?.vetoTally, - proposal?.active, - proposal?.executed, - proposal?.parameters?.minVetoRatio, - totalSupply, - bridgedBalance, - ]); - - return status; -}; diff --git a/plugins/optimistic-proposals/hooks/useProposalVeto.ts b/plugins/optimistic-proposals/hooks/useProposalVeto.ts deleted file mode 100644 index 59b7044..0000000 --- a/plugins/optimistic-proposals/hooks/useProposalVeto.ts +++ /dev/null @@ -1,47 +0,0 @@ -import { useProposal } from "./useProposal"; -import { useProposalVetoes } from "@/plugins/optimistic-proposals/hooks/useProposalVetoes"; -import { useUserCanVeto } from "@/plugins/optimistic-proposals/hooks/useUserCanVeto"; -import { OptimisticTokenVotingPluginAbi } from "@/plugins/optimistic-proposals/artifacts/OptimisticTokenVotingPlugin.sol"; -import { PUB_DUAL_GOVERNANCE_PLUGIN_ADDRESS } from "@/constants"; -import { useProposalId } from "./useProposalId"; -import { useTransactionManager } from "@/hooks/useTransactionManager"; - -export function useProposalVeto(index: number) { - const { proposalId } = useProposalId(index); - const { proposal, status: proposalFetchStatus, refetch: refetchProposal } = useProposal(proposalId, true); - const vetoes = useProposalVetoes(proposalId); - const { canVeto, refetch: refetchCanVeto } = useUserCanVeto(proposalId); - - const { - writeContract, - status: vetoingStatus, - isConfirming, - isConfirmed, - } = useTransactionManager({ - onSuccessMessage: "Veto registered", - onSuccess() { - refetchCanVeto(); - refetchProposal(); - }, - onErrorMessage: "Could not submit the veto", - }); - - const vetoProposal = () => { - writeContract({ - abi: OptimisticTokenVotingPluginAbi, - address: PUB_DUAL_GOVERNANCE_PLUGIN_ADDRESS, - functionName: "veto", - args: [proposalId ?? BigInt(0)], - }); - }; - - return { - proposal, - proposalFetchStatus, - vetoes, - canVeto: !!canVeto, - isConfirming: vetoingStatus === "pending" || isConfirming, - isConfirmed, - vetoProposal, - }; -} diff --git a/plugins/optimistic-proposals/hooks/useProposalVetoes.ts b/plugins/optimistic-proposals/hooks/useProposalVetoes.ts deleted file mode 100644 index bcaa2a9..0000000 --- a/plugins/optimistic-proposals/hooks/useProposalVetoes.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { useState, useEffect } from "react"; -import { getAbiItem } from "viem"; -import { OptimisticTokenVotingPluginAbi } from "@/plugins/optimistic-proposals/artifacts/OptimisticTokenVotingPlugin.sol"; -import { VetoCastEvent } from "@/plugins/optimistic-proposals/utils/types"; -import { usePublicClient } from "wagmi"; -import { PUB_DUAL_GOVERNANCE_PLUGIN_ADDRESS } from "@/constants"; - -const event = getAbiItem({ - abi: OptimisticTokenVotingPluginAbi, - name: "VetoCast", -}); - -export function useProposalVetoes(proposalId?: bigint) { - const publicClient = usePublicClient(); - const [proposalLogs, setLogs] = useState([]); - - useEffect(() => { - if (!proposalId || !publicClient) return; - - publicClient - .getLogs({ - address: PUB_DUAL_GOVERNANCE_PLUGIN_ADDRESS, - event: event, - args: { - proposalId, - }, - fromBlock: BigInt(0), - toBlock: "latest", - }) - .then((logs) => { - const newLogs = logs.flatMap((log) => log.args as VetoCastEvent); - if (newLogs.length > proposalLogs.length) setLogs(newLogs); - }); - }, [proposalId, publicClient?.chain.id]); - - return proposalLogs; -} diff --git a/plugins/optimistic-proposals/hooks/useToken.ts b/plugins/optimistic-proposals/hooks/useToken.ts deleted file mode 100644 index dd4f6dc..0000000 --- a/plugins/optimistic-proposals/hooks/useToken.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { erc20Abi } from "viem"; -import { useReadContract } from "wagmi"; -import { PUB_TOKEN_ADDRESS } from "@/constants"; - -export function useToken() { - const { - data: tokenSupply, - isError: isError1, - isLoading: isLoading1, - } = useReadContract({ - address: PUB_TOKEN_ADDRESS, - abi: erc20Abi, - functionName: "totalSupply", - }); - - const { - data: tokenSymbol, - isError: isError2, - isLoading: isLoading2, - } = useReadContract({ - address: PUB_TOKEN_ADDRESS, - abi: erc20Abi, - functionName: "symbol", - }); - - return { - address: PUB_TOKEN_ADDRESS, - tokenSupply, - symbol: tokenSymbol, - status: { - isLoading: isLoading1 || isLoading2, - isError: isError1 || isError2, - }, - }; -} diff --git a/plugins/optimistic-proposals/hooks/useTokenPastVotes.ts b/plugins/optimistic-proposals/hooks/useTokenPastVotes.ts deleted file mode 100644 index c2a5f78..0000000 --- a/plugins/optimistic-proposals/hooks/useTokenPastVotes.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { useConfig } from "wagmi"; -import { PUB_TOKEN_ADDRESS } from "@/constants"; -import { Erc20VotesAbi } from "../artifacts/ERC20Votes"; -import { Address } from "viem"; -import { useQuery } from "@tanstack/react-query"; -import { readContract } from "@wagmi/core"; - -export function useTokenPastVotes(holderAddress?: Address, timestamp?: bigint) { - const config = useConfig(); - const { - data: votes, - isLoading, - isError, - } = useQuery({ - queryKey: ["get-past-votes", PUB_TOKEN_ADDRESS, holderAddress, timestamp?.toString()], - queryFn: () => { - return readContract(config, { - abi: Erc20VotesAbi, - address: PUB_TOKEN_ADDRESS, - functionName: "getPastVotes", - args: [holderAddress!, timestamp!], - }); - }, - retry: true, - refetchOnMount: false, - refetchOnReconnect: false, - retryOnMount: true, - enabled: !!holderAddress && !!timestamp, - staleTime: 1000 * 60 * 60 * 24, - }); - - return { - votes: votes || BigInt("0"), - status: { - isLoading: isLoading, - isError: isError, - }, - }; -} diff --git a/plugins/optimistic-proposals/hooks/useUserCanVeto.ts b/plugins/optimistic-proposals/hooks/useUserCanVeto.ts deleted file mode 100644 index 573fac4..0000000 --- a/plugins/optimistic-proposals/hooks/useUserCanVeto.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { useAccount, useBlockNumber, useReadContract } from "wagmi"; -import { OptimisticTokenVotingPluginAbi } from "@/plugins/optimistic-proposals/artifacts/OptimisticTokenVotingPlugin.sol"; -import { useEffect } from "react"; -import { PUB_CHAIN, PUB_DUAL_GOVERNANCE_PLUGIN_ADDRESS } from "@/constants"; - -export function useUserCanVeto(proposalId?: bigint) { - const { address } = useAccount(); - const { data: blockNumber } = useBlockNumber({ watch: true }); - - const { data: canVeto, refetch } = useReadContract({ - chainId: PUB_CHAIN.id, - address: PUB_DUAL_GOVERNANCE_PLUGIN_ADDRESS, - abi: OptimisticTokenVotingPluginAbi, - functionName: "canVeto", - args: [proposalId ?? BigInt(0), address!], - query: { - enabled: !!address, - }, - }); - - useEffect(() => { - if (Number(blockNumber) % 2 === 0) { - refetch(); - } - }, [blockNumber]); - - return { canVeto, refetch }; -} diff --git a/plugins/optimistic-proposals/index.tsx b/plugins/optimistic-proposals/index.tsx deleted file mode 100644 index e4c473e..0000000 --- a/plugins/optimistic-proposals/index.tsx +++ /dev/null @@ -1,20 +0,0 @@ -import { NotFound } from "@/components/not-found"; -import ProposalList from "./pages/proposal-list"; -import ProposalDetail from "./pages/proposal"; -import { useUrl } from "@/hooks/useUrl"; - -export default function PluginPage() { - // Select the inner pages to display depending on the URL hash - const { hash } = useUrl(); - - if (!hash || hash === "#/") return ; - else if (hash.startsWith("#/proposals/")) { - const index = parseInt(hash.replace("#/proposals/", "")); - if (isNaN(index)) return ; - - return ; - } - - // Default not found page - return ; -} diff --git a/plugins/optimistic-proposals/pages/proposal-list.tsx b/plugins/optimistic-proposals/pages/proposal-list.tsx deleted file mode 100644 index 616ff4b..0000000 --- a/plugins/optimistic-proposals/pages/proposal-list.tsx +++ /dev/null @@ -1,136 +0,0 @@ -import { useAccount, useBlockNumber, useReadContract } from "wagmi"; -import { useEffect } from "react"; -import ProposalCard from "../components/proposal"; -import { AlertCard, DataList, Link, ProposalDataListItemSkeleton, type DataListState } from "@aragon/ods"; -import { Else, ElseIf, If, Then } from "@/components/if"; -import { PUB_DUAL_GOVERNANCE_PLUGIN_ADDRESS, PUB_CHAIN } from "@/constants"; -import { MyOptimisticTokenVotingPluginAbi } from "../artifacts/MyOptimisticTokenVotingPlugin.sol"; -import { MainSection } from "@/components/layout/main-section"; -import { MissingContentView } from "@/components/MissingContentView"; -import { ADDRESS_ZERO } from "@/utils/evm"; -import { AddressText } from "@/components/text/address"; -import { type Address } from "viem"; - -const DEFAULT_PAGE_SIZE = 6; - -export default function Proposals() { - const { address } = useAccount(); - const { data: blockNumber } = useBlockNumber({ watch: true }); - const balance = 0; - const delegatesTo = "0x0" as Address; - - const { - data: proposalCountResponse, - error: isError, - isLoading, - isFetching: isFetchingNextPage, - refetch, - } = useReadContract({ - address: PUB_DUAL_GOVERNANCE_PLUGIN_ADDRESS, - abi: MyOptimisticTokenVotingPluginAbi, - functionName: "proposalCount", - chainId: PUB_CHAIN.id, - }); - const proposalCount = Number(proposalCountResponse); - - useEffect(() => { - refetch(); - }, [blockNumber]); - - const entityLabel = proposalCount === 1 ? "Proposal" : "Proposals"; - - let dataListState: DataListState = "idle"; - if (isLoading && !proposalCount) { - dataListState = "initialLoading"; - } else if (isError) { - dataListState = "error"; - } else if (isFetchingNextPage) { - dataListState = "fetchingNextPage"; - } - - const hasBalance = !!balance && balance > BigInt(0); - const delegatingToSomeoneElse = !!delegatesTo && delegatesTo !== address && delegatesTo !== ADDRESS_ZERO; - const delegatedToZero = !!delegatesTo && delegatesTo === ADDRESS_ZERO; - - return ( - -
-

- Proposals -

-
- - - - - - - - {Array.from(Array(proposalCount || 0)?.keys()) - .reverse() - ?.map((proposalIndex) => )} - - - - - - - No proposals have been created yet. -
- Here you will see the list of proposals initiated by the Security Council. -
-
-
-
- ); -} - -const NoVetoPowerWarning = ({ - delegatingToSomeoneElse, - delegatesTo, - delegatedToZero, - address, -}: { - delegatingToSomeoneElse: boolean; - delegatesTo: Address | undefined; - delegatedToZero: boolean; - address: Address | undefined; -}) => { - return ( - - - - You are currently delegating your voting power to {delegatesTo}. - If you wish to participate by yourself in future proposals, - - - You have not self delegated your voting power to participate in the DAO. If you wish to participate in - future proposals, - - -  make sure that{" "} - - your voting power is self delegated - - . - - } - message={ - delegatingToSomeoneElse ? "Your voting power is currently delegated" : "You cannot veto on new proposals" - } - variant="info" - /> - ); -}; diff --git a/plugins/optimistic-proposals/pages/proposal.tsx b/plugins/optimistic-proposals/pages/proposal.tsx deleted file mode 100644 index 7c2e3a0..0000000 --- a/plugins/optimistic-proposals/pages/proposal.tsx +++ /dev/null @@ -1,210 +0,0 @@ -import type { useProposal } from "@/plugins/optimistic-proposals/hooks/useProposal"; -import ProposalHeader from "@/plugins/optimistic-proposals/components/proposal/header"; -import { PleaseWaitSpinner } from "@/components/please-wait"; -import { useProposalVeto } from "@/plugins/optimistic-proposals/hooks/useProposalVeto"; -import { useProposalExecute } from "@/plugins/optimistic-proposals/hooks/useProposalExecute"; -import { BodySection } from "@/components/proposal/proposalBodySection"; -import { type IBreakdownMajorityVotingResult, ProposalVoting } from "@/components/proposalVoting"; -import type { ITransformedStage, IVote } from "@/utils/types"; -import { ProposalStages } from "@/utils/types"; -import { useProposalStatus } from "../hooks/useProposalVariantStatus"; -import dayjs from "dayjs"; -import { ProposalActions } from "@/components/proposalActions/proposalActions"; -import { CardResources } from "@/components/proposal/cardResources"; -import { type Address, formatEther } from "viem"; -import { useToken } from "../hooks/useToken"; -import { usePastSupply } from "../hooks/usePastSupply"; -import { ElseIf, If, Then } from "@/components/if"; -import { AlertCard, ProposalStatus } from "@aragon/ods"; -import { PUB_TOKEN_SYMBOL } from "@/constants"; -import { useAccount } from "wagmi"; -import { ADDRESS_ZERO } from "@/utils/evm"; -import { AddressText } from "@/components/text/address"; -import Link from "next/link"; - -const ZERO = BigInt(0); - -export default function ProposalDetail({ index: proposalIdx }: { index: number }) { - const { address } = useAccount(); - const { - proposal, - proposalFetchStatus, - canVeto, - vetoes, - isConfirming: isConfirmingVeto, - vetoProposal, - } = useProposalVeto(proposalIdx); - const pastSupply = usePastSupply(proposal); - const { symbol: tokenSymbol } = useToken(); - const balance = 0; - const delegatesTo = "0x0" as Address; - - const { executeProposal, canExecute, isConfirming: isConfirmingExecution } = useProposalExecute(proposalIdx); - - const startDate = dayjs(Number(proposal?.parameters.vetoStartDate) * 1000).toString(); - const endDate = dayjs(Number(proposal?.parameters.vetoEndDate) * 1000).toString(); - - const showProposalLoading = getShowProposalLoading(proposal, proposalFetchStatus); - const proposalStatus = useProposalStatus(proposal!); - let vetoPercentage = 0; - if (proposal?.vetoTally && pastSupply && proposal.parameters.minVetoRatio) { - vetoPercentage = Number( - (BigInt(1000) * proposal.vetoTally) / ((pastSupply * BigInt(proposal.parameters.minVetoRatio)) / BigInt(10000000)) - ); - } - - let cta: IBreakdownMajorityVotingResult["cta"]; - if (proposal?.executed) { - cta = { - disabled: true, - label: "Executed", - }; - } else if (proposalStatus === ProposalStatus.ACCEPTED) { - cta = { - disabled: !canExecute || !proposal?.actions.length, - isLoading: isConfirmingExecution, - label: proposal?.actions.length ? "Execute" : "No actions to execute", - onClick: executeProposal, - }; - } else if (proposalStatus === ProposalStatus.ACTIVE) { - cta = { - disabled: !canVeto, - isLoading: isConfirmingVeto, - label: "Veto", - onClick: vetoProposal, - }; - } - - const proposalStage: ITransformedStage[] = [ - { - id: "1", - type: ProposalStages.OPTIMISTIC_EXECUTION, - variant: "majorityVoting", - title: "Optimistic voting", - status: proposalStatus!, - disabled: false, - proposalId: proposalIdx.toString(), - providerId: "1", - result: { - cta, - votingScores: [ - { - option: "Veto", - voteAmount: formatEther(proposal?.vetoTally || BigInt(0)), - votePercentage: vetoPercentage, - tokenSymbol: tokenSymbol || PUB_TOKEN_SYMBOL, - }, - ], - proposalId: proposalIdx.toString(), - }, - details: { - censusTimestamp: Number(proposal?.parameters.snapshotTimestamp || 0) || 0, - startDate, - endDate, - strategy: "Optimistic voting", - options: "Veto", - }, - votes: vetoes.map(({ voter }) => ({ address: voter, variant: "no" }) as IVote), - }, - ]; - - const hasBalance = !!balance && balance > ZERO; - const delegatingToSomeoneElse = !!delegatesTo && delegatesTo !== address && delegatesTo !== ADDRESS_ZERO; - const delegatedToZero = !!delegatesTo && delegatesTo === ADDRESS_ZERO; - - if (!proposal || showProposalLoading) { - return ( -
- -
- ); - } - - return ( -
- - -
-
-
- - - - - - -
-
- -
-
-
-
- ); -} - -const NoVetoPowerWarning = ({ - delegatingToSomeoneElse, - delegatesTo, - delegatedToZero, - address, - canVeto, -}: { - delegatingToSomeoneElse: boolean; - delegatesTo: Address | undefined; - delegatedToZero: boolean; - address: Address | undefined; - canVeto: boolean; -}) => { - return ( - - - - You are currently delegating your voting power to {delegatesTo}. - If you wish to participate by yourself in future proposals, - - - You have not self delegated your voting power to participate in the DAO. If you wish to participate in - future proposals, - - -  make sure that{" "} - - your voting power is self delegated - - . - - } - message={ - delegatingToSomeoneElse - ? "Your voting power is currently delegated" - : canVeto - ? "You cannot veto on new proposals" - : "You cannot veto" - } - variant="info" - /> - ); -}; - -function getShowProposalLoading( - proposal: ReturnType["proposal"], - status: ReturnType["status"] -) { - if (!proposal && status.proposalLoading) return true; - else if (status.metadataLoading && !status.metadataError) return true; - else if (!proposal?.title && !status.metadataError) return true; - - return false; -} diff --git a/plugins/optimistic-proposals/utils/proposal-id.ts b/plugins/optimistic-proposals/utils/proposal-id.ts deleted file mode 100644 index c7ab4f2..0000000 --- a/plugins/optimistic-proposals/utils/proposal-id.ts +++ /dev/null @@ -1,8 +0,0 @@ -export function parseProposalId(proposalId: bigint) { - const mask64Bit = BigInt("0xffffffffffffffff"); - const index = Number(proposalId & mask64Bit); - const startDate = Number((proposalId >> BigInt(128)) & mask64Bit); - const endDate = Number((proposalId >> BigInt(64)) & mask64Bit); - - return { index, startDate, endDate }; -} diff --git a/plugins/optimistic-proposals/utils/types.tsx b/plugins/optimistic-proposals/utils/types.tsx deleted file mode 100644 index 2e3d40a..0000000 --- a/plugins/optimistic-proposals/utils/types.tsx +++ /dev/null @@ -1,49 +0,0 @@ -import type { Address, Hex } from "viem"; -import type { IProposalResource, RawAction } from "@/utils/types"; - -export type ProposalInputs = { - proposalId: bigint; -}; - -export type OptimisticProposalResultType = readonly [ - boolean, - boolean, - OptimisticProposalParameters, - bigint, - Hex, - readonly RawAction[], - bigint, -]; - -export type OptimisticProposalParameters = { - snapshotTimestamp: bigint; - vetoStartDate?: number | bigint; - vetoEndDate: number | bigint; - minVetoRatio: number; - skipL2: boolean; -}; - -export type OptimisticProposal = { - index: number; - active: boolean; - executed: boolean; - parameters: OptimisticProposalParameters; - vetoTally: bigint; - actions: RawAction[]; - allowFailureMap: bigint; - creator: string; - title: string; - summary: string; - description: string; - resources: IProposalResource[]; -}; - -export type VoteCastResponse = { - args: VetoCastEvent[]; -}; - -export type VetoCastEvent = { - voter: Address; - proposalId: bigint; - votingPower: bigint; -}; diff --git a/scripts/example.ts b/scripts/example.ts deleted file mode 100644 index 1d28a42..0000000 --- a/scripts/example.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { toHex } from "viem"; -import { deploymentPublicClient as publicClient, deploymentWalletClient as walletClient } from "./lib/util/client"; -import { deploymentAccount as account } from "./lib/util/account"; - -async function main() { - console.log("Emitting delegation event"); - const message = "ipfs://..."; - - const { request } = await publicClient.simulateContract({ - address: "0xa119833aba78d4639c6ce6c2fe3ca4c7de02d710", - abi: {} as any, // TODO: reference ABI here - functionName: "register", - args: [toHex(message)], - account, - }); - const hash = await walletClient.writeContract(request); - - console.log(` - Waiting for transaction (${hash})`); - - const receipt = await publicClient.waitForTransactionReceipt({ hash }); - if (!receipt) { - throw new Error("The Dual Governance plugin repository could not be created"); - } - - console.log("Done"); -} - -main();