Skip to content

Commit

Permalink
refactor: add proposalId to proposalCreated event; remove Salt in Met…
Browse files Browse the repository at this point in the history
…aTransaction
  • Loading branch information
pscott committed Jun 6, 2024
1 parent f3964bf commit c4781c8
Show file tree
Hide file tree
Showing 6 changed files with 156 additions and 189 deletions.
72 changes: 36 additions & 36 deletions ethereum/src/execution-strategies/L1AvatarExecutionStrategy.sol
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ contract L1AvatarExecutionStrategy is SimpleQuorumExecutionStrategy {
event ExecutionRelayerSet(uint256 indexed newExecutionRelayer);

/// @dev Emitted each time a proposal is executed.
event ProposalExecuted(uint256 indexed space, bytes32 executionHash);
event ProposalExecuted(uint256 indexed space, uint256 proposalId);

/// @notice Emitted when a new Avatar Execution Strategy is initialized.
/// @param _owner Address of the owner of the strategy.
Expand Down Expand Up @@ -93,69 +93,69 @@ contract L1AvatarExecutionStrategy is SimpleQuorumExecutionStrategy {

/// @notice Executes a proposal
/// @param space The address of the space that the proposal was created in.
/// @param proposalId The ID of the proposal (on Starknet).
/// @param proposal The proposal struct.
/// @param votesFor The number of votes for the proposal.
/// @param votesAgainst The number of votes against the proposal.
/// @param votesAbstain The number of votes abstaining from the proposal.
/// @param votes Struct that hold the voting power of for, against and abstain choices.
/// @param executionHash The hash of the proposal transactions.
/// @param transactions The proposal transactions to be executed.
function execute(
uint256 space,
uint256 proposalId,
Proposal memory proposal,
uint256 votesFor,
uint256 votesAgainst,
uint256 votesAbstain,
Votes 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, proposal, votesFor, votesAgainst, votesAbstain, executionHash);
_receiveProposal(space, proposalId, proposal, votes, executionHash);

ProposalStatus proposalStatus = getProposalStatus(proposal, votesFor, votesAgainst, votesAbstain);
ProposalStatus proposalStatus =
getProposalStatus(proposal, votes.votesFor, votes.votesAgainst, votes.votesAbstain);
if ((proposalStatus != ProposalStatus.Accepted) && (proposalStatus != ProposalStatus.VotingPeriodAccepted)) {
revert InvalidProposalStatus(proposalStatus);
}

if (bytes32(executionHash) != keccak256(abi.encode(transactions))) revert InvalidPayload();

_execute(transactions);
emit ProposalExecuted(space, bytes32(executionHash));
emit ProposalExecuted(space, proposalId);
}

/// @dev Reverts if the expected message was not received from L2.
function _receiveProposal(
uint256 space,
uint256 proposalId,
Proposal memory proposal,
uint256 votesFor,
uint256 votesAgainst,
uint256 votesAbstain,
Votes memory votes,
uint256 executionHash
) internal {
// The Cairo serialization of the payload sent from L2
uint256[] memory payload = new uint256[](19);
uint256[] memory payload = new uint256[](21);
payload[0] = space;
payload[1] = uint256(proposal.startTimestamp);
payload[2] = uint256(proposal.minEndTimestamp);
payload[3] = uint256(proposal.maxEndTimestamp);
payload[4] = uint256(proposal.finalizationStatus);
payload[5] = proposal.executionPayloadHash;
payload[6] = proposal.executionStrategy;
payload[7] = proposal.authorAddressType;
payload[8] = proposal.author;
payload[9] = proposal.activeVotingStrategies & (2 ** 128 - 1);
payload[10] = proposal.activeVotingStrategies >> 128;

payload[11] = votesFor & (2 ** 128 - 1);
payload[12] = votesFor >> 128;

payload[13] = votesAgainst & (2 ** 128 - 1);
payload[14] = votesAgainst >> 128;

payload[15] = votesAbstain & (2 ** 128 - 1);
payload[16] = votesAbstain >> 128;

payload[17] = executionHash & (2 ** 128 - 1);
payload[18] = executionHash >> 128;
payload[1] = proposalId & (2 ** 128 - 1);
payload[2] = proposalId >> 128;
payload[3] = uint256(proposal.startTimestamp);
payload[4] = uint256(proposal.minEndTimestamp);
payload[5] = uint256(proposal.maxEndTimestamp);
payload[6] = uint256(proposal.finalizationStatus);
payload[7] = proposal.executionPayloadHash;
payload[8] = proposal.executionStrategy;
payload[9] = proposal.authorAddressType;
payload[10] = proposal.author;
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[15] = votes.votesAgainst & (2 ** 128 - 1);
payload[16] = votes.votesAgainst >> 128;

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

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

// If proposal execution message did not exist/not received yet, then this will revert.
IStarknetCore(starknetCore).consumeMessageFromL2(executionRelayer, payload);
Expand Down
102 changes: 41 additions & 61 deletions ethereum/src/mocks/L1AvatarExecutionStrategyMockMessaging.sol
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ contract L1AvatarExecutionStrategyMockMessaging is SimpleQuorumExecutionStrategy
event ExecutionRelayerSet(uint256 indexed newExecutionRelayer);

/// @dev Emitted each time a proposal is executed.
event ProposalExecuted(uint256 indexed space, bytes32 executionHash);
event ProposalExecuted(uint256 indexed space, uint256 proposalId);

/// @notice Emitted when a new Avatar Execution Strategy is initialized.
/// @param _owner Address of the owner of the strategy.
Expand All @@ -48,37 +48,17 @@ contract L1AvatarExecutionStrategyMockMessaging is SimpleQuorumExecutionStrategy
uint256 _quorum
);

/// @notice Constructor
/// @param _owner Address of the owner of this contract.
/// @param _target Address of the avatar that this module will pass transactions to.
/// @param _starknetCore Address of the StarkNet Core contract.
/// @param _executionRelayer Address of the StarkNet contract that will send execution details to this contract in a L2 -> L1 message
/// @param _starknetSpaces Array of whitelisted space contracts.
/// @param _quorum The quorum required to execute a proposal.
constructor(
constructor() {}

/// @notice Initialization function, should be called immediately after deploying a new proxy to this contract.
function setUp(
address _owner,
address _target,
address _starknetCore,
uint256 _executionRelayer,
uint256[] memory _starknetSpaces,
uint256 _quorum
) {
bytes memory initParams =
abi.encode(_owner, _target, _starknetCore, _executionRelayer, _starknetSpaces, _quorum);
setUp(initParams);
}

/// @notice Initialization function, should be called immediately after deploying a new proxy to this contract.
/// @param initParams ABI encoded parameters, in the same order as the constructor.
function setUp(bytes memory initParams) public initializer {
(
address _owner,
address _target,
address _starknetCore,
uint256 _executionRelayer,
uint256[] memory _starknetSpaces,
uint256 _quorum
) = abi.decode(initParams, (address, address, address, uint256, uint256[], uint256));
) public initializer {
__Ownable_init();
transferOwnership(_owner);
__SpaceManager_init(_starknetSpaces);
Expand Down Expand Up @@ -112,69 +92,69 @@ contract L1AvatarExecutionStrategyMockMessaging is SimpleQuorumExecutionStrategy

/// @notice Executes a proposal
/// @param space The address of the space that the proposal was created in.
/// @param proposalId The ID of the proposal (on Starknet).
/// @param proposal The proposal struct.
/// @param votesFor The number of votes for the proposal.
/// @param votesAgainst The number of votes against the proposal.
/// @param votesAbstain The number of votes abstaining from the proposal.
/// @param votes Struct that hold the voting power of for, against and abstain choices.
/// @param executionHash The hash of the proposal transactions.
/// @param transactions The proposal transactions to be executed.
function execute(
uint256 space,
uint256 proposalId,
Proposal memory proposal,
uint256 votesFor,
uint256 votesAgainst,
uint256 votesAbstain,
Votes 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, proposal, votesFor, votesAgainst, votesAbstain, executionHash);
_receiveProposal(space, proposalId, proposal, votes, executionHash);

ProposalStatus proposalStatus = getProposalStatus(proposal, votesFor, votesAgainst, votesAbstain);
ProposalStatus proposalStatus =
getProposalStatus(proposal, votes.votesFor, votes.votesAgainst, votes.votesAbstain);
if ((proposalStatus != ProposalStatus.Accepted) && (proposalStatus != ProposalStatus.VotingPeriodAccepted)) {
revert InvalidProposalStatus(proposalStatus);
}

if (bytes32(executionHash) != keccak256(abi.encode(transactions))) revert InvalidPayload();

_execute(transactions);
emit ProposalExecuted(space, bytes32(executionHash));
emit ProposalExecuted(space, proposalId);
}

/// @dev Reverts if the expected message was not received from L2.
function _receiveProposal(
uint256 space,
uint256 proposalId,
Proposal memory proposal,
uint256 votesFor,
uint256 votesAgainst,
uint256 votesAbstain,
Votes memory votes,
uint256 executionHash
) internal {
// The Cairo serialization of the payload sent from L2
uint256[] memory payload = new uint256[](19);
uint256[] memory payload = new uint256[](21);
payload[0] = space;
payload[1] = uint256(proposal.startTimestamp);
payload[2] = uint256(proposal.minEndTimestamp);
payload[3] = uint256(proposal.maxEndTimestamp);
payload[4] = uint256(proposal.finalizationStatus);
payload[5] = proposal.executionPayloadHash;
payload[6] = proposal.executionStrategy;
payload[7] = proposal.authorAddressType;
payload[8] = proposal.author;
payload[9] = proposal.activeVotingStrategies & (2 ** 128 - 1);
payload[10] = proposal.activeVotingStrategies >> 128;

payload[11] = votesFor & (2 ** 128 - 1);
payload[12] = votesFor >> 128;

payload[13] = votesAgainst & (2 ** 128 - 1);
payload[14] = votesAgainst >> 128;

payload[15] = votesAbstain & (2 ** 128 - 1);
payload[16] = votesAbstain >> 128;

payload[17] = executionHash & (2 ** 128 - 1);
payload[18] = executionHash >> 128;
payload[1] = proposalId & (2 ** 128 - 1);
payload[2] = proposalId >> 128;
payload[3] = uint256(proposal.startTimestamp);
payload[4] = uint256(proposal.minEndTimestamp);
payload[5] = uint256(proposal.maxEndTimestamp);
payload[6] = uint256(proposal.finalizationStatus);
payload[7] = proposal.executionPayloadHash;
payload[8] = proposal.executionStrategy;
payload[9] = proposal.authorAddressType;
payload[10] = proposal.author;
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[15] = votes.votesAgainst & (2 ** 128 - 1);
payload[16] = votes.votesAgainst >> 128;

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

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

// If proposal execution message did not exist/not received yet, then this will revert.
MockStarknetMessaging(starknetCore).consumeMessageFromL2(executionRelayer, payload);
Expand Down
9 changes: 7 additions & 2 deletions ethereum/src/types.sol
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@ struct MetaTransaction {
uint256 value;
bytes data;
Enum.Operation operation;
// We use a salt so that the struct can always be unique and we can use its hash as a unique identifier.
uint256 salt;
}

/// @notice The set of possible finalization statuses for a proposal.
Expand All @@ -40,6 +38,13 @@ struct Proposal {
uint256 activeVotingStrategies;
}

/// @notice Struct to store the votes for a proposal. Used because of Solidity's stack limitations.
struct Votes {
uint256 votesFor;
uint256 votesAgainst;
uint256 votesAbstain;
}

/// @notice The set of possible statuses for a proposal.
enum ProposalStatus {
VotingDelay,
Expand Down
1 change: 1 addition & 0 deletions starknet/src/execution_strategies/eth_relayer.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ mod EthRelayerExecutionStrategy {
// Serialize the payload to be sent to the L1 execution strategy
let mut l1_payload = array![];
space.serialize(ref l1_payload);
proposal_id.serialize(ref l1_payload);
proposal.serialize(ref l1_payload);
votes_for.serialize(ref l1_payload);
votes_against.serialize(ref l1_payload);
Expand Down
Loading

0 comments on commit c4781c8

Please sign in to comment.