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

Deploy: blast SynapseRouter with verification #319

Merged
merged 6 commits into from
Mar 29, 2024
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
2 changes: 1 addition & 1 deletion deployments/blast/SynapseRouter.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"address": "0x7E7A0e201FD38d3ADAA9523Da6C109a07118C96a",
"address": "0x0000000000365b1d5B142732CF4d33BcddED21Fc",
"constructorArgs": "0x00000000000000000000000055769baf6ec39b3bf4aae948eb890ea33307ef3c0000000000000000000000000fea3e5840334fc758a3decf14546bfdfbef5cd3",
"abi": [
{
Expand Down
3 changes: 0 additions & 3 deletions script/bytecode/SwapQuoter.json

This file was deleted.

5 changes: 5 additions & 0 deletions script/configs/Create2Factory.salts.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,10 @@
"initCodeHash": "0xa57ff234acc44680bd95296290c915c556b5cf30c8c2a843962585fdb607c3ed",
"predictedAddress": "0x0000000000489d89D2B233D3375C045dfD05745F",
"salt": "0x0000000000000000000000000000000000000000a887a859fa44720198162f0e"
},
"SynapseRouter": {
"initCodeHash": "0x4e3652671a68c0263a6844cbfabcab93d1a951bdc4b7983183b99f74308383e0",
"predictedAddress": "0x0000000000365b1d5B142732CF4d33BcddED21Fc",
"salt": "0x000000000000000000000000000000000000000090f74d8e39833b00b2808238"
}
}
10 changes: 10 additions & 0 deletions script/configs/blast/SynapseRouter.dc.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,19 @@
"bridge": "0x55769bAF6ec39B3bf4aAE948eB890eA33307Ef3C",
"ids": [
"nUSD",
"SYN",
"nETH"
],
"tokens": {
"SYN": {
"bridgeFee": 10000000,
"bridgeToken": "0x9592f08387134e218327E6E8423400eb845EdE0E",
"decimals": 18,
"maxFee": "0x000000000000000000000000000000000000000000032dcba101cb7220c6938c",
"minFee": "0x0000000000000000000000000000000000000000000000008ac7230489e80000",
"token": "0x9592f08387134e218327E6E8423400eb845EdE0E",
"tokenType": 0
},
"nETH": {
"bridgeFee": 1000000,
"bridgeToken": "0xce971282fAAc9faBcF121944956da7142cccC855",
Expand Down
26 changes: 26 additions & 0 deletions script/router/DeployRouterV1.CREATE2.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

import {BasicSynapseScript, console2} from "../templates/BasicSynapse.s.sol";

contract DeployRouterV1CREATE2 is BasicSynapseScript {
function run() external {
// Setup the BasicSynapseScript
setUp();
vm.startBroadcast();
// Use `deployCreate2` as callback to deploy the contract with CREATE2
// This will load deployment salt from the pre-saved list, if there's an entry for the contract
deployAndSave({
contractName: "SynapseRouter",
constructorArgs: getConstructorArgs(),
deployCode: deploySolcGeneratedCreate2
});
vm.stopBroadcast();
}

function getConstructorArgs() internal returns (bytes memory constructorArgs) {
address bridge = getDeploymentAddress("SynapseBridge");
address owner = vm.envAddress("OWNER_ADDR");
constructorArgs = abi.encode(bridge, owner);
}
}
18 changes: 8 additions & 10 deletions script/router/DeployRouterV1.s.sol
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.6.12;
pragma experimental ABIEncoderV2;

import {SynapseRouter} from "../../contracts/bridge/router/SynapseRouter.sol";
pragma solidity 0.8.17;

import {BasicSynapseScript, console2} from "../templates/BasicSynapse.s.sol";

Expand All @@ -14,7 +11,12 @@ contract DeployRouterV1 is BasicSynapseScript {
setUp();
vm.startBroadcast();
skipToNonce(routerNonce);
deployAndSave({contractName: "SynapseRouter", deployContract: cbDeployRouterV1});
bytes memory constructorArgs = getConstructorArgs();
deployAndSave({
contractName: "SynapseRouter",
constructorArgs: constructorArgs,
deployCode: deploySolcGenerated
});
vm.stopBroadcast();
}

Expand All @@ -36,13 +38,9 @@ contract DeployRouterV1 is BasicSynapseScript {
console2.log("Deployer nonce is %s", nonce);
}

/// @notice Callback function to deploy the SynapseRouter contract.
/// Must follow this signature for the deploy script to work:
/// `deployContract() internal returns (address deployedAt, bytes memory constructorArgs)`
function cbDeployRouterV1() internal returns (address deployedAt, bytes memory constructorArgs) {
function getConstructorArgs() internal returns (bytes memory constructorArgs) {
address bridge = getDeploymentAddress("SynapseBridge");
address owner = vm.envAddress("OWNER_ADDR");
deployedAt = address(new SynapseRouter(bridge, owner));
constructorArgs = abi.encode(bridge, owner);
}
}
11 changes: 11 additions & 0 deletions script/router/deploy-router.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#!/usr/bin/env bash
# This script will deploy SynapseRouter and its auxilary contracts on the given chain.
# Deployment address on every chain will depend on the deployer address initial nonce.
# Existing deployments will be reused rather than overwritten.

# Usage: ./script/router/deploy-router.sh <chainName> <walletName> [<options...>]

# Temp fix until Foundry bytecode matches solc bytecode EXACTLY
./script/sh/solc.sh SynapseRouter
# Pass the full list of arguments to the run script
./script/run.sh ./script/router/DeployRouterV1.s.sol "$@"
6 changes: 3 additions & 3 deletions script/sh/bytecode.sh → script/sh/solc.sh
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#!/usr/bin/env bash
# This script saves bytecode for a contract into "./script/bytecode/<contract>.json"
# Usage: ./script/sh/bytecode.sh <contract>
# This script saves bytecode for a contract into "./script/solc/<contract>.json"
# Usage: ./script/sh/solc.sh <contract>
Comment on lines +2 to +3
Copy link

Choose a reason for hiding this comment

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

The script's purpose is clearly stated, and the usage message is helpful. However, ensure that the directory ./script/solc/ is created before attempting to save bytecode files to it, as the script does not currently check for or create the directory if it does not exist.


YELLOW='\033[0;33m'
NC='\033[0m' # No Color
Expand All @@ -20,7 +20,7 @@ key=$(jq ".contracts | keys[] | select(endswith($keyFilter))" temp.out.json)
# Get the bytecode
bytecode="0x"$(jq -r ".contracts.$key.$1.evm.bytecode.object" temp.out.json)
# Save the bytecode
jq -n ".bytecode = \"$bytecode\"" >script/bytecode/$1.json
jq -n ".bytecode = \"$bytecode\"" >script/solc/$1.json
# Clean temp files
rm temp.in.json
rm temp.out.json

Large diffs are not rendered by default.

40 changes: 37 additions & 3 deletions script/templates/BasicSynapse.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -109,13 +109,31 @@ contract BasicSynapseScript is BasicUtils {
function deploy(string memory contractName, bytes memory constructorArgs) internal returns (address deployedAt) {
// Init code is the contract bytecode with constructor args appended
bytes memory initCode = abi.encodePacked(getContractBytecode(contractName), constructorArgs);
deployedAt = deployCode(initCode);
}

/// @notice Creates a contract with the given name and constructor args.
/// Bytecode generated by utilizing `solc` directly instead of forge is used for the deployment (see sh/solc.sh).
/// Note: could be used as callback for `deployAndSave` and `deployAndSaveAs`
/// for contracts with a different compiler version.
function deploySolcGenerated(string memory contractName, bytes memory constructorArgs)
internal
returns (address deployedAt)
{
// Init code is the contract bytecode with constructor args appended
bytes memory initCode = abi.encodePacked(getSolcBytecode(contractName), constructorArgs);
deployedAt = deployCode(initCode);
}

/// @notice Deploys a contract with the given init code.
function deployCode(bytes memory initCode) internal returns (address deployedAt) {
// Use assembly to deploy the contract
// solhint-disable-next-line no-inline-assembly
assembly {
// Add 0x20 to skip the length field of initCode
deployedAt := create(0, add(initCode, 0x20), mload(initCode))
}
require(deployedAt != address(0), StringUtils.concat("Deployment failed: ", contractName));
require(deployedAt != address(0), "Deployment failed");
}

/// @notice Creates a contract with the given name and constructor args.
Expand All @@ -133,14 +151,30 @@ contract BasicSynapseScript is BasicUtils {
nextDeploymentSalt = loadDeploymentSalt(initCode, contractName);
}
deployedAt = factoryDeployCreate2(initCode, nextDeploymentSalt);
// Erase the salt after the deployment
nextDeploymentSalt = 0;
}

/// @notice Creates a contract with the given name and constructor args.
/// Bytecode generated by utilizing `solc` directly instead of forge is used for the deployment (see sh/solc.sh).
/// Deployment is done in a deterministic way, using create2 and salt saved in `nextDeploymentSalt`.
/// Note: could be used as callback for `deployAndSave` and `deployAndSaveAs`.
function deploySolcGeneratedCreate2(string memory contractName, bytes memory constructorArgs)
internal
returns (address deployedAt)
{
// Init code is the contract bytecode with constructor args appended
bytes memory initCode = abi.encodePacked(getSolcBytecode(contractName), constructorArgs);
// If no salt was provided, try reading it from the pre-saved list
if (nextDeploymentSalt == 0) {
nextDeploymentSalt = loadDeploymentSalt(initCode, contractName);
}
deployedAt = factoryDeployCreate2(initCode, nextDeploymentSalt);
}

/// @notice Creates a contract with the given init code.
/// Deployment is done in a deterministic way, using create2 and the given salt.
/// Note: does not save the deployment JSON.
function factoryDeployCreate2(bytes memory initCode, bytes32 salt) internal returns (address deployedAt) {
console2.log("Using initCodeHash: %s", vm.toString(keccak256(initCode)));
// Get address of the factory on the active chain
address factory = getDeploymentAddress(MINIMAL_CREATE2_FACTORY);
assertContractCodeExists(MINIMAL_CREATE2_FACTORY, factory);
Expand Down
9 changes: 8 additions & 1 deletion script/templates/BasicUtils.sol
Original file line number Diff line number Diff line change
Expand Up @@ -113,10 +113,17 @@ abstract contract BasicUtils is CommonBase {
}

/// @notice Returns the contract bytecode extracted from the artifact generated by forge.
function getContractBytecode(string memory contractName) internal returns (bytes memory bytecode) {
function getContractBytecode(string memory contractName) internal view returns (bytes memory bytecode) {
return getContractArtifact(contractName).readBytes(".bytecode.object");
}

/// @notice Returns the contract bytecode generated by using solc directly.
function getSolcBytecode(string memory contractName) internal view returns (bytes memory bytecode) {
string memory bytecodeFN = StringUtils.concat("script/solc/", contractName, ".json");
string memory bytecodeJSON = vm.readFile(bytecodeFN);
return bytecodeJSON.readBytes(".bytecode");
}

// ═════════════════════════════════════════════ CHAIN ID GETTERS ══════════════════════════════════════════════════

/// @notice Returns the chain ID for a given chain by reading the chain ID file in the deployments directory.
Expand Down
Loading