Skip to content

Commit

Permalink
Space factory (#197)
Browse files Browse the repository at this point in the history
* space factory base

* added space creation event

* updated cairo to 0.9

* added dynamic calldata construction

* added space deployment event

* updated starknet hardhat plugin

* space class hash

* space factory test

* added typechain-types to gitignore

* Delete typechain-types directory

* removed space creation event from space contract

* updated sx.js

* formatting

* event monitoring on Space Factory test

* merged starknet exec

* Switched to OZ account for 0.6 support

* fixed merge conflict

* updated blueprint

* Update SpaceFactory.cairo

* updated starknet packages

* added deploy_from_zero flag

* formatting

* fixed typo
  • Loading branch information
Orland0x authored Jul 25, 2022
1 parent 94c0e33 commit 08f0a5e
Show file tree
Hide file tree
Showing 9 changed files with 311 additions and 62 deletions.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@ contracts
│ │ ├─ Test_array2d.cairo
│ │ ├─ Test_words.cairo
│ │ └─ Test_words_to_uint256.cairo
│ └─ Space.cairo - "The core contract for Snapshot X"
│ ├─ Space.cairo - "The core contract for Snapshot X that handles the voting state for each space"
│ └─ SpaceFactory.cairo - "Handles the deployment and tracking of Space contracts"
└─ ethereum
├─ Interfaces
│ └─ IStarknetCore.sol — "Interface of the StarkNet core contract"
Expand Down
32 changes: 0 additions & 32 deletions contracts/starknet/Space.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -115,23 +115,6 @@ end
func vote_created(proposal_id : felt, voter_address : Address, vote : Vote):
end
@event
func space_created(
_voting_delay : felt,
_min_voting_duration : felt,
_max_voting_duration : felt,
_proposal_threshold : Uint256,
_controller : felt,
_quorum : Uint256,
_voting_strategies_len : felt,
_voting_strategies : felt*,
_authenticators_len : felt,
_authenticators : felt*,
_executors_len : felt,
_executors : felt*,
):
end
@event
func controller_updated(previous : felt, new_controller : felt):
end
Expand Down Expand Up @@ -237,21 +220,6 @@ func constructor{syscall_ptr : felt*, pedersen_ptr : HashBuiltin*, range_check_p
# The first proposal in a space will have a proposal ID of 1.
next_proposal_nonce_store.write(1)
space_created.emit(
_voting_delay,
_min_voting_duration,
_max_voting_duration,
_proposal_threshold,
_controller,
_quorum,
_voting_strategies_len,
_voting_strategies,
_authenticators_len,
_authenticators,
_executors_len,
_executors,
)
return ()
end
Expand Down
119 changes: 119 additions & 0 deletions contracts/starknet/SpaceFactory.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
%lang starknet

from starkware.cairo.common.cairo_builtins import HashBuiltin
from starkware.cairo.common.uint256 import Uint256
from starkware.cairo.common.alloc import alloc
from starkware.cairo.common.memcpy import memcpy
from starkware.starknet.common.syscalls import deploy, get_caller_address

@storage_var
func salt() -> (value : felt):
end
@storage_var
func space_class_hash_store() -> (value : felt):
end
@event
func space_deployed(
deployer_address : felt,
space_address : felt,
_voting_delay : felt,
_min_voting_duration : felt,
_max_voting_duration : felt,
_proposal_threshold : Uint256,
_controller : felt,
_quorum : Uint256,
_voting_strategies_len : felt,
_voting_strategies : felt*,
_authenticators_len : felt,
_authenticators : felt*,
_executors_len : felt,
_executors : felt*,
):
end
@constructor
func constructor{syscall_ptr : felt*, pedersen_ptr : HashBuiltin*, range_check_ptr}(
space_class_hash : felt
):
space_class_hash_store.write(space_class_hash)
return ()
end

@external
func deploy_space{syscall_ptr : felt*, pedersen_ptr : HashBuiltin*, range_check_ptr : felt}(
_voting_delay : felt,
_min_voting_duration : felt,
_max_voting_duration : felt,
_proposal_threshold : Uint256,
_controller : felt,
_quorum : Uint256,
_voting_strategy_params_flat_len : felt,
_voting_strategy_params_flat : felt*,
_voting_strategies_len : felt,
_voting_strategies : felt*,
_authenticators_len : felt,
_authenticators : felt*,
_executors_len : felt,
_executors : felt*,
):
alloc_locals
let (calldata : felt*) = alloc()
assert calldata[0] = _voting_delay
assert calldata[1] = _min_voting_duration
assert calldata[2] = _max_voting_duration
assert calldata[3] = _proposal_threshold.low
assert calldata[4] = _proposal_threshold.high
assert calldata[5] = _controller
assert calldata[6] = _quorum.low
assert calldata[7] = _quorum.high
assert calldata[8] = _voting_strategy_params_flat_len
memcpy(calldata + 9, _voting_strategy_params_flat, _voting_strategy_params_flat_len)
assert calldata[9 + _voting_strategy_params_flat_len] = _voting_strategies_len
memcpy(
calldata + 10 + _voting_strategy_params_flat_len, _voting_strategies, _voting_strategies_len
)
assert calldata[10 + _voting_strategies_len + _voting_strategy_params_flat_len] = _authenticators_len
memcpy(
calldata + 11 + _voting_strategies_len + _voting_strategy_params_flat_len,
_authenticators,
_authenticators_len,
)
assert calldata[11 + _voting_strategies_len + _voting_strategy_params_flat_len + _authenticators_len] = _executors_len
memcpy(
calldata + 12 + _voting_strategies_len + _voting_strategy_params_flat_len + _authenticators_len,
_executors,
_executors_len,
)
let (deployer_address) = get_caller_address()
let calldata_len = 12 + _voting_strategies_len + _voting_strategy_params_flat_len + _authenticators_len + _executors_len
let (current_salt) = salt.read()
let (space_class_hash) = space_class_hash_store.read()
let (space_address) = deploy(
class_hash=space_class_hash,
contract_address_salt=current_salt,
constructor_calldata_size=calldata_len,
constructor_calldata=calldata,
deploy_from_zero=0,
)
salt.write(value=current_salt + 1)

space_deployed.emit(
deployer_address,
space_address,
_voting_delay,
_min_voting_duration,
_max_voting_duration,
_proposal_threshold,
_controller,
_quorum,
_voting_strategies_len,
_voting_strategies,
_authenticators_len,
_authenticators,
_executors_len,
_executors,
)
return ()
end
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
"@gnosis.pm/safe-contracts": "^1.3.0",
"@gnosis.pm/zodiac": "^1.1.3",
"@openzeppelin/contracts": "^4.7.0",
"@shardlabs/starknet-hardhat-plugin": "^0.5.5",
"@shardlabs/starknet-hardhat-plugin": "^0.6.2",
"@snapshot-labs/sx": "0.1.0-beta.7",
"concurrently": "^7.3.0",
"ethereumjs-util": "^7.1.5",
Expand Down
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
https://github.com/starkware-libs/cairo-lang/releases/download/v0.9.0/cairo-lang-0.9.0.zip
https://github.com/starkware-libs/cairo-lang/releases/download/v0.9.1/cairo-lang-0.9.1.zip
openzeppelin-cairo-contracts==0.1.0
70 changes: 51 additions & 19 deletions test/shared/setup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,8 @@ import { starknet, ethers } from 'hardhat';
import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers';
import { StarknetContract, Account } from 'hardhat/types';
import { Contract, ContractFactory } from 'ethers';
// import { SplitUint256, IntsSequence } from './types';
// import { hexToBytes, flatten2DArray } from './helpers';
// import {
// ProcessBlockInputs,
// getProcessBlockInputs,
// ProofInputs,
// getProofInputs,
// } from './parseRPCData';
// import { encodeParams } from './singleSlotProofStrategyEncoding';
import { AddressZero } from '@ethersproject/constants';
import { executeContractCallWithSigners } from './safeUtils';

import { utils } from '@snapshot-labs/sx';

export interface Fossil {
Expand All @@ -24,7 +14,7 @@ export interface Fossil {
}

export async function vanillaSetup() {
const controller = (await starknet.deployAccount('Argent')) as Account;
const controller = (await starknet.deployAccount('OpenZeppelin')) as Account;
const spaceFactory = await starknet.getContractFactory('./contracts/starknet/Space.cairo');
const vanillaVotingStrategyFactory = await starknet.getContractFactory(
'./contracts/starknet/VotingStrategies/Vanilla.cairo'
Expand Down Expand Up @@ -85,7 +75,7 @@ export async function vanillaSetup() {
}

export async function zodiacRelayerSetup() {
const controller = (await starknet.deployAccount('Argent')) as Account;
const controller = (await starknet.deployAccount('OpenZeppelin')) as Account;
const spaceFactory = await starknet.getContractFactory('./contracts/starknet/Space.cairo');
const vanillaVotingStategyFactory = await starknet.getContractFactory(
'./contracts/starknet/VotingStrategies/Vanilla.cairo'
Expand Down Expand Up @@ -251,7 +241,7 @@ export async function safeWithZodiacSetup(
}

export async function ethTxAuthSetup() {
const controller = (await starknet.deployAccount('Argent')) as Account;
const controller = (await starknet.deployAccount('OpenZeppelin')) as Account;
const spaceFactory = await starknet.getContractFactory('./contracts/starknet/Space.cairo');
const vanillaVotingStrategyFactory = await starknet.getContractFactory(
'./contracts/starknet/VotingStrategies/Vanilla.cairo'
Expand Down Expand Up @@ -336,9 +326,10 @@ export async function singleSlotProofSetup(block: any, proofs: any) {
proofs
);

const controller = (await starknet.deployAccount('Argent')) as Account;
const controller = await starknet.deployAccount('OpenZeppelin');

const fossil = await fossilSetup(controller);

const spaceFactory = await starknet.getContractFactory('./contracts/starknet/Space.cairo');
const singleSlotProofStrategyFactory = await starknet.getContractFactory(
'contracts/starknet/VotingStrategies/SingleSlotProof.cairo'
Expand Down Expand Up @@ -421,7 +412,7 @@ export async function singleSlotProofSetup(block: any, proofs: any) {

// Setup function to test the single slot proof strategy in isolation, ie not within context of space contract
export async function singleSlotProofSetupIsolated(block: any) {
const account = await starknet.deployAccount('Argent');
const account = await starknet.deployAccount('OpenZeppelin');
const fossil = await fossilSetup(account);
const singleSlotProofStrategyFactory = await starknet.getContractFactory(
'contracts/starknet/VotingStrategies/SingleSlotProof.cairo'
Expand Down Expand Up @@ -461,7 +452,7 @@ async function fossilSetup(deployer: Account): Promise<Fossil> {
);
const factsRegistry = await factsRegistryFactory.deploy();
const l1HeadersStore = await l1HeadersStoreFactory.deploy();
const l1RelayerAccount = await starknet.deployAccount('Argent');
const l1RelayerAccount = await starknet.deployAccount('OpenZeppelin');
await deployer.invoke(factsRegistry, 'initialize', {
l1_headers_store_addr: BigInt(l1HeadersStore.address),
});
Expand All @@ -478,7 +469,7 @@ async function fossilSetup(deployer: Account): Promise<Fossil> {
// TODO: Ive left these functions in the old style for now as some changes are needed, but they should be refactored like the ones above soon.

export async function starknetAccountSetup() {
const account = await starknet.deployAccount('Argent');
const account = await starknet.deployAccount('OpenZeppelin');

const vanillaSpaceFactory = await starknet.getContractFactory('./contracts/starknet/Space.cairo');
const vanillaVotingStrategyFactory = await starknet.getContractFactory(
Expand Down Expand Up @@ -538,7 +529,7 @@ export async function starknetAccountSetup() {
}

export async function starkTxAuthSetup() {
const controller = await starknet.deployAccount('Argent');
const controller = await starknet.deployAccount('OpenZeppelin');
const spaceFactory = await starknet.getContractFactory('./contracts/starknet/Space.cairo');
const vanillaVotingStrategyFactory = await starknet.getContractFactory(
'./contracts/starknet/VotingStrategies/Vanilla.cairo'
Expand Down Expand Up @@ -598,8 +589,49 @@ export async function starkTxAuthSetup() {
};
}

export async function spaceFactorySetup() {
const controller = (await starknet.deployAccount('OpenZeppelin')) as Account;
const spaceDeployerFactory = await starknet.getContractFactory(
'./contracts/starknet/SpaceFactory.cairo'
);

const spaceFactoryClass = await starknet.getContractFactory('./contracts/starknet/Space.cairo');
const spaceHash = await spaceFactoryClass.declare();

const vanillaVotingStrategyFactory = await starknet.getContractFactory(
'./contracts/starknet/VotingStrategies/Vanilla.cairo'
);
const vanillaAuthenticatorFactory = await starknet.getContractFactory(
'./contracts/starknet/Authenticators/Vanilla.cairo'
);
const vanillaExecutionStrategyFactory = await starknet.getContractFactory(
'./contracts/starknet/ExecutionStrategies/Vanilla.cairo'
);

const deployments = [
vanillaAuthenticatorFactory.deploy(),
vanillaVotingStrategyFactory.deploy(),
vanillaExecutionStrategyFactory.deploy(),
spaceDeployerFactory.deploy({ space_class_hash: spaceHash }),
];
const contracts = await Promise.all(deployments);
const vanillaAuthenticator = contracts[0] as StarknetContract;
const vanillaVotingStrategy = contracts[1] as StarknetContract;
const vanillaExecutionStrategy = contracts[2] as StarknetContract;
const spaceDeployer = contracts[3] as StarknetContract;

return {
spaceDeployer,
spaceFactoryClass,
controller,
vanillaAuthenticator,
vanillaVotingStrategy,
vanillaExecutionStrategy,
};
}

export async function starknetExecutionSetup() {
const controller = (await starknet.deployAccount('Argent')) as Account;
const controller = (await starknet.deployAccount('OpenZeppelin')) as Account;
const spaceFactory = await starknet.getContractFactory('./contracts/starknet/Space.cairo');
const vanillaVotingStrategyFactory = await starknet.getContractFactory(
'./contracts/starknet/VotingStrategies/Vanilla.cairo'
Expand Down
2 changes: 1 addition & 1 deletion test/starknet/SingleSlotProof.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ describe('Single slot proof voting strategy:', () => {
const block = JSON.parse(fs.readFileSync('./test/data/block.json').toString());
const proofs = JSON.parse(fs.readFileSync('./test/data/proofs.json').toString());

account = await starknet.deployAccount('Argent');
account = await starknet.deployAccount('OpenZeppelin');

({
space,
Expand Down
Loading

0 comments on commit 08f0a5e

Please sign in to comment.