Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: multichoice #636

Open
wants to merge 7 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -91,5 +91,5 @@ jobs:
working-directory: ./starknet
run: scarb test --verbose

- name: run Hardhat tests
- name: Run Hardhat tests
run: yarn test-ts
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ typechain-types/
build/
cache/
out/
cache_forge/

!/broadcast
/broadcast/*/31337/
Expand Down
28 changes: 15 additions & 13 deletions ethereum/src/execution-strategies/L1AvatarExecutionStrategy.sol
Original file line number Diff line number Diff line change
Expand Up @@ -101,15 +101,14 @@ contract L1AvatarExecutionStrategy is SimpleQuorumExecutionStrategy {
uint256 space,
uint256 proposalId,
Proposal memory proposal,
Votes memory votes,
uint256[] memory votes,
uint256 executionHash,
MetaTransaction[] memory transactions
) external onlySpace(space) {
// Call to the Starknet core contract will fail if finalized proposal message was not received on L1.
_receiveProposal(space, proposalId, proposal, votes, executionHash);

ProposalStatus proposalStatus =
getProposalStatus(proposal, votes.votesFor, votes.votesAgainst, votes.votesAbstain);
ProposalStatus proposalStatus = getProposalStatus(proposal, votes[1], votes[0], votes[2]);
if ((proposalStatus != ProposalStatus.Accepted) && (proposalStatus != ProposalStatus.VotingPeriodAccepted)) {
revert InvalidProposalStatus(proposalStatus);
}
Expand All @@ -120,16 +119,17 @@ contract L1AvatarExecutionStrategy is SimpleQuorumExecutionStrategy {
emit ProposalExecuted(space, proposalId);
}

/// @dev Reverts if the expected message was not received from L2.
/// @dev Reverts if the expected message was not received from L2.
function _receiveProposal(
uint256 space,
uint256 proposalId,
Proposal memory proposal,
Votes memory votes,
uint256[] memory votes,
uint256 executionHash
) internal {
// The Cairo serialization of the payload sent from L2
uint256[] memory payload = new uint256[](21);
uint256[] memory payload = new uint256[](22);
payload[0] = space;
payload[1] = proposalId & (2 ** 128 - 1);
payload[2] = proposalId >> 128;
Expand All @@ -144,17 +144,19 @@ contract L1AvatarExecutionStrategy is SimpleQuorumExecutionStrategy {
payload[11] = proposal.activeVotingStrategies & (2 ** 128 - 1);
payload[12] = proposal.activeVotingStrategies >> 128;

payload[13] = votes.votesFor & (2 ** 128 - 1);
payload[14] = votes.votesFor >> 128;
payload[13] = votes.length;

payload[14] = votes[0] & (2 ** 128 - 1);
payload[15] = votes[0] >> 128;

payload[15] = votes.votesAgainst & (2 ** 128 - 1);
payload[16] = votes.votesAgainst >> 128;
payload[16] = votes[1] & (2 ** 128 - 1);
payload[17] = votes[1] >> 128;

payload[17] = votes.votesAbstain & (2 ** 128 - 1);
payload[18] = votes.votesAbstain >> 128;
payload[18] = votes[2] & (2 ** 128 - 1);
payload[19] = votes[2] >> 128;

payload[19] = executionHash & (2 ** 128 - 1);
payload[20] = executionHash >> 128;
payload[20] = executionHash & (2 ** 128 - 1);
payload[21] = executionHash >> 128;

// If proposal execution message did not exist/not received yet, then this will revert.
IStarknetCore(starknetCore).consumeMessageFromL2(executionRelayer, payload);
Expand Down
27 changes: 14 additions & 13 deletions ethereum/src/mocks/L1AvatarExecutionStrategyMockMessaging.sol
Original file line number Diff line number Diff line change
Expand Up @@ -100,15 +100,14 @@ contract L1AvatarExecutionStrategyMockMessaging is SimpleQuorumExecutionStrategy
uint256 space,
uint256 proposalId,
Proposal memory proposal,
Votes memory votes,
uint256[] memory votes,
uint256 executionHash,
MetaTransaction[] memory transactions
) external onlySpace(space) {
// Call to the Starknet core contract will fail if finalized proposal message was not received on L1.
_receiveProposal(space, proposalId, proposal, votes, executionHash);

ProposalStatus proposalStatus =
getProposalStatus(proposal, votes.votesFor, votes.votesAgainst, votes.votesAbstain);
ProposalStatus proposalStatus = getProposalStatus(proposal, votes[1], votes[0], votes[2]);
if ((proposalStatus != ProposalStatus.Accepted) && (proposalStatus != ProposalStatus.VotingPeriodAccepted)) {
revert InvalidProposalStatus(proposalStatus);
}
Expand All @@ -124,11 +123,11 @@ contract L1AvatarExecutionStrategyMockMessaging is SimpleQuorumExecutionStrategy
uint256 space,
uint256 proposalId,
Proposal memory proposal,
Votes memory votes,
uint256[] memory votes,
uint256 executionHash
) internal {
// The Cairo serialization of the payload sent from L2
uint256[] memory payload = new uint256[](21);
uint256[] memory payload = new uint256[](22);
payload[0] = space;
payload[1] = proposalId & (2 ** 128 - 1);
payload[2] = proposalId >> 128;
Expand All @@ -143,17 +142,19 @@ contract L1AvatarExecutionStrategyMockMessaging is SimpleQuorumExecutionStrategy
payload[11] = proposal.activeVotingStrategies & (2 ** 128 - 1);
payload[12] = proposal.activeVotingStrategies >> 128;

payload[13] = votes.votesFor & (2 ** 128 - 1);
payload[14] = votes.votesFor >> 128;
payload[13] = 3;

payload[15] = votes.votesAgainst & (2 ** 128 - 1);
payload[16] = votes.votesAgainst >> 128;
payload[14] = votes[0] & (2 ** 128 - 1);
payload[15] = votes[0] >> 128;

payload[17] = votes.votesAbstain & (2 ** 128 - 1);
payload[18] = votes.votesAbstain >> 128;
payload[16] = votes[1] & (2 ** 128 - 1);
payload[17] = votes[1] >> 128;

payload[19] = executionHash & (2 ** 128 - 1);
payload[20] = executionHash >> 128;
payload[18] = votes[2] & (2 ** 128 - 1);
payload[19] = votes[2] >> 128;

payload[20] = executionHash & (2 ** 128 - 1);
payload[21] = executionHash >> 128;

// If proposal execution message did not exist/not received yet, then this will revert.
MockStarknetMessaging(starknetCore).consumeMessageFromL2(executionRelayer, payload);
Expand Down
1 change: 0 additions & 1 deletion hardhat.config.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import dotenv from 'dotenv';
dotenv.config();
import { task } from 'hardhat/config';
import { HardhatUserConfig } from 'hardhat/types';
import 'starknet';
import '@nomicfoundation/hardhat-toolbox';
Expand Down
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
"@gnosis.pm/zodiac": "^4.0.3",
"@nomicfoundation/hardhat-chai-matchers": "^2.0.0",
"@nomicfoundation/hardhat-ethers": "^3.0.6",
"@nomicfoundation/hardhat-foundry": "^1.1.1",
"@nomicfoundation/hardhat-foundry": "^1.1.3",
"@nomicfoundation/hardhat-ignition": "^0.15.5",
"@nomicfoundation/hardhat-ignition-ethers": "^0.15.5",
"@nomicfoundation/hardhat-network-helpers": "^1.0.11",
Expand All @@ -45,7 +45,7 @@
"eslint-plugin-prettier": "^5.0.0",
"ethers": "^6.13.2",
"fs": "^0.0.1-security",
"hardhat": "^2.17.2",
"hardhat": "^2.22.16",
"hardhat-gas-reporter": "^1.0.8",
"json-format-cli": "^1.1.1",
"micro-starknet": "^0.2.3",
Expand All @@ -60,4 +60,4 @@
"dependencies": {
"starknet-devnet": "^0.1.2"
}
}
}
46 changes: 17 additions & 29 deletions scripts/deploy-space.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,6 @@
import dotenv from 'dotenv';
import fs from 'fs';
import {
defaultProvider,
Provider,
RpcProvider,
Account,
ec,
json,
CallData,
constants,
shortString,
cairo,
} from 'starknet';
import { RpcProvider, Account, json, CallData, cairo } from 'starknet';

dotenv.config();

Expand All @@ -24,12 +13,12 @@ async function main() {
const account = new Account(provider, accountAddress, accountPk);

// OZ Votes token 18 decimals
const l1TokenAddress = '0xd96844c9B21CB6cCf2c236257c7fc703E43BA071';
const l1TokenAddress = '0xd96844c9B21CB6cCf2c236257c7fc703E43BA071';

// Slot index of the checkpoints mapping in the token contract,
// obtained using Foundry's Cast Storage Layout tool.
const slotIndex = cairo.uint256(8);

// Slot index of the checkpoints mapping in the token contract,
// obtained using Foundry's Cast Storage Layout tool.
const slotIndex = cairo.uint256(8);

const factsRegistryAddress = '0x01b2111317EB693c3EE46633edd45A4876db14A3a53ACDBf4E5166976d8e869d';
const timestampsRemapperAddress =
'0x2ee57d848297bc7dfc8675111b9aa3bd3085e4038e475250770afe303b772af';
Expand Down Expand Up @@ -57,18 +46,17 @@ async function main() {
const vanillaProposalValidationStrategyAddress =
'0x2247f5d86a60833da9dd8224d8f35c60bde7f4ca3b2a6583d4918d48750f69';

// const deployResponse = await account.declareAndDeploy({
// contract: evmSlotValueVotingStrategySierra,
// casm: evmSlotValueVotingStrategyCasm,
// constructorCalldata: CallData.compile({
// timestamp_remappers: timestampsRemapperAddress,
// facts_registry: factsRegistryAddress,
// }),
// });
// const evmSlotValueVotingStrategyAddress = deployResponse.deploy.contract_address;
const deployResponse = await account.declareAndDeploy({
contract: evmSlotValueVotingStrategySierra,
casm: evmSlotValueVotingStrategyCasm,
constructorCalldata: CallData.compile({
timestamp_remappers: timestampsRemapperAddress,
facts_registry: factsRegistryAddress,
}),
});
const evmSlotValueVotingStrategyAddress = deployResponse.deploy.contract_address;

const evmSlotValueVotingStrategyAddress =
'0x474edaba6e88a1478d0680bb97f43f01e6a311593ddc496da58d5a7e7a647cf';
// const evmSlotValueVotingStrategyAddress = '0x474edaba6e88a1478d0680bb97f43f01e6a311593ddc496da58d5a7e7a647cf';
console.log('Voting Strategy Address: ', evmSlotValueVotingStrategyAddress);

const spaceDeployResponse = await account.declareAndDeploy({
Expand All @@ -80,7 +68,7 @@ async function main() {
console.log('Space Address: ', spaceAddress);

// initialize space
const result = await account.execute({
await account.execute({
contractAddress: spaceAddress,
entrypoint: 'initialize',
calldata: CallData.compile({
Expand Down
3 changes: 2 additions & 1 deletion scripts/herodotus-interaction-demo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import {
CairoOptionVariant,
} from 'starknet';
import { utils } from '@snapshot-labs/sx';
import { check } from 'prettier';

dotenv.config();

Expand All @@ -26,6 +25,7 @@ const accountPk = process.env.PK || '';
const starknetNetworkUrl = process.env.STARKNET_NETWORK_URL || '';
const ethNetworkUrl = process.env.ETH_NETWORK_URL || '';
const herodotusApiKey = process.env.HERODOTUS_API_KEY || '';
const choices = '0x3';

async function main() {
const provider = new RpcProvider({ nodeUrl: starknetNetworkUrl });
Expand Down Expand Up @@ -88,6 +88,7 @@ async function main() {
selector: '0x1bfd596ae442867ef71ca523061610682af8b00fc2738329422f4ad8d220b81',
data: CallData.compile({
author: utils.starknetEnums.getUserAddressEnum('ETHEREUM', voterAddress),
choices: choices,
metadataUri: ['0x1', '0x2', '0x3', '0x4'],
executionStrategy: {
address: '0x0000000000000000000000000000000000005678',
Expand Down
31 changes: 25 additions & 6 deletions starknet/src/authenticators/eth_sig.cairo
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use starknet::{ContractAddress, EthAddress};
use sx::types::{Strategy, IndexedStrategy, Choice};
use sx::types::{Strategy, IndexedStrategy};

#[starknet::interface]
trait IEthSigAuthenticator<TContractState> {
Expand All @@ -23,6 +23,7 @@ trait IEthSigAuthenticator<TContractState> {
v: u32,
space: ContractAddress,
author: EthAddress,
choices: u128,
metadata_uri: Array<felt252>,
execution_strategy: Strategy,
user_proposal_validation_params: Array<felt252>,
Expand Down Expand Up @@ -51,7 +52,7 @@ trait IEthSigAuthenticator<TContractState> {
space: ContractAddress,
voter: EthAddress,
proposal_id: u256,
choice: Choice,
choice: u128,
user_voting_strategies: Array<IndexedStrategy>,
metadata_uri: Array<felt252>,
);
Expand All @@ -77,6 +78,7 @@ trait IEthSigAuthenticator<TContractState> {
space: ContractAddress,
author: EthAddress,
proposal_id: u256,
choices: u128,
execution_strategy: Strategy,
metadata_uri: Array<felt252>,
salt: u256
Expand All @@ -88,7 +90,7 @@ mod EthSigAuthenticator {
use super::IEthSigAuthenticator;
use starknet::{ContractAddress, EthAddress};
use sx::interfaces::{ISpaceDispatcher, ISpaceDispatcherTrait};
use sx::types::{Strategy, IndexedStrategy, Choice, UserAddress};
use sx::types::{Strategy, IndexedStrategy, UserAddress};
use sx::utils::{eip712, LegacyHashEthAddress, ByteReverse};

#[storage]
Expand All @@ -105,6 +107,7 @@ mod EthSigAuthenticator {
v: u32,
space: ContractAddress,
author: EthAddress,
choices: u128,
metadata_uri: Array<felt252>,
execution_strategy: Strategy,
user_proposal_validation_params: Array<felt252>,
Expand All @@ -118,6 +121,7 @@ mod EthSigAuthenticator {
v,
space,
author,
choices,
metadata_uri.span(),
@execution_strategy,
user_proposal_validation_params.span(),
Expand All @@ -127,6 +131,7 @@ mod EthSigAuthenticator {
ISpaceDispatcher { contract_address: space }
.propose(
UserAddress::Ethereum(author),
choices,
metadata_uri,
execution_strategy,
user_proposal_validation_params,
Expand All @@ -141,7 +146,7 @@ mod EthSigAuthenticator {
space: ContractAddress,
voter: EthAddress,
proposal_id: u256,
choice: Choice,
choice: u128,
user_voting_strategies: Array<IndexedStrategy>,
metadata_uri: Array<felt252>,
) {
Expand Down Expand Up @@ -177,19 +182,33 @@ mod EthSigAuthenticator {
space: ContractAddress,
author: EthAddress,
proposal_id: u256,
choices: u128,
execution_strategy: Strategy,
metadata_uri: Array<felt252>,
salt: u256
) {
assert(!self._used_salts.read((author, salt)), 'Salt Already Used');

eip712::verify_update_proposal_sig(
r, s, v, space, author, proposal_id, @execution_strategy, metadata_uri.span(), salt
r,
s,
v,
space,
author,
proposal_id,
choices,
@execution_strategy,
metadata_uri.span(),
salt
);
self._used_salts.write((author, salt), true);
ISpaceDispatcher { contract_address: space }
.update_proposal(
UserAddress::Ethereum(author), proposal_id, execution_strategy, metadata_uri
UserAddress::Ethereum(author),
proposal_id,
choices,
execution_strategy,
metadata_uri
);
}
}
Expand Down
Loading
Loading