Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Deployment scripts for BeefyClient & Gateway #1190

Merged
merged 12 commits into from
May 23, 2024
Merged
Show file tree
Hide file tree
Changes from 5 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
2 changes: 1 addition & 1 deletion contracts/scripts/Deploy.sol
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,4 @@ contract Stage1 is Script {

vm.stopBroadcast();
}
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: whitespace

61 changes: 61 additions & 0 deletions contracts/scripts/DeployBeefyClient.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
// SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: 2023 Snowfork <[email protected]>
pragma solidity 0.8.23;

import {Script} from "forge-std/Script.sol";
import {stdJson} from "forge-std/StdJson.sol";

import {WETH9} from "canonical-weth/WETH9.sol";
import {BeefyClient} from "../src/BeefyClient.sol";

import {IGateway} from "../src/interfaces/IGateway.sol";
import {GatewayProxy} from "../src/GatewayProxy.sol";
import {Gateway} from "../src/Gateway.sol";
import {MockGatewayV2} from "../test/mocks/MockGatewayV2.sol";
import {Agent} from "../src/Agent.sol";
import {AgentExecutor} from "../src/AgentExecutor.sol";
import {ChannelID, ParaID, OperatingMode} from "../src/Types.sol";
import {SafeNativeTransfer} from "../src/utils/SafeTransfer.sol";
import {UD60x18, ud60x18} from "prb/math/src/UD60x18.sol";

