Skip to content
Merged
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
27 changes: 27 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
### Replace placeholder values before running scripts

# Private key used by forge script (hex without quotes)
PRIVATE_KEY=0xabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcd

# External RPC endpoint to broadcast transactions
RPC_URL=https://rpc.testnet3.goat.network

# Previously deployed Bitcoin SPV verifier contract
BITCOINSPV_ADDR=0x0000000000000000000000000000000000000001

# Addresses captured after running each deploy script
GATEWAY_PROXY_ADDR=0x0000000000000000000000000000000000000002
PEGBTC_ADDR=0x0000000000000000000000000000000000000003
COMMITTEE_PROXY_ADDR=0x0000000000000000000000000000000000000004
STAKE_PROXY_ADDR=0x0000000000000000000000000000000000000005

# Committee member addresses (add or remove sequentially numbered keys)
COMMITTEE_0=0x0000000000000000000000000000000000000006
COMMITTEE_1=0x0000000000000000000000000000000000000007

# Watchtower identifiers (32-byte hex strings). Add WATCHTOWER_2, etc. as needed.
WATCHTOWER_0=0x0000000000000000000000000000000000000000000000000000000000000008

# SequencerSetPublisher owner address
OWNER=0x0000000000000000000000000000000000000000

24 changes: 24 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
deploy-gateway-main:
forge script script/deploy/DeployGateway.sol:DeployGateway --rpc-url goatMainnet --broadcast -vvvv --verify --verifier blockscout --verifier-url https://explorer.goat.network/api/

deploy-gateway-test:
forge script script/deploy/DeployGateway.sol:DeployGateway --rpc-url goatTestnet --broadcast -vvvv --verify --verifier blockscout --verifier-url https://explorer.testnet3.goat.network/api/

deploy-pegbtc-main:
forge script script/deploy/DeployPegBTC.sol:DeployPegBTC --rpc-url goatMainnet --broadcast -vvvv --verify --verifier blockscout --verifier-url https://explorer.goat.network/api/

deploy-pegbtc-test:
forge script script/deploy/DeployPegBTC.sol:DeployPegBTC --rpc-url goatTestnet --broadcast -vvvv --verify --verifier blockscout --verifier-url https://explorer.testnet3.goat.network/api/

deploy-committee-main:
forge script script/deploy/DeployCommitteeManagement.sol:DeployCommitteeManagement --rpc-url goatMainnet --broadcast -vvvv --verify --verifier blockscout --verifier-url https://explorer.goat.network/api/

deploy-committee-test:
forge script script/deploy/DeployCommitteeManagement.sol:DeployCommitteeManagement --rpc-url goatTestnet --broadcast -vvvv --verify --verifier blockscout --verifier-url https://explorer.testnet3.goat.network/api/

deploy-stake-main:
forge script script/deploy/DeployStakeManagement.sol:DeployStakeManagement --rpc-url goatMainnet --broadcast -vvvv --verify --verifier blockscout --verifier-url https://explorer.goat.network/api/

deploy-stake-test:
forge script script/deploy/DeployStakeManagement.sol:DeployStakeManagement --rpc-url goatTestnet --broadcast -vvvv --verify --verifier blockscout --verifier-url https://explorer.testnet3.goat.network/api/

8 changes: 8 additions & 0 deletions foundry.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"lib/openzeppelin-contracts-upgradeable": {
"rev": "3d5fa5c24c411112bab47bec25cfa9ad0af0e6e8"
},
"lib/forge-std": {
"rev": "3b20d60d14b343ee4f908cb8079495c07f5e8981"
}
}
111 changes: 85 additions & 26 deletions script/DeployContractDebug.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import {IPegBTC} from "../src/interfaces/IPegBTC.sol";
import {IBitcoinSPV} from "../src/interfaces/IBitcoinSPV.sol";
import {CommitteeManagement} from "../src/CommitteeManagement.sol";
import {StakeManagement} from "../src/StakeManagement.sol";
import {ICommitteeManagement} from "../src/interfaces/ICommitteeManagement.sol";
import {IStakeManagement} from "../src/interfaces/IStakeManagement.sol";

import {GatewayDebug, CommitteeManagementDebug} from "../src/GatewayDebug.sol";
import {PegBTC} from "../src/PegBTC.sol";
Expand All @@ -30,47 +32,97 @@ contract DeployGateway is Script {
}

