Skip to content

Commit 49cbb3c

Browse files
authored
docs(contracts): improve deployment instructions and scripts (#181)
1 parent 1311a87 commit 49cbb3c

7 files changed

Lines changed: 335 additions & 241 deletions

File tree

contracts/DESIGN.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Design
1+
# Contract Design
22

33
This document describes the Succinct Prover Network contracts in detail.
44

contracts/OPERATIONS.md

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
# Contract Operations
2+
3+
This document contains commands to interact with the deployed contracts.
4+
5+
To run these cast commands, you need to set the environment variables to the addresses of the contracts you deployed, by looking at the [deployments](./deployments) directory.
6+
7+
This can be automatically done with the following command:
8+
9+
```sh
10+
CHAIN_ID=$(cast chain-id --rpc-url "$ETH_RPC_URL") && export $(jq -r 'to_entries|map("\(.key)=\(.value)")|.[]' ./deployments/${CHAIN_ID}.json) >/dev/null
11+
```
12+
13+
## Staking
14+
15+
### Create a Prover
16+
17+
```sh
18+
cast send $STAKING "createProver(uint256)" 1000 --private-key $PRIVATE_KEY --rpc-url $ETH_RPC_URL
19+
```
20+
21+
### Stake
22+
23+
```sh
24+
cast send $PROVE "approve(address,uint256)" $STAKING 10000e18 --private-key $PRIVATE_KEY --rpc-url $ETH_RPC_URL
25+
```
26+
27+
```sh
28+
cast send $STAKING "stake(address,uint256)" $PROVER 9990e18 --private-key $PRIVATE_KEY --rpc-url $ETH_RPC_URL
29+
```
30+
31+
### Unstake
32+
33+
```sh
34+
cast send $STAKING "requestUnstake(uint256)" 2000e18 --private-key $PRIVATE_KEY --rpc-url $ETH_RPC_URL
35+
```
36+
37+
```sh
38+
cast send $STAKING "finishUnstake()" --private-key $PRIVATE_KEY --rpc-url $ETH_RPC_URL
39+
```
40+
41+
### Dispense
42+
43+
Figure out the maximum amount of $PROVE that can be dispensed:
44+
45+
```sh
46+
export DISPENSE_AMOUNT=$(cast call $STAKING "maxDispense()" --rpc-url $ETH_RPC_URL)
47+
```
48+
49+
Send some $PROVE to the $STAKING contract (assumes your balance is enough):
50+
51+
```sh
52+
cast send $PROVE "transfer(address,uint256)" $STAKING $DISPENSE_AMOUNT --private-key $PRIVATE_KEY --rpc-url $ETH_RPC_URL
53+
```
54+
55+
Dispense it:
56+
57+
```sh
58+
cast send $STAKING "dispense(uint256)" $DISPENSE_AMOUNT --private-key $PRIVATE_KEY --rpc-url $ETH_RPC_URL
59+
```
60+
61+
OR just simply dispense the maximum amount:
62+
63+
```sh
64+
cast send $STAKING "dispense(uint256)" $(cast max-uint) --private-key $PRIVATE_KEY --rpc-url $ETH_RPC_URL
65+
```
66+
67+
## vApp
68+
69+
### Deposit
70+
71+
```sh
72+
cast send $PROVE "approve(address,uint256)" $VAPP 10000000e18 --private-key $PRIVATE_KEY --rpc-url $ETH_RPC_URL
73+
```
74+
75+
```sh
76+
cast send $VAPP "deposit(uint256)" 10000000e18 --private-key $PRIVATE_KEY --rpc-url $ETH_RPC_URL
77+
```
78+
79+
## View
80+
81+
82+
### Check stake balances
83+
84+
Staker:
85+
86+
```sh
87+
cast to-dec $(cast call $STAKING "staked(address)" $(cast wallet address --private-key $PRIVATE_KEY) --rpc-url $ETH_RPC_URL)
88+
```
89+
90+
Prover:
91+
92+
```sh
93+
cast to-dec $(cast call $STAKING "proverStaked(address)" $PROVER --rpc-url $ETH_RPC_URL)
94+
```

contracts/README.md

Lines changed: 56 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -62,122 +62,116 @@ Then add a `{CHAIN_ID}.json` file in the [deployments](./deployments) directory
6262
CHAIN_ID=$(cast chain-id --rpc-url $ETH_RPC_URL); mkdir -p ./deployments && [ -f "./deployments/${CHAIN_ID}.json" ] || echo '{}' > "./deployments/${CHAIN_ID}.json"
6363
```
6464

65-
### Run the scripts
65+
Then you should add the `VKEY` and `GENESIS_STATE_ROOT` to the `{CHAIN_ID}.json` file:
6666

67-
Deploy all contracts:
68-
69-
```sh
70-
FOUNDRY_PROFILE=deploy forge script AllScript --private-key $PRIVATE_KEY --broadcast --rpc-url $ETH_RPC_URL
67+
```json
68+
{
69+
"VKEY": "0x004988f252500633b4d3d369b3726d5bdacfbe35236b36eb2d487af3742c905e",
70+
"GENESIS_STATE_ROOT": "0xc88159adb4da01a67b90803d48a35fbf7f457572b61377e5d4b090c89488b838"
71+
}
7172
```
7273

73-
Then mint some $PROVE tokens (assuming you made the $OWNER the same as the $PRIVATE_KEY address):
74+
Ensure these match the actual vkey and genesis state root for the Rust vApp program.
7475

75-
```sh
76-
FOUNDRY_PROFILE=deploy forge script MintScript --private-key $PRIVATE_KEY --broadcast --rpc-url $ETH_RPC_URL
77-
```
76+
Note: the production version of these contracts were deployed using foundry [v1.3.0](https://github.com/foundry-rs/foundry/releases/tag/v1.3.0).
77+
78+
### Bulk deployment
79+
80+
This should generally only be used for testing.
7881

79-
Then create a prover and stake:
82+
Deploy all contracts at once:
8083

8184
```sh
82-
FOUNDRY_PROFILE=deploy forge script CreateProverAndStakeScript --private-key $PRIVATE_KEY --broadcast --rpc-url $ETH_RPC_URL
85+
FOUNDRY_PROFILE=deploy forge script AllScript --private-key $PRIVATE_KEY --broadcast --rpc-url $ETH_RPC_URL
8386
```
8487

8588
You can append `--verify --verifier etherscan --etherscan-api-key $ETHERSCAN_API_KEY` to the above commands to verify the contracts on Etherscan.
8689

87-
## Other Operations
90+
### Individual deployment
8891

89-
To run cast commands, you need to set the environment variables to the addresses of the contracts you deployed, by looking at the [deployments](./deployments) directory.
92+
Instead of deploying all contracts at once, it's recommended to deploy each contract individually for production deployments.
9093

91-
```sh
92-
CHAIN_ID=$(cast chain-id --rpc-url "$ETH_RPC_URL") && export $(jq -r 'to_entries|map("\(.key)=\(.value)")|.[]' ./deployments/${CHAIN_ID}.json) >/dev/null
93-
```
94+
#### Pre-deployed contracts
9495

95-
### Deposit
96+
Fill out `{CHAIN_ID}.json` with any pre-deployed contracts. For example, if there is an existing `PROVE` and `VERIFIER` those keys would be filled:
9697

97-
```sh
98-
cast send $PROVE "approve(address,uint256)" $VAPP 10000000e18 --private-key $PRIVATE_KEY --rpc-url $ETH_RPC_URL
98+
```json
99+
{
100+
"VKEY": "0x004988f252500633b4d3d369b3726d5bdacfbe35236b36eb2d487af3742c905e",
101+
"GENESIS_STATE_ROOT": "0xc88159adb4da01a67b90803d48a35fbf7f457572b61377e5d4b090c89488b838",
102+
"PROVE": "0x6BEF15D938d4E72056AC92Ea4bDD0D76B1C4ad29",
103+
"VERIFIER": "0x397A5f7f3dBd538f23DE225B51f532c34448dA9B"
104+
}
99105
```
100106

101-
```sh
102-
cast send $VAPP "deposit(uint256)" 10000000e18 --private-key $PRIVATE_KEY --rpc-url $ETH_RPC_URL
103-
```
107+
#### Deploy each contract
104108

105-
### Withdraw
109+
Deploy the SuccinctStaking contract:
106110

107111
```sh
108-
cast send $VAPP "requestWithdraw(address,uint256)" $(cast wallet address --private-key $PRIVATE_KEY) 100e18 --private-key $PRIVATE_KEY --rpc-url $ETH_RPC_URL
112+
FOUNDRY_PROFILE=deploy forge script SuccinctStakingScript --private-key $PRIVATE_KEY --broadcast --rpc-url $ETH_RPC_URL --verify --verifier etherscan --etherscan-api-key $ETHERSCAN_API_KEY
109113
```
110114

111-
You need to wait for the withdrawal to be processed before you can finish it:
115+
This DOES NOT initalize the contract - this will be done in a later step once references to other contracts are available.
116+
117+
Deploy the $iPROVE contract (assumes $PROVE is already deployed):
112118

113119
```sh
114-
if [ $(cast call $VAPP "claimableWithdrawal(address)" $(cast wallet address --private-key $PRIVATE_KEY) --rpc-url $ETH_RPC_URL) -gt 0 ]; then
115-
cast send $VAPP "finishWithdraw()" --private-key $PRIVATE_KEY --rpc-url $ETH_RPC_URL
116-
fi
120+
FOUNDRY_PROFILE=deploy forge script IntermediateSuccinctScript --private-key $PRIVATE_KEY --broadcast --rpc-url $ETH_RPC_URL --verify --verifier etherscan --etherscan-api-key $ETHERSCAN_API_KEY
117121
```
118122

119-
### Create a Prover
123+
Deploy the SuccinctGovernor contract:
120124

121125
```sh
122-
cast send $STAKING "createProver()" $(cast wallet address --private-key $PRIVATE_KEY) --private-key $PRIVATE_KEY --rpc-url $ETH_RPC_URL
126+
FOUNDRY_PROFILE=deploy forge script SuccinctGovernorScript --private-key $PRIVATE_KEY --broadcast --rpc-url $ETH_RPC_URL --verify --verifier etherscan --etherscan-api-key $ETHERSCAN_API_KEY
123127
```
124128

125-
### Stake
129+
Deploy the SuccinctVApp implementation and proxy contracts (assumes verifier is already deployed):
126130

127131
```sh
128-
cast send $PROVE "approve(address,uint256)" $STAKING 10000e18 --private-key $PRIVATE_KEY --rpc-url $ETH_RPC_URL
132+
FOUNDRY_PROFILE=deploy forge script SuccinctVAppScript --private-key $PRIVATE_KEY --broadcast --rpc-url $ETH_RPC_URL --verify --verifier etherscan --etherscan-api-key $ETHERSCAN_API_KEY
129133
```
130134

131-
```sh
132-
cast send $STAKING "stake(address,uint256)" $PROVER 9990e18 --private-key $PRIVATE_KEY --rpc-url $ETH_RPC_URL
133-
```
135+
If the SP1VerifierGateway is not already deployed, follow steps in [sp1-contracts](https://github.com/succinctlabs/sp1-contracts) to deploy it and fill out the address in your `{CHAIN_ID}.json` file.
134136

135-
### Unstake
137+
Initalize the SuccinctStaking contract:
136138

137139
```sh
138-
cast send $STAKING "requestUnstake(uint256)" 2000e18 --private-key $PRIVATE_KEY --rpc-url $ETH_RPC_URL
140+
FOUNDRY_PROFILE=deploy forge script SuccinctStakingScript --sig "initialize()" --private-key $PRIVATE_KEY --broadcast --rpc-url $ETH_RPC_URL
139141
```
140142

143+
Run the integrity check:
144+
141145
```sh
142-
cast send $STAKING "finishUnstake()" --private-key $PRIVATE_KEY --rpc-url $ETH_RPC_URL
146+
FOUNDRY_PROFILE=deploy forge script PostDeploymentScript --rpc-url $ETH_RPC_URL
143147
```
144148

145-
### Dispense
149+
If that passes without reverting, the contracts have been successfully deployed and initalized. The addresses are in the `{CHAIN_ID}.json` file.
146150

147-
Figure out the maximum amount of $PROVE that can be dispensed:
151+
## Verification
148152

149-
```sh
150-
export DISPENSE_AMOUNT=$(cast call $STAKING "maxDispense()" --rpc-url $ETH_RPC_URL)
151-
```
153+
If any of the contracts failed to verify on Etherscan, you can manually verify them by copying the the flatten source code and uploading it to Etherscan.
152154

153-
Send some $PROVE to the $STAKING contract (assumes your balance is enough):
155+
To do this, go to the address on Etherscan and click "Verify Contract". Choose:
154156

155-
```sh
156-
cast send $PROVE "transfer(address,uint256)" $STAKING $DISPENSE_AMOUNT --private-key $PRIVATE_KEY --rpc-url $ETH_RPC_URL
157-
```
157+
* Compiler: "Solidity (Single File)"
158+
* Compiler Version: "0.8.28"
159+
* License: "MIT"
158160

159-
Dispense it:
161+
Then flatten the contract you're verifying, for example the SuccinctStaking contract:
160162

161163
```sh
162-
cast send $STAKING "dispense(uint256)" $DISPENSE_AMOUNT --private-key $PRIVATE_KEY --rpc-url $ETH_RPC_URL
164+
forge flatten src/SuccinctStaking.sol
163165
```
164166

165-
OR just simply dispense the maximum amount:
167+
Copy the output into the "Contract Code" field.
166168

167-
```sh
168-
cast send $STAKING "dispense(uint256)" $(cast max-uint) --private-key $PRIVATE_KEY --rpc-url $ETH_RPC_URL
169-
```
170-
171-
### Check stake balances
169+
Then enter the compiler settings from the [foundry.toml](./foundry.toml) file's `[profile.deploy]` section.
172170

173-
Staker:
171+
If any constructor arguements were used but not shown in the "Constructor Arguments" field, use `cast abi-encode` with the appropriate signature to encode them, for example:
174172

175173
```sh
176-
cast to-dec $(cast call $STAKING "staked(address)" $(cast wallet address --private-key $PRIVATE_KEY) --rpc-url $ETH_RPC_URL)
174+
cast abi-encode "constructor(address)" 0xbD74E9B0Dcb0317E26505CA93757c29d564B533B
177175
```
178176

179-
Prover:
180-
181-
```sh
182-
cast to-dec $(cast call $STAKING "proverStaked(address)" $PROVER --rpc-url $ETH_RPC_URL)
183-
```
177+
strip the `0x` prefix from this output and paste it into the "Constructor Arguments" field.

contracts/script/deploy/All.s.sol

Lines changed: 27 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@ contract AllScript is BaseScript, FixtureLoader {
2525
address PROVE = address(new Succinct{salt: salt}(OWNER));
2626
address I_PROVE = address(new IntermediateSuccinct{salt: salt}(PROVE, STAKING));
2727
address GOVERNOR = _deployGovernor(salt, I_PROVE);
28-
(address VERIFIER, address VAPP) = _deployVAppAsProxy(salt, OWNER, PROVE, I_PROVE, STAKING);
28+
(address VERIFIER, address VAPP, address VAPP_IMPL) =
29+
_deployVAppAsProxy(salt, OWNER, PROVE, I_PROVE, STAKING);
2930

3031
// Initialize staking contract
3132
_initializeStaking(STAKING, GOVERNOR, VAPP, PROVE, I_PROVE);
@@ -34,6 +35,7 @@ contract AllScript is BaseScript, FixtureLoader {
3435
writeAddress("STAKING", STAKING);
3536
writeAddress("VERIFIER", VERIFIER);
3637
writeAddress("VAPP", VAPP);
38+
writeAddress("VAPP_IMPL", VAPP_IMPL);
3739
writeAddress("PROVE", PROVE);
3840
writeAddress("I_PROVE", I_PROVE);
3941
writeAddress("GOVERNOR", GOVERNOR);
@@ -60,14 +62,13 @@ contract AllScript is BaseScript, FixtureLoader {
6062
address PROVE,
6163
address I_PROVE,
6264
address STAKING
63-
) internal returns (address, address) {
65+
) internal returns (address, address, address) {
6466
// Read config
6567
address AUCTIONEER = readAddress("AUCTIONEER");
66-
address VERIFIER = vm.envOr("VERIFIER", address(0));
68+
address VERIFIER = readAddress("VERIFIER");
6769
uint256 MIN_DEPOSIT_AMOUNT = readUint256("MIN_DEPOSIT_AMOUNT");
68-
bytes32 VKEY = bytes32(0x00e76fb5ef418452b5e97124585bafbaeb300468cc863e052341ec81b8daa5d8);
69-
bytes32 GENESIS_STATE_ROOT =
70-
bytes32(0xde6c5941bbaeab97cabda7eaba5e6dd8b5dfb58cb2fb43238a7e707c6b2c587f);
70+
bytes32 VKEY = readBytes32("VKEY");
71+
bytes32 GENESIS_STATE_ROOT = readBytes32("GENESIS_STATE_ROOT");
7172

7273
// If the verifier is not provided, deploy the SP1VerifierGateway and add v5.0.0 Groth16 SP1Verifier to it
7374
if (VERIFIER == address(0)) {
@@ -76,23 +77,29 @@ contract AllScript is BaseScript, FixtureLoader {
7677
SP1VerifierGateway(VERIFIER).addRoute(groth16);
7778
}
7879

80+
// Encode the initialize function call data
81+
bytes memory initData = abi.encodeCall(
82+
SuccinctVApp.initialize,
83+
(
84+
OWNER,
85+
PROVE,
86+
I_PROVE,
87+
AUCTIONEER,
88+
STAKING,
89+
VERIFIER,
90+
MIN_DEPOSIT_AMOUNT,
91+
VKEY,
92+
GENESIS_STATE_ROOT
93+
)
94+
);
95+
7996
// Deploy contract
80-
address vappImpl = address(new SuccinctVApp{salt: salt}());
81-
address VAPP =
82-
address(SuccinctVApp(payable(address(new ERC1967Proxy{salt: salt}(vappImpl, "")))));
83-
SuccinctVApp(VAPP).initialize(
84-
OWNER,
85-
PROVE,
86-
I_PROVE,
87-
AUCTIONEER,
88-
STAKING,
89-
VERIFIER,
90-
MIN_DEPOSIT_AMOUNT,
91-
VKEY,
92-
GENESIS_STATE_ROOT
97+
address VAPP_IMPL = address(new SuccinctVApp{salt: salt}());
98+
address VAPP = address(
99+
SuccinctVApp(payable(address(new ERC1967Proxy{salt: salt}(VAPP_IMPL, initData))))
93100
);
94101

95-
return (VERIFIER, VAPP);
102+
return (VERIFIER, VAPP, VAPP_IMPL);
96103
}
97104

98105
/// @dev This is a stack-too-deep workaround.

0 commit comments

Comments
 (0)