Skip to content

Commit

Permalink
Merge branch 'main' into ron/transact-from-eth-to-sub
Browse files Browse the repository at this point in the history
  • Loading branch information
yrong committed Feb 29, 2024
2 parents e99ce53 + cba0fe1 commit 2e4140c
Show file tree
Hide file tree
Showing 13 changed files with 273 additions and 22 deletions.
11 changes: 0 additions & 11 deletions codecov.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,9 @@ ignore:
- "contracts/src/utils"
- "contracts/src/ScaleCodec.sol"
- "contracts/src/SubstrateTypes.sol"
- "polkadot-sdk/bridges/snowbridge/pallets/ethereum-beacon-client/src/benchmarking"
- "polkadot-sdk/bridges/snowbridge/pallets/ethereum-beacon-client/src/weights.rs"
- "polkadot-sdk/bridges/snowbridge/pallets/inbound-queue/fixtures"
- "polkadot-sdk/bridges/snowbridge/pallets/ethereum-client/fixtures"
- "polkadot-sdk/bridges/snowbridge/pallets/ethereum-client/fuzz"
- "contracts/src/DeployScript.sol"
- "parachain/pallets/inbound-queue/fixtures"
- "parachain/pallets/ethereum-client/fixtures"
flags:
solidity:
paths:
- contracts
carryforward: true
rust:
paths:
- polkadot-sdk/bridges/snowbridge
carryforward: true
33 changes: 33 additions & 0 deletions contracts/src/DeployGatewayLogic.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: 2023 Snowfork <[email protected]>
pragma solidity 0.8.23;

import {AgentExecutor} from "./AgentExecutor.sol";
import {Gateway} from "./Gateway.sol";
import {ParaID} from "./Types.sol";
import {Script} from "forge-std/Script.sol";
import {stdJson} from "forge-std/StdJson.sol";