function deploy() public {
// deploy contracts
GatewayDebug gatewayImpl = new GatewayDebug();
console.log("Gateway implementation contract address: ", address(gatewayImpl));
console.log(
"Gateway implementation contract address: ",
address(gatewayImpl)
);

UpgradeableProxy proxy = new UpgradeableProxy(address(gatewayImpl), deployer, "");
console.log("Gateway proxy contract contract address: ", address(proxy));
GatewayDebug gateway = GatewayDebug(payable(proxy));
UpgradeableProxy gatewayProxy = new UpgradeableProxy(
address(gatewayImpl),
deployer,
""
);
console.log("Gateway proxy contract address: ", address(gatewayProxy));
GatewayDebug gateway = GatewayDebug(payable(gatewayProxy));

PegBTC pegBTC = new PegBTC(address(gateway));
console.log("PegBTC contract address: ", address(pegBTC));

// Read committee config from env
// - COMMITTEE_0, COMMITTEE_1, ... (addresses)
// - WATCHTOWER_0, WATCHTOWER_1, ... (bytes32)
address[] memory initialMembers = _readSequentialAddresses("COMMITTEE");
uint256 initialRequired = (initialMembers.length * 2 + 2) / 3;
bytes32[] memory initialWatchtowers = _readSequentialBytes32("WATCHTOWER");
bytes32[] memory initialWatchtowers = _readSequentialBytes32(
"WATCHTOWER"
);
require(initialMembers.length > 0, "COMMITTEE list empty");
require(initialWatchtowers.length > 0, "WATCHTOWER list empty");
address[] memory initialAuthorizedCallers = new address[](1);
initialAuthorizedCallers[0] = address(gateway);
CommitteeManagementDebug committeeManagement =
new CommitteeManagementDebug(initialMembers, initialRequired, initialAuthorizedCallers, initialWatchtowers);
console.log("CommitteeManagement contract address: ", address(committeeManagement));

StakeManagement stakeManagement = new StakeManagement(IERC20(address(pegBTC)), address(gateway));
console.log("StakeManagement contract address: ", address(stakeManagement));
CommitteeManagementDebug committeeImpl = new CommitteeManagementDebug();
console.log(
"CommitteeManagement implementation contract address: ",
address(committeeImpl)
);
bytes memory committeeInitData = abi.encodeWithSelector(
CommitteeManagement.initialize.selector,
initialMembers,
initialRequired,
initialAuthorizedCallers,
initialWatchtowers
);
UpgradeableProxy committeeProxy = new UpgradeableProxy(
address(committeeImpl),
deployer,
committeeInitData
);
console.log(
"CommitteeManagement proxy contract address: ",
address(committeeProxy)
);
ICommitteeManagement committeeManagement = ICommitteeManagement(
address(committeeProxy)
);

StakeManagement stakeImpl = new StakeManagement();
console.log(
"StakeManagement implementation contract address: ",
address(stakeImpl)
);
bytes memory stakeInitData = abi.encodeWithSelector(
StakeManagement.initialize.selector,
IERC20(address(pegBTC)),
address(gateway)
);
UpgradeableProxy stakeProxy = new UpgradeableProxy(
address(stakeImpl),
deployer,
stakeInitData
);
console.log(
"StakeManagement proxy contract address: ",
address(stakeProxy)
);
IStakeManagement stakeManagement = IStakeManagement(
address(stakeProxy)
);

gateway.initialize(
IPegBTC(address(pegBTC)),
IBitcoinSPV(bitcoinSPV),
CommitteeManagement(address(committeeManagement)),
StakeManagement(address(stakeManagement))
committeeManagement,
stakeManagement
);
}

