From cb6b1ff63c2f59fb891201392f2d399044831905 Mon Sep 17 00:00:00 2001 From: ChiTimesChi <88190723+ChiTimesChi@users.noreply.github.com> Date: Thu, 2 May 2024 15:02:41 +0100 Subject: [PATCH 1/3] Add generic script for SynERC20 deployment --- script/bridge/DeployConfigureSynERC20.s.sol | 110 ++++++++++++++++++++ script/configs/SynapseERC20.symbols.json | 9 ++ 2 files changed, 119 insertions(+) create mode 100644 script/bridge/DeployConfigureSynERC20.s.sol create mode 100644 script/configs/SynapseERC20.symbols.json diff --git a/script/bridge/DeployConfigureSynERC20.s.sol b/script/bridge/DeployConfigureSynERC20.s.sol new file mode 100644 index 000000000..9b5d5a891 --- /dev/null +++ b/script/bridge/DeployConfigureSynERC20.s.sol @@ -0,0 +1,110 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.6.12; +pragma experimental ABIEncoderV2; + +import {SynapseERC20Factory} from "../../contracts/bridge/SynapseERC20Factory.sol"; +import {SynapseERC20} from "../../contracts/bridge/SynapseERC20.sol"; + +import {BasicSynapseScript, StringUtils} from "../templates/BasicSynapse.s.sol"; + +import {stdJson} from "forge-std/StdJson.sol"; + +contract DeployConfigureSynERC20 is BasicSynapseScript { + using stdJson for string; + using StringUtils for string; + + string public config; + string public keyPrefix; + address public synapseERC20Impl; + SynapseERC20Factory public factory; + + SynapseERC20 public token; + address public multisig; + address public bridge; + + function run(string memory symbol) external { + // Setup the BasicSynapseScript + setUp(); + vm.startBroadcast(); + loadConfig(symbol); + token = SynapseERC20( + deployAndSaveAs({contractName: "SynapseERC20", contractAlias: symbol, deployContract: cbDeploySynapseERC20}) + ); + grantRoles(); + vm.stopBroadcast(); + checkRoles(); + } + + function loadConfig(string memory symbol) internal { + config = getGlobalConfig({contractName: "SynapseERC20", globalProperty: "symbols"}); + keyPrefix = StringUtils.concat(".", symbol, ".", activeChain); + + synapseERC20Impl = getDeploymentAddress("SynapseERC20"); + factory = SynapseERC20Factory(getDeploymentAddress("SynapseERC20Factory")); + + multisig = getDeploymentAddress("DevMultisig"); + bridge = getDeploymentAddress("SynapseBridge"); + } + + /// @notice Callback function to deploy the SynapseERC20 contract. + /// Must follow this signature for the deploy script to work: + /// `deployContract() internal returns (address deployedAt, bytes memory constructorArgs)` + function cbDeploySynapseERC20() internal returns (address deployedAt, bytes memory constructorArgs) { + deployedAt = factory.deploy({ + synapseERC20Address: synapseERC20Impl, + name: config.readString(keyPrefix.concat(".name")), + symbol: config.readString(keyPrefix.concat(".symbol")), + decimals: uint8(config.readUint(keyPrefix.concat(".decimals"))), + owner: msg.sender + }); + constructorArgs = ""; + } + + function grantRoles() internal { + printLog("Granting roles"); + bytes32 adminRole = token.DEFAULT_ADMIN_ROLE(); + bytes32 minterRole = token.MINTER_ROLE(); + if (!token.hasRole(adminRole, msg.sender)) { + printLog(TAB.concat("Skipping: ", vm.toString(msg.sender), " is not an admin")); + return; + } + + grantRole("DEFAULT_ADMIN_ROLE", adminRole, multisig); + grantRole("MINTER_ROLE", minterRole, bridge); + + token.renounceRole(adminRole, msg.sender); + printLog(TAB.concat("Renounced admin role for ", vm.toString(msg.sender))); + } + + function grantRole( + string memory roleName, + bytes32 role, + address account + ) internal { + if (!token.hasRole(role, account)) { + token.grantRole(role, account); + printLog(TAB.concat("Granted ", roleName, " to ", vm.toString(account))); + } else { + printLog(TAB.concat("Skipping: ", roleName, " already granted to ", vm.toString(account))); + } + } + + function checkRoles() internal { + printLog("Checking roles"); + increaseIndent(); + checkCondition(token.hasRole(token.DEFAULT_ADMIN_ROLE(), multisig), "DevMultisig is the admin"); + checkCondition(token.hasRole(token.MINTER_ROLE(), bridge), "SynapseBridge is the minter"); + checkCondition(token.getRoleMemberCount(token.DEFAULT_ADMIN_ROLE()) == 1, "Admin count is 1"); + checkCondition(token.getRoleMemberCount(token.MINTER_ROLE()) == 1, "Minter count is 1"); + decreaseIndent(); + } + + function checkCondition(bool condition, string memory message) internal { + if (condition) { + printLog(StringUtils.concat("✅ ", message)); + } else { + printLog(StringUtils.concat("❌ ", message)); + assert(false); + } + } +} diff --git a/script/configs/SynapseERC20.symbols.json b/script/configs/SynapseERC20.symbols.json new file mode 100644 index 000000000..703e1cceb --- /dev/null +++ b/script/configs/SynapseERC20.symbols.json @@ -0,0 +1,9 @@ +{ + "SPEC": { + "base": { + "decimals": 18, + "name": "Spectral Token", + "symbol": "SPEC" + } + } +} From e723602a9887865878b13f326cb8c6f5d429406b Mon Sep 17 00:00:00 2001 From: ChiTimesChi <88190723+ChiTimesChi@users.noreply.github.com> Date: Thu, 2 May 2024 15:06:55 +0100 Subject: [PATCH 2/3] Deploy SPEC --- deployments/base/SPEC.json | 669 +++++++++++++++++++++++++++++++++++++ 1 file changed, 669 insertions(+) create mode 100644 deployments/base/SPEC.json diff --git a/deployments/base/SPEC.json b/deployments/base/SPEC.json new file mode 100644 index 000000000..fe54b6d29 --- /dev/null +++ b/deployments/base/SPEC.json @@ -0,0 +1,669 @@ +{ + "address": "0x96419929d7949D6A801A6909c145C8EEf6A40431", + "constructorArgs": "0x", + "abi": [ + { + "type": "function", + "name": "DEFAULT_ADMIN_ROLE", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "DOMAIN_SEPARATOR", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "MINTER_ROLE", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "allowance", + "inputs": [ + { + "name": "owner", + "type": "address", + "internalType": "address" + }, + { + "name": "spender", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "approve", + "inputs": [ + { + "name": "spender", + "type": "address", + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "balanceOf", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "burn", + "inputs": [ + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "burnFrom", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "decimals", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "uint8", + "internalType": "uint8" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "decreaseAllowance", + "inputs": [ + { + "name": "spender", + "type": "address", + "internalType": "address" + }, + { + "name": "subtractedValue", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "getRoleAdmin", + "inputs": [ + { + "name": "role", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "outputs": [ + { + "name": "", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getRoleMember", + "inputs": [ + { + "name": "role", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "index", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getRoleMemberCount", + "inputs": [ + { + "name": "role", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "grantRole", + "inputs": [ + { + "name": "role", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "account", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "hasRole", + "inputs": [ + { + "name": "role", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "account", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "increaseAllowance", + "inputs": [ + { + "name": "spender", + "type": "address", + "internalType": "address" + }, + { + "name": "addedValue", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "initialize", + "inputs": [ + { + "name": "name", + "type": "string", + "internalType": "string" + }, + { + "name": "symbol", + "type": "string", + "internalType": "string" + }, + { + "name": "decimals", + "type": "uint8", + "internalType": "uint8" + }, + { + "name": "owner", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "mint", + "inputs": [ + { + "name": "to", + "type": "address", + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "name", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "string", + "internalType": "string" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "nonces", + "inputs": [ + { + "name": "owner", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "permit", + "inputs": [ + { + "name": "owner", + "type": "address", + "internalType": "address" + }, + { + "name": "spender", + "type": "address", + "internalType": "address" + }, + { + "name": "value", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "deadline", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "v", + "type": "uint8", + "internalType": "uint8" + }, + { + "name": "r", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "s", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "renounceRole", + "inputs": [ + { + "name": "role", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "account", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "revokeRole", + "inputs": [ + { + "name": "role", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "account", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "symbol", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "string", + "internalType": "string" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "totalSupply", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "transfer", + "inputs": [ + { + "name": "recipient", + "type": "address", + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "transferFrom", + "inputs": [ + { + "name": "sender", + "type": "address", + "internalType": "address" + }, + { + "name": "recipient", + "type": "address", + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "event", + "name": "Approval", + "inputs": [ + { + "name": "owner", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "spender", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "value", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "RoleAdminChanged", + "inputs": [ + { + "name": "role", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + }, + { + "name": "previousAdminRole", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + }, + { + "name": "newAdminRole", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "RoleGranted", + "inputs": [ + { + "name": "role", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + }, + { + "name": "account", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "sender", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "RoleRevoked", + "inputs": [ + { + "name": "role", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + }, + { + "name": "account", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "sender", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "Transfer", + "inputs": [ + { + "name": "from", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "to", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "value", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + } + ] +} \ No newline at end of file From b415fdbd183633a9f266f273b6be3cf57fe78bdb Mon Sep 17 00:00:00 2001 From: ChiTimesChi <88190723+ChiTimesChi@users.noreply.github.com> Date: Fri, 3 May 2024 23:37:38 +0100 Subject: [PATCH 3/3] Save new Router configs --- script/configs/base/SynapseRouter.dc.json | 14 ++++++++++++-- script/configs/mainnet/SynapseRouter.dc.json | 12 +++++++++++- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/script/configs/base/SynapseRouter.dc.json b/script/configs/base/SynapseRouter.dc.json index 8809ac46e..739820748 100644 --- a/script/configs/base/SynapseRouter.dc.json +++ b/script/configs/base/SynapseRouter.dc.json @@ -3,9 +3,19 @@ "ids": [ "SYN", "nETH", - "UNIDX" + "UNIDX", + "SPEC" ], "tokens": { + "SPEC": { + "bridgeFee": 5000000, + "bridgeToken": "0x96419929d7949D6A801A6909c145C8EEf6A40431", + "decimals": 18, + "maxFee": "0x000000000000000000000000000000000000000000032dcba101cb7220c6938c", + "minFee": "0x00000000000000000000000000000000000000000000000006f05b59d3b20000", + "token": "0x96419929d7949D6A801A6909c145C8EEf6A40431", + "tokenType": 0 + }, "SYN": { "bridgeFee": 5000000, "bridgeToken": "0x432036208d2717394d2614d6697c46DF3Ed69540", @@ -29,7 +39,7 @@ "bridgeToken": "0xb554A55358fF0382Fb21F0a478C3546d1106Be8c", "decimals": 18, "maxFee": "0x000000000000000000000000000000000000000000032dcba101cb7220c6938c", - "minFee": "0x0000000000000000000000000000000000000000000000000001c6bf52634000", + "minFee": "0x00000000000000000000000000000000000000000000000000038d7ea4c68000", "token": "0xb554A55358fF0382Fb21F0a478C3546d1106Be8c", "tokenType": 0 } diff --git a/script/configs/mainnet/SynapseRouter.dc.json b/script/configs/mainnet/SynapseRouter.dc.json index a6c003e43..d7b65ab35 100644 --- a/script/configs/mainnet/SynapseRouter.dc.json +++ b/script/configs/mainnet/SynapseRouter.dc.json @@ -23,7 +23,8 @@ "agEUR", "LINK", "UNIDX", - "PEPE" + "PEPE", + "SPEC" ], "tokens": { "DAI": { @@ -116,6 +117,15 @@ "token": "0xb753428af26E81097e7fD17f40c88aaA3E04902c", "tokenType": 1 }, + "SPEC": { + "bridgeFee": 5000000, + "bridgeToken": "0xAdF7C35560035944e805D98fF17d58CDe2449389", + "decimals": 18, + "maxFee": "0x000000000000000000000000000000000000000000032dcba101cb7220c6938c", + "minFee": "0x00000000000000000000000000000000000000000000000022b1c8c1227a0000", + "token": "0xAdF7C35560035944e805D98fF17d58CDe2449389", + "tokenType": 1 + }, "SYN": { "bridgeFee": 5000000, "bridgeToken": "0x0f2D719407FdBeFF09D87557AbB7232601FD9F29",