contract DeployBeefyClient is Script {
using SafeNativeTransfer for address payable;
using stdJson for string;

struct Config {
uint64 startBlock;
BeefyClient.ValidatorSet current;
BeefyClient.ValidatorSet next;
uint256 randaoCommitDelay;
uint256 randaoCommitExpiration;
uint256 minimumSignatures;
}

function readConfig() internal pure returns (Config memory config) {
// TODO: When we are ready to commit to checkpoint, run the following to compute the checkpoint
// (cd web/packages/test-helpers; BEEFY_BLOCK=... npx npx ts-node src/generateBeefyCheckpointProd.ts)
// Substitute `startBlock`, `current`, `next` below
config = Config({
startBlock: 0,
current: BeefyClient.ValidatorSet({id: 0, length: 0, root: 0}),
next: BeefyClient.ValidatorSet({id: 0, length: 0, root: 0}),
randaoCommitDelay: 128,
vgeddes marked this conversation as resolved.
Show resolved Hide resolved
randaoCommitExpiration: 24,
minimumSignatures: 17
});
}

function run() public {
vm.startBroadcast();
Config memory config = readConfig();

new BeefyClient(
config.randaoCommitDelay,
config.randaoCommitExpiration,
config.minimumSignatures,
config.startBlock,
config.current,
config.next
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {ParaID} from "../src//Types.sol";
import {Script} from "forge-std/Script.sol";
import {stdJson} from "forge-std/StdJson.sol";

contract DeployGatewayLogic is Script {
contract DeployLocalGatewayLogic is Script {
using stdJson for string;

function setUp() public {}
Expand Down
90 changes: 90 additions & 0 deletions contracts/scripts/UpgradeShell.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
// SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: 2023 Snowfork <[email protected]>
pragma solidity 0.8.23;

import {WETH9} from "canonical-weth/WETH9.sol";
import {Script} from "forge-std/Script.sol";
import {BeefyClient} from "../src/BeefyClient.sol";

import {IGateway} from "../src/interfaces/IGateway.sol";
import {IShell} from "../src/interfaces/IShell.sol";
import {GatewayProxy} from "../src/GatewayProxy.sol";
import {Gateway} from "../src/Gateway.sol";
import {MockGatewayV2} from "../test/mocks/MockGatewayV2.sol";
import {Agent} from "../src/Agent.sol";
import {AgentExecutor} from "../src/AgentExecutor.sol";
import {ChannelID, ParaID, OperatingMode} from "../src/Types.sol";
import {SafeNativeTransfer} from "../src/utils/SafeTransfer.sol";
import {stdJson} from "forge-std/StdJson.sol";
import {UD60x18, ud60x18} from "prb/math/src/UD60x18.sol";

function mDot(uint32 value) pure returns (uint128) {
// 1 mDOT = 0.001 DOT
return value * (10 ** 7);
}

function dot(uint32 value) pure returns (uint128) {
return value * (10 ** 10);
}

contract UpgradeShell is Script {
using SafeNativeTransfer for address payable;
using stdJson for string;

struct Config {
address gatewayProxy;
address beefyClient;
ParaID bridgeHubParaID;
bytes32 bridgeHubAgentID;
uint8 foreignTokenDecimals;
uint128 maxDestinationFee;
Gateway.Config initializerParams;
}

function readConfig() internal pure returns (Config memory config) {
config = Config({
gatewayProxy: 0x27ca963C279c93801941e1eB8799c23f407d68e7,
beefyClient: address(0),
bridgeHubParaID: ParaID.wrap(1002),
bridgeHubAgentID: 0x03170a2e7597b7b7e3d84c05391d139a62b157e78786d8c082f29dcf4c111314,
foreignTokenDecimals: 10,
maxDestinationFee: dot(2),
initializerParams: Gateway.Config({
mode: OperatingMode.Normal,
deliveryCost: mDot(100), // 0.1 DOT
registerTokenFee: 0.002 ether,
assetHubParaID: ParaID.wrap(1000),
assetHubAgentID: 0x81c5ab2571199e3188135178f3c2c8e2d268be1313d029b30f534fa579b69b79,
assetHubCreateAssetFee: mDot(100), // 0.1 DOT
alistair-singh marked this conversation as resolved.
Show resolved Hide resolved
assetHubReserveTransferFee: mDot(100), // 0.1 DOT
exchangeRate: ud60x18(0.0024e18),
multiplier: ud60x18(1.33e18)
})
});
}

function run() public {
vm.startBroadcast();

Config memory config = readConfig();

// AgentExecutor
AgentExecutor executor = new AgentExecutor();

// Gateway implementation
Gateway gatewayLogic = new Gateway(
config.beefyClient,
address(executor),
config.bridgeHubParaID,
config.bridgeHubAgentID,
config.foreignTokenDecimals,
config.maxDestinationFee
);

IShell shell = IShell(config.gatewayProxy);

shell.upgrade(address(gatewayLogic), address(gatewayLogic).codehash, abi.encode(config.initializerParams));

vm.stopBroadcast();
}
}
20 changes: 0 additions & 20 deletions contracts/scripts/minsigs.py

This file was deleted.

31 changes: 30 additions & 1 deletion contracts/src/Gateway.sol
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ import {
import {CoreStorage} from "./storage/CoreStorage.sol";
import {PricingStorage} from "./storage/PricingStorage.sol";
import {AssetsStorage} from "./storage/AssetsStorage.sol";
import {OperatorStorage} from "./storage/OperatorStorage.sol";

import {UD60x18, ud60x18, convert} from "prb/math/src/UD60x18.sol";

Expand Down Expand Up @@ -416,7 +417,9 @@ contract Gateway is IGateway, IInitializable, IUpgradable {
uint128 amount
) external payable {
_submitOutbound(
Assets.sendToken(token, msg.sender, destinationChain, destinationAddress, destinationFee, MAX_DESTINATION_FEE, amount)
Assets.sendToken(
token, msg.sender, destinationChain, destinationAddress, destinationFee, MAX_DESTINATION_FEE, amount
)
);
}

Expand Down Expand Up @@ -612,5 +615,31 @@ contract Gateway is IGateway, IInitializable, IUpgradable {
assets.registerTokenFee = config.registerTokenFee;
assets.assetHubCreateAssetFee = config.assetHubCreateAssetFee;
assets.assetHubReserveTransferFee = config.assetHubReserveTransferFee;

// Initialize operator storage
OperatorStorage.Layout storage operatorStorage = OperatorStorage.layout();
operatorStorage.operator = 0x4B8a782D4F03ffcB7CE1e95C5cfe5BFCb2C8e967;
vgeddes marked this conversation as resolved.
Show resolved Hide resolved
}

/// @dev Temporary rescue ability for the initial bootstrapping phase of the bridge
function rescue(address impl, bytes32 implCodeHash, bytes calldata initializerParams) external {
OperatorStorage.Layout storage operatorStorage = OperatorStorage.layout();
if (msg.sender != operatorStorage.operator) {
revert Unauthorized();
}
Upgrade.upgrade(impl, implCodeHash, initializerParams);
}
vgeddes marked this conversation as resolved.
Show resolved Hide resolved

function dropRescueAbility() external {
OperatorStorage.Layout storage operatorStorage = OperatorStorage.layout();
if (msg.sender != operatorStorage.operator) {
revert Unauthorized();
}
operatorStorage.operator = address(0);
}

function rescueOperator() external view returns (address) {
OperatorStorage.Layout storage operatorStorage = OperatorStorage.layout();
return operatorStorage.operator;
}
}
20 changes: 20 additions & 0 deletions contracts/src/storage/OperatorStorage.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: 2023 Snowfork <[email protected]>
pragma solidity 0.8.23;

import {UD60x18} from "prb/math/src/UD60x18.sol";
vgeddes marked this conversation as resolved.
Show resolved Hide resolved

library OperatorStorage {
struct Layout {
address operator;
}

bytes32 internal constant SLOT = keccak256("org.snowbridge.storage.operator");

function layout() internal pure returns (Layout storage $) {
bytes32 slot = SLOT;
assembly {
$.slot := slot
}
}
}
43 changes: 35 additions & 8 deletions contracts/test/Gateway.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ import {SubstrateTypes} from "./../src/SubstrateTypes.sol";
import {MultiAddress} from "../src/MultiAddress.sol";
import {Channel, InboundMessage, OperatingMode, ParaID, Command, ChannelID, MultiAddress} from "../src/Types.sol";


import {NativeTransferFailed} from "../src/utils/SafeTransfer.sol";
import {PricingStorage} from "../src/storage/PricingStorage.sol";

Expand Down Expand Up @@ -99,12 +98,7 @@ contract GatewayTest is Test {
function setUp() public {
AgentExecutor executor = new AgentExecutor();
gatewayLogic = new MockGateway(
address(0),
address(executor),
bridgeHubParaID,
bridgeHubAgentID,
foreignTokenDecimals,
maxDestinationFee
address(0), address(executor), bridgeHubParaID, bridgeHubAgentID, foreignTokenDecimals, maxDestinationFee
);
Gateway.Config memory config = Gateway.Config({
mode: OperatingMode.Normal,
Expand Down Expand Up @@ -857,6 +851,39 @@ contract GatewayTest is Test {
IGateway(address(gateway)).quoteSendTokenFee(address(token), destPara, maxDestinationFee + 1);

vm.expectRevert(Assets.InvalidDestinationFee.selector);
IGateway(address(gateway)).sendToken{value: fee}(address(token), destPara, recipientAddress32, maxDestinationFee + 1, 1);
IGateway(address(gateway)).sendToken{value: fee}(
address(token), destPara, recipientAddress32, maxDestinationFee + 1, 1
);
}

function testRescuebyTrustedOperator() public {
// Upgrade to this new logic contract
MockGatewayV2 newLogic = new MockGatewayV2();

address impl = address(newLogic);
bytes32 implCodeHash = address(newLogic).codehash;
bytes memory initParams = abi.encode(42);

// Expect the gateway to emit `Upgraded`
vm.expectEmit(true, false, false, false);
emit IUpgradable.Upgraded(address(newLogic));

hoax(0x4B8a782D4F03ffcB7CE1e95C5cfe5BFCb2C8e967);
Gateway(address(gateway)).rescue(impl, implCodeHash, initParams);

// Verify that the MockGatewayV2.initialize was called
assertEq(MockGatewayV2(address(gateway)).getValue(), 42);
}

function testRescuebyPublicFails() public {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could make this test use dropRescueAbility to relinquish the rescuer address, and then try upgrade using the rescuer address. This will test both paths.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added a test in the latest upload

// Upgrade to this new logic contract
MockGatewayV2 newLogic = new MockGatewayV2();

address impl = address(newLogic);
bytes32 implCodeHash = address(newLogic).codehash;
bytes memory initParams = abi.encode(42);

vm.expectRevert(Gateway.Unauthorized.selector);
Gateway(address(gateway)).rescue(impl, implCodeHash, initParams);
}
}
2 changes: 1 addition & 1 deletion web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"private": true,
"engines": {
"node": "^20 || ^18",
"pnpm": "^8"
"pnpm": ">=8"
},
"scripts": {
"preinstall": "npx only-allow pnpm",
Expand Down
2 changes: 1 addition & 1 deletion web/packages/test-helpers/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
"generateBeefyFinalProof": "npx ts-node src/generateBeefyTestFixture.ts GenerateProofs"
},
"devDependencies": {
"@types/node": "^18.16.8",
"@typescript-eslint/eslint-plugin": "^5.42.0",
"@typescript-eslint/parser": "^5.42.0",
"eslint": "^8.26.0",
Expand All @@ -37,7 +38,6 @@
"@typechain/ethers-v5": "^10.1.1",
"@types/keccak": "^3.0.1",
"@types/lodash": "^4.14.186",
"@types/node": "^18.13.0",
"@types/secp256k1": "^4.0.3",
"@types/seedrandom": "^3.0.2",
"bitfield": "^4.1.0",
Expand Down
Loading