// Helpers: read env arrays as sequential variables with numeric suffixes
// Example: BASE=PREFIX, reads PREFIX_0, PREFIX_1, ... until a default is hit.
function _readSequentialAddresses(string memory baseKey) internal view returns (address[] memory out) {
// first pass: count
function _readSequentialAddresses(
string memory baseKey
) internal view returns (address[] memory out) {
uint256 count = 0;
while (true) {
string memory key = string(abi.encodePacked(baseKey, "_", vm.toString(count)));
string memory key = string(
abi.encodePacked(baseKey, "_", vm.toString(count))
);
address val = vm.envOr(key, address(0));
if (val == address(0)) break;
unchecked {
Expand All @@ -79,16 +131,21 @@ contract DeployGateway is Script {
}
out = new address[](count);
for (uint256 i = 0; i < count; i++) {
string memory key = string(abi.encodePacked(baseKey, "_", vm.toString(i)));
string memory key = string(
abi.encodePacked(baseKey, "_", vm.toString(i))
);
out[i] = vm.envAddress(key);
}
}

function _readSequentialBytes32(string memory baseKey) internal view returns (bytes32[] memory out) {
// first pass: count
function _readSequentialBytes32(
string memory baseKey
) internal view returns (bytes32[] memory out) {
uint256 count = 0;
while (true) {
string memory key = string(abi.encodePacked(baseKey, "_", vm.toString(count)));
string memory key = string(
abi.encodePacked(baseKey, "_", vm.toString(count))
);
bytes32 val = vm.envOr(key, bytes32(0));
if (val == bytes32(0)) break;
unchecked {
Expand All @@ -97,7 +154,9 @@ contract DeployGateway is Script {
}
out = new bytes32[](count);
for (uint256 i = 0; i < count; i++) {
string memory key = string(abi.encodePacked(baseKey, "_", vm.toString(i)));
string memory key = string(
abi.encodePacked(baseKey, "_", vm.toString(i))
);
out[i] = vm.envBytes32(key);
}
}
Expand Down
106 changes: 0 additions & 106 deletions script/DeployGateway.sol

This file was deleted.

2 changes: 1 addition & 1 deletion script/InitWithdraw.sol
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ contract InitWithdraw is Script {
// Read pegin data to compute the exact lock amount in PegBTC
GatewayUpgradeable.PeginData memory pegin = gateway.getPeginData(instanceId);
require(pegin.peginAmountSats > 0, "pegin not found or amount=0");
uint256 lockAmount = Converter.amountFromSats(pegin.peginAmountSats);
uint256 lockAmount = Converter._amountFromSats(pegin.peginAmountSats);

// derive sender address from private key in a view-only way
address operator = vm.addr(pk);
Expand Down
38 changes: 30 additions & 8 deletions script/README.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,35 @@
# Deploy
# Deployment Scripts

## Environment setup

```
export prv=...
export OWNER=0x8943545177806ED17B9F23F0a21ee5948eCaa776
1. Copy `.env.example` to `.env` and replace the placeholder values.
2. Add as many `COMMITTEE_<index>` and `WATCHTOWER_<index>` entries as needed. Indexes must be sequential (e.g., `_0`, `_1`, `_2`).
3. Export the variables into your shell (`set -a && source .env && set +a`) or let Foundry load them via `--env .env`.

## Deploying the Gateway stack

All deployment scripts now live under `script/deploy/` and each script focuses on a single contract. Run them in the order below, updating your `.env` with the emitted addresses between steps:

forge script script/SSPDeploy.s.sol:Deploy \
--rpc-url https://rpc.testnet3.goat.network --private-key=$prv --broadcast --legacy
1. **Gateway proxy** – `script/deploy/DeployGateway.sol:DeployGateway`
2. **PegBTC token** – `script/deploy/DeployPegBTC.sol:DeployPegBTC`
3. **CommitteeManagement proxy** – `script/deploy/DeployCommitteeManagement.sol:DeployCommitteeManagement`
4. **StakeManagement proxy** – `script/deploy/DeployStakeManagement.sol:DeployStakeManagement`
5. **Gateway init via constructor data** – rerun the Gateway deploy script once `PEGBTC_ADDR`, `BITCOINSPV_ADDR`, `COMMITTEE_PROXY_ADDR`, and `STAKE_PROXY_ADDR` are known so that the proxy is deployed with the correct initializer calldata.

Example command:

```bash
forge script script/deploy/DeployGateway.sol:DeployGateway \
--rpc-url goatTestnet \
--broadcast -vvvv \
--verify --verifier blockscout \
--verifier-url https://explorer.testnet3.goat.network/api/
```

forge verify-contract --compiler-version 0.8.28 0x3901C4670aA92a626636f7Ea1e3F029A0ECd6b68 SequencerSetPublisher --verifier blockscout --verifier-url 'https://explorer.testnet3.goat.network/api/'
Repeat the command with the appropriate script name (and `goatMainnet` when deploying to mainnet). Required environment variables grow as you progress:

```
- `PRIVATE_KEY`: broadcaster key (hex string, no quotes).
- `BITCOINSPV_ADDR`: previously deployed Bitcoin SPV contract.
- `GATEWAY_PROXY_ADDR`: emitted when deploying the gateway proxy (needed by PegBTC + Committee scripts).
- `PEGBTC_ADDR`, `COMMITTEE_PROXY_ADDR`, `STAKE_PROXY_ADDR`: used by the Gateway deploy script when encoding initializer calldata.
- `COMMITTEE_<i>` / `WATCHTOWER_<i>`: sequential committee + watchtower definitions for the committee deploy script.
Loading