contract DeployGatewayLogic is Script {
using stdJson for string;

function setUp() public {}

function run() public {
uint256 privateKey = vm.envUint("PRIVATE_KEY");
address deployer = vm.rememberKey(privateKey);
vm.startBroadcast(deployer);

address beefyClient = vm.envAddress("BEEFY_CLIENT_CONTRACT_ADDRESS");

ParaID bridgeHubParaID = ParaID.wrap(uint32(vm.envUint("BRIDGE_HUB_PARAID")));
bytes32 bridgeHubAgentID = vm.envBytes32("BRIDGE_HUB_AGENT_ID");

uint8 foreignTokenDecimals = uint8(vm.envUint("FOREIGN_TOKEN_DECIMALS"));

AgentExecutor executor = new AgentExecutor();
new Gateway(address(beefyClient), address(executor), bridgeHubParaID, bridgeHubAgentID, foreignTokenDecimals);

vm.stopBroadcast();
}
}
7 changes: 6 additions & 1 deletion contracts/src/Gateway.sol
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ contract Gateway is IGateway, IInitializable {
error InvalidAgentExecutionPayload();
error InvalidCodeHash();
error InvalidConstructorParams();
error InvalidTransact();
error AlreadyInitialized();

// handler functions are privileged
modifier onlySelf() {
Expand Down Expand Up @@ -585,6 +585,11 @@ contract Gateway is IGateway, IInitializable {
Config memory config = abi.decode(data, (Config));

CoreStorage.Layout storage core = CoreStorage.layout();

if (core.channels[PRIMARY_GOVERNANCE_CHANNEL_ID].agent != address(0)) {
revert AlreadyInitialized();
}

core.mode = config.mode;

// Initialize agent for BridgeHub
Expand Down
59 changes: 59 additions & 0 deletions contracts/test/Gateway.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -496,6 +496,65 @@ contract GatewayTest is Test {
assertEq(GatewayV2(address(gateway)).getValue(), 42);
}

function testUgradeInitializerRunsOnlyOnce() public {
// Upgrade to this current logic contract
AgentExecutor executor = new AgentExecutor();
GatewayMock currentLogic =
new GatewayMock(address(0), address(executor), bridgeHubParaID, bridgeHubAgentID, foreignTokenDecimals);

Gateway.Config memory config = Gateway.Config({
mode: OperatingMode.Normal,
deliveryCost: outboundFee,
registerTokenFee: registerTokenFee,
assetHubParaID: assetHubParaID,
assetHubAgentID: assetHubAgentID,
assetHubCreateAssetFee: createTokenFee,
assetHubReserveTransferFee: sendTokenFee,
exchangeRate: exchangeRate
});

UpgradeParams memory params = UpgradeParams({
impl: address(currentLogic),
implCodeHash: address(currentLogic).codehash,
initParams: abi.encode(config)
});

vm.expectRevert(Gateway.AlreadyInitialized.selector);
// Expect the gateway to emit `Upgraded`
GatewayMock(address(gateway)).upgradePublic(abi.encode(params));
}

function testUpgradeSkipsInitializerIfNoneProvided() public {
bytes32 agentID = keccak256("123");

testSetPricingParameters();
uint256 fee = IGateway(address(gateway)).quoteRegisterTokenFee();
assertEq(fee, 10000000000000000);

testCreateAgent();
assertNotEq(GatewayMock(address(gateway)).agentOf(agentID), address(0));

// Upgrade to this current logic contract
AgentExecutor executor = new AgentExecutor();
GatewayMock currentLogic =
new GatewayMock(address(0), address(executor), bridgeHubParaID, bridgeHubAgentID, foreignTokenDecimals);

bytes memory initParams; // empty
UpgradeParams memory params = UpgradeParams({
impl: address(currentLogic),
implCodeHash: address(currentLogic).codehash,
initParams: initParams
});

// Expect the gateway to emit `Upgraded`
GatewayMock(address(gateway)).upgradePublic(abi.encode(params));

// Verify that storage was not overwritten
fee = IGateway(address(gateway)).quoteRegisterTokenFee();
assertEq(fee, 10000000000000000);
assertNotEq(GatewayMock(address(gateway)).agentOf(agentID), address(0));
}

function testUpgradeGatewayMock() public {
GatewayUpgradeMock newLogic = new GatewayUpgradeMock();
uint256 d0 = 99;
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/.gitbook/assets/image (2).png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions docs/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,6 @@
## Runbooks

* [Updating Snowbridge Pallets, BridgeHub & AssetHub Runtimes](runbooks/updating-snowbridge-pallets-bridgehub-and-assethub-runtimes.md)
* [Initialize Ethereum light client with Forced Checkpoint](runbooks/initialize-ethereum-light-client-with-forced-checkpoint.md)
* [Initial Deployment of Gateway Contracts](runbooks/initial-deployment-of-gateway-contracts.md)
* [Halt Bridge in Case of Emergency](runbooks/halt-bridge-in-case-of-emergency.md)
6 changes: 3 additions & 3 deletions docs/rococo-testnet/rococo-sepolia-token-transfers.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ Snowbridge has initially only activated support for the sending of ERC20 tokens

If you already have [WETH](https://sepolia.etherscan.io/address/0xfFf9976782d46CC05630D1f6eBAb18b2324d6B14) you can skip this step. If not go to the [WETH](https://sepolia.etherscan.io/address/0xfFf9976782d46CC05630D1f6eBAb18b2324d6B14) contract and make a deposit.

Weth Contract Address: [0xfFf9976782d46CC05630D1f6eBAb18b2324d6B14](https://sepolia.etherscan.io/address/0xfFf9976782d46CC05630D1f6eBAb18b2324d6B14)
WETH Contract Address: [0xfFf9976782d46CC05630D1f6eBAb18b2324d6B14](https://sepolia.etherscan.io/address/0xfFf9976782d46CC05630D1f6eBAb18b2324d6B14)

1. Click on the Contracts tab.
2. Click on the Write Contract tab.
Expand All @@ -28,11 +28,11 @@ Weth Contract Address: [0xfFf9976782d46CC05630D1f6eBAb18b2324d6B14](https://sepo

Snowbridge needs to be an approved spender for you to send tokens to Polkadot.

Gateway Contract Address: [0x5b4909ce6ca82d2ce23bd46738953c7959e710cd](https://sepolia.etherscan.io/address/0x5b4909ce6ca82d2ce23bd46738953c7959e710cd)
WETH Contract Address: [0xfFf9976782d46CC05630D1f6eBAb18b2324d6B14](https://sepolia.etherscan.io/address/0xfFf9976782d46CC05630D1f6eBAb18b2324d6B14)

Navigate to the Contract tab, click on Write Contract, and connect your wallet.

1. Enter Snowbridge’s Gateway contract as the `guy` (spender) parameter.
1. Enter Snowbridge’s Gateway contract as the `guy` (spender) parameter. Gateway Contract Address: [0x5b4909ce6ca82d2ce23bd46738953c7959e710cd](https://sepolia.etherscan.io/address/0x5b4909ce6ca82d2ce23bd46738953c7959e710cd)
2. Enter the amount that Snowbridge can spend as the `wad` parameter. In this example, we have used 5 Gwei (5000000000 Wei).

<figure><img src="../.gitbook/assets/approve_weth.png" alt=""><figcaption></figcaption></figure>
Expand Down
27 changes: 27 additions & 0 deletions docs/runbooks/halt-bridge-in-case-of-emergency.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
---
description: >-
In a case of an emergency (e.g. a exploitable vulnerability found), the bridge
needs to be halted so that no messages can be processed.
---

# Halt Bridge in Case of Emergency

### Halting Mechanism

The bridge is halted through a storage item in each Snowbridge pallet called `OperatingMode` .

Possible operating mode states are:

* `Normal`
* `Halted` (`RejectingOutboundMessages` for the `system` pallet)

If the operating mode is set to [`Halted`](https://github.com/Snowfork/polkadot-sdk/blob/2536e780bf6af052e1d9e85a8b2648aae91ec6d7/bridges/snowbridge/primitives/core/src/operating\_mode.rs#L12), no bridge messages will be processed. Each pallet needs to be disabled individually. Here are the pallets that need to be disabled, with the call hash to do so:

* Ethereum client pallet: `0x520301`
* Inbound queue pallet: `0x500101`
* Outbound queue pallet: `0x510001`
* Ethereum system pallet: `0x530101`

These extrinsics should be done from the relay chain, descending to the BridgeHub parachain origin, similar to the [force beacon checkpoint call](https://app.gitbook.com/o/bDGMcdShFBeGc3v6VzHf/s/tC80IPpnYgEJmgOYIpqZ/\~/changes/72/runbooks/initialize-ethereum-light-client-with-forced-checkpoint).

If the bridge was halted, no messages will be processed. When the operating mode is changed to `normal` messages will be continue being processed.
85 changes: 85 additions & 0 deletions docs/runbooks/initial-deployment-of-gateway-contracts.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
---
description: >-
How to upgrade the Ethereum gateway controlling the bridge on the Ethereum
side.
---

# Initial Deployment of Gateway Contracts

### Build and Deploy Contracts

To build and deploy the new contracts, follow these steps from inside the [Snowbridge repository](https://github.com/snowfork/snowbridge):

#### Generate BEEFY State

Set the following in .env file:

```bash
export RELAYCHAIN_ENDPOINT= <relay chain endpoint>
export BEEFY_START_BLOCK= # default is 1
```

The BEEFY start block can be selected from a recent block that has a BEEFY commitment.

Run `scripts/generate-beefy-checkoutpoint.sh`. This will leave the beefy state in the contracts folder.

#### Deploy Contracts

Set the following in .env file:

```bash
# Secret
export INFURA_PROJECT_ID=<secret>
export ETHERSCAN_API_KEY=<secret>
export DEPLOYER_ETH_KEY=<secret>

# Chain
export ETH_NETWORK=< sepolia /mainnet >
export ETH_NETWORK_ID=< 11155111 /1 >

# Endpoints
export RELAYCHAIN_ENDPOINT=wss://rococo-rpc.polkadot.io
export ETH_RPC_ENDPOINT=https://sepolia.infura.io/v3
export ETH_WS_ENDPOINT=wss://sepolia.infura.io/ws/v3
export BEACON_HTTP_ENDPOINT=https://lodestar-sepolia.chainsafe.io

# Beefy
export BEEFY_START_BLOCK=8592280 # Default value
export MINIMUM_REQUIRED_SIGNATURES=16
export ETH_RANDAO_DELAY=128 # 4 epochs=128 slots=25.6mins
export ETH_RANDAO_EXP=6 # 6 slots before expired

# Channels and Agents
export BRIDGE_HUB_PARAID=1013
export BRIDGE_HUB_AGENT_ID=0x03170a2e7597b7b7e3d84c05391d139a62b157e78786d8c082f29dcf4c111314
export ASSET_HUB_PARAID=1000
export ASSET_HUB_AGENT_ID=0x81c5ab2571199e3188135178f3c2c8e2d268be1313d029b30f534fa579b69b79
export REJECT_OUTBOUND_MESSAGES=false

# Fees
export CREATE_ASSET_FEE=10000000000
export DELIVERY_COST=10000000000
export EXCHANGE_RATE=25000000000000
export REGISTER_TOKEN_FEE=5000000000000000000
export RESERVE_TRANSFER_FEE=10000000000

export FOREIGN_TOKEN_DECIMALS=12

# Initial agents deposits. Set low on purpose as they can be topped up manually
export ETH_BRIDGE_HUB_INITIAL_DEPOSIT=1000000
```

Run `scripts/deploy-contracts.sh`

Back up `contracts.json` and contract artifacts to s3: [https://s3.console.aws.amazon.com/s3/buckets/snowbridge-rococo-demo?region=eu-central-1\&bucketType=general\&tab=objects](https://s3.console.aws.amazon.com/s3/buckets/snowbridge-rococo-demo?region=eu-central-1\&bucketType=general\&tab=objects)

Confirm settings with the team and get ETH for the deployment.&#x20;

Add contracts to tenderly

### Update the EthereumGatewayAddress on BridgeHub

To update the `EthereumGateway` [contract address](https://github.com/Snowfork/polkadot-sdk/blob/snowbridge/bridges/snowbridge/pallets/inbound-queue/src/lib.rs#L112), a set storage call is executed:

* Example call hash: `0xff00630003000100d50f03082f000006020700c817a804824f1200a400040440aed97c7854d601808b98ae43079dafb3505b4909ce6ca82d2ce23bd46738953c7959e710cd`
* Link to pre-populate on Rococo: [https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Frococo-rpc.polkadot.io#/extrinsics/decode/0xff00630003000100d50f03082f000006020700c817a804824f1200a400040440aed97c7854d601808b98ae43079dafb3505b4909ce6ca82d2ce23bd46738953c7959e710cd](https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Frococo-rpc.polkadot.io#/extrinsics/decode/0xff00630003000100d50f03082f000006020700c817a804824f1200a400040440aed97c7854d601808b98ae43079dafb3505b4909ce6ca82d2ce23bd46738953c7959e710cd\))
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
---
description: >-
Generate a beacon checkpoint to sync the Ethereum client from. This is done on
bridge initialization or forced sync reset.
---

# Initialize Ethereum light client with Forced Checkpoint

## Generate Checkpoint Data

On the server where the relayer is deployed, run the following command:

```
relayer/build/snowbridge-relay generate-beacon-checkpoint --url http://127.0.0.1:9596
```

The command will output the beacon checkpoint data in hex form. Prepend `0x5200` to the resulting hex (the [Ethereum client pallet index](https://github.com/Snowfork/polkadot-sdk/blob/snowbridge/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs#L730) and the `force_checkpoint` [call index](https://github.com/Snowfork/polkadot-sdk/blob/snowbridge/bridges/snowbridge/pallets/ethereum-client/src/lib.rs#L216) combined).

### Call Force Checkpoint from Relay Chain

Use the resulting call data to make the Transact call to set the beacon checkpoint.

* call hash: `0xff00630003000100d50f03082f00000602070008d6e82982ee3600a5025200821017d7c8b03a2a182824cfe569187a28faa718368a0ace36e2b1b8b6dbd7f8093c0594aa8a9c557dabac173fac324158e77fb5840738a1a541f633cbec8884c6a601c567d2b376a05392000000000000000002101851a76c1adff357d59b36327d02cfb7f718368a0ace36e2b1b8b6dbd7f8093c0594aa8a9c557dabac173fac324158e77fb5840738a1a541f633cbec8884c6a601c567d2b376a05392000000000000000000`
* link to pre-populate on Rococo: [https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Frococo-rpc.polkadot.io#/extrinsics/decode/0xff00630003000100d50f03082f00000602070008d6e82982ee3600a5025200821017d7c8b03a2a182824cfe569187a28faa718368a0ace36e2b1b8b6dbd7f8093c0594aa8a9c557dabac173fac324158e77fb5840738a1a541f633cbec8884c6a601c567d2b376a05392000000000000000002101851a76c1adff357d59b36327d02cfb7f718368a0ace36e2b1b8b6dbd7f8093c0594aa8a9c557dabac173fac324158e77fb5840738a1a541f633cbec8884c6a601c567d2b376a05392000000000000000000](https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Frococo-rpc.polkadot.io#/extrinsics/decode/0xff00630003000100d50f03082f00000602070008d6e82982ee3600a5025200821017d7c8b03a2a182824cfe569187a28faa718368a0ace36e2b1b8b6dbd7f8093c0594aa8a9c557dabac173fac324158e77fb5840738a1a541f633cbec8884c6a601c567d2b376a05392000000000000000002101851a76c1adff357d59b36327d02cfb7f718368a0ace36e2b1b8b6dbd7f8093c0594aa8a9c557dabac173fac324158e77fb5840738a1a541f633cbec8884c6a601c567d2b376a05392000000000000000000)

Replace the encoded call bytes highlighted in the screenshot below with the checkpoint data generated in the previous step:

<figure><img src="../.gitbook/assets/Screenshot 2024-02-16 at 11.21.53.png" alt=""><figcaption><p>Replace encoded call bytes with hex generated in the first step.</p></figcaption></figure>





Original file line number Diff line number Diff line change
Expand Up @@ -87,8 +87,8 @@ Configuration items to periodically configure for Snowbridge:

These items would require a referenda item to be created on OpenGov.

TBH Items:
TBC Items:

* Which wallet will be used to create the referenda? Snowfork team members personal wallets?
* Which wallet will be used to create the referenda?
* Exact steps to create referenda (e.g. extrinsic, renferenda on Polkassembly)
* Where is the voting and enactment periods set?
* Confirm where voting and enactment periods are set?
25 changes: 21 additions & 4 deletions web/packages/test/scripts/deploy-contracts.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ set -eu

source scripts/set-env.sh

deploy_contracts()
{
deploy_command() {
local deploy_script=$1

pushd "$contract_dir"
if [ "$eth_network" != "localhost" ]; then
forge script \
Expand All @@ -13,15 +14,31 @@ deploy_contracts()
--verify \
--etherscan-api-key $etherscan_api_key \
-vvv \
src/DeployScript.sol:DeployScript
$deploy_script
else
forge script \
--rpc-url $eth_endpoint_http \
--broadcast \
-vvv \
src/DeployScript.sol:DeployScript
$deploy_script
fi
popd
}

deploy_gateway_logic()
{
deploy_command src/DeployGatewayLogic.sol:DeployGatewayLogic

pushd "$test_helpers_dir"
pnpm generateContracts "$output_dir/contracts.json"
popd

echo "Exported contract artifacts: $output_dir/contracts.json"
}

deploy_contracts()
{
deploy_command src/DeployScript.sol:DeployScript

pushd "$test_helpers_dir"
pnpm generateContracts "$output_dir/contracts.json"
Expand Down

0 comments on commit 2e4140c

Please sign in to comment.