ethereum: EVM fork protection
Added a `uint256 evmChainId` state variable to the Core, Token and NFT Bridge contracts. `evmChainId` is compared to `block.chainid` in the `chainId` function. When they don't match, a "bad fork" Chain ID is returned, otherwise the Wormhole Chain ID is returned.
This commit is contained in:
parent
d83e44cf6b
commit
9d477e0585
|
@ -51,7 +51,6 @@ export async function query_contract_evm(
|
|||
result.isInitialized = await core.isInitialized(result.implementation)
|
||||
break
|
||||
case "TokenBridge":
|
||||
// TODO: add finality (need new sdk release)
|
||||
contract_address = contract_address ? contract_address : contracts.token_bridge;
|
||||
if (contract_address === undefined) {
|
||||
throw Error(`Unknown token bridge contract on ${network} for ${chain}`)
|
||||
|
@ -63,6 +62,9 @@ export async function query_contract_evm(
|
|||
result.isInitialized = await tb.isInitialized(result.implementation)
|
||||
result.tokenImplementation = await tb.tokenImplementation()
|
||||
result.chainId = await tb.chainId()
|
||||
// TODO: need new sdk release to expose this function in BridgeImplementation
|
||||
const tb2 = new ethers.Contract(contract_address, ["function finality() public view returns (uint8)"], provider)
|
||||
result.finality = await tb2.finality()
|
||||
result.governanceChainId = await tb.governanceChainId()
|
||||
result.governanceContract = await tb.governanceContract()
|
||||
result.WETH = await tb.WETH()
|
||||
|
@ -75,7 +77,6 @@ export async function query_contract_evm(
|
|||
}
|
||||
break
|
||||
case "NFTBridge":
|
||||
// TODO: add finality (need new sdk release)
|
||||
contract_address = contract_address ? contract_address : contracts.nft_bridge;
|
||||
if (contract_address === undefined) {
|
||||
throw Error(`Unknown nft bridge contract on ${network} for ${chain}`)
|
||||
|
@ -87,6 +88,9 @@ export async function query_contract_evm(
|
|||
result.isInitialized = await nb.isInitialized(result.implementation)
|
||||
result.tokenImplementation = await nb.tokenImplementation()
|
||||
result.chainId = await nb.chainId()
|
||||
// TODO: need new sdk release to expose this function in NFTBridgeImplementation
|
||||
const nb2 = new ethers.Contract(contract_address, ["function finality() public view returns (uint8)"], provider)
|
||||
result.finality = await nb2.finality()
|
||||
result.governanceChainId = await nb.governanceChainId()
|
||||
result.governanceContract = await nb.governanceContract()
|
||||
result.registrations = {}
|
||||
|
|
|
@ -55,7 +55,7 @@ spec:
|
|||
command:
|
||||
- /bin/sh
|
||||
- -c
|
||||
- "sed -i 's/CHAIN_ID=0x2/CHAIN_ID=0x4/g' .env && npm run migrate && npx truffle exec scripts/deploy_test_token.js && npx truffle exec scripts/register_solana_chain.js && npx truffle exec scripts/register_terra_chain.js && npx truffle exec scripts/register_terra2_chain.js && npx truffle exec scripts/register_eth_chain.js && npx truffle exec scripts/register_algo_chain.js && nc -lkp 2000 0.0.0.0"
|
||||
- "sed -i 's/CHAIN_ID=0x2/CHAIN_ID=0x4/g;s/EVM_CHAIN_ID=1/EVM_CHAIN_ID=1397/g' .env && npm run migrate && npx truffle exec scripts/deploy_test_token.js && npx truffle exec scripts/register_solana_chain.js && npx truffle exec scripts/register_terra_chain.js && npx truffle exec scripts/register_terra2_chain.js && npx truffle exec scripts/register_eth_chain.js && npx truffle exec scripts/register_algo_chain.js && nc -lkp 2000 0.0.0.0"
|
||||
readinessProbe:
|
||||
periodSeconds: 1
|
||||
failureThreshold: 300
|
||||
|
|
|
@ -6,6 +6,7 @@ INIT_SIGNERS=["0x58CC3AE5C097b213cE3c81979e1B9f9570746AA5"]
|
|||
INIT_CHAIN_ID=0xc
|
||||
INIT_GOV_CHAIN_ID=0x1
|
||||
INIT_GOV_CONTRACT=0x0000000000000000000000000000000000000000000000000000000000000004
|
||||
INIT_EVM_CHAIN_ID=787
|
||||
|
||||
# Bridge Migrations
|
||||
BRIDGE_INIT_CHAIN_ID=0xc
|
||||
|
|
|
@ -6,6 +6,7 @@ INIT_SIGNERS=["0x13947Bd48b18E53fdAeEe77F3473391aC727C638"]
|
|||
INIT_CHAIN_ID=0xc
|
||||
INIT_GOV_CHAIN_ID=0x1
|
||||
INIT_GOV_CONTRACT=0x0000000000000000000000000000000000000000000000000000000000000004
|
||||
INIT_EVM_CHAIN_ID=597
|
||||
|
||||
# Bridge Migrations
|
||||
BRIDGE_INIT_CHAIN_ID=0xc
|
||||
|
|
|
@ -6,3 +6,4 @@ INIT_SIGNERS=["0x58CC3AE5C097b213cE3c81979e1B9f9570746AA5"]
|
|||
INIT_CHAIN_ID=23
|
||||
INIT_GOV_CHAIN_ID=0x1
|
||||
INIT_GOV_CONTRACT=0x0000000000000000000000000000000000000000000000000000000000000004
|
||||
INIT_EVM_CHAIN_ID=42161
|
||||
|
|
|
@ -6,3 +6,4 @@ INIT_SIGNERS=["0x13947Bd48b18E53fdAeEe77F3473391aC727C638"]
|
|||
INIT_CHAIN_ID=23
|
||||
INIT_GOV_CHAIN_ID=0x1
|
||||
INIT_GOV_CONTRACT=0x0000000000000000000000000000000000000000000000000000000000000004
|
||||
INIT_EVM_CHAIN_ID=421611
|
||||
|
|
|
@ -6,6 +6,7 @@ INIT_SIGNERS=["0x58CC3AE5C097b213cE3c81979e1B9f9570746AA5"]
|
|||
INIT_CHAIN_ID=0x9
|
||||
INIT_GOV_CHAIN_ID=0x1
|
||||
INIT_GOV_CONTRACT=0x0000000000000000000000000000000000000000000000000000000000000004
|
||||
INIT_EVM_CHAIN_ID=1313161554
|
||||
|
||||
# Bridge Migrations
|
||||
BRIDGE_INIT_CHAIN_ID=0x9
|
||||
|
|
|
@ -6,6 +6,7 @@ INIT_SIGNERS=["0x13947Bd48b18E53fdAeEe77F3473391aC727C638"]
|
|||
INIT_CHAIN_ID=0x9
|
||||
INIT_GOV_CHAIN_ID=0x1
|
||||
INIT_GOV_CONTRACT=0x0000000000000000000000000000000000000000000000000000000000000004
|
||||
INIT_EVM_CHAIN_ID=1313161555
|
||||
|
||||
# Bridge Migrations
|
||||
BRIDGE_INIT_CHAIN_ID=0x9
|
||||
|
|
|
@ -6,6 +6,7 @@ INIT_SIGNERS=["0x58CC3AE5C097b213cE3c81979e1B9f9570746AA5"]
|
|||
INIT_CHAIN_ID=0xE
|
||||
INIT_GOV_CHAIN_ID=0x1
|
||||
INIT_GOV_CONTRACT=0x0000000000000000000000000000000000000000000000000000000000000004
|
||||
INIT_EVM_CHAIN_ID=42220
|
||||
|
||||
# Bridge Migrations
|
||||
BRIDGE_INIT_CHAIN_ID=0xE
|
||||
|
|
|
@ -6,6 +6,7 @@ INIT_SIGNERS=["0x13947Bd48b18E53fdAeEe77F3473391aC727C638"]
|
|||
INIT_CHAIN_ID=0xE
|
||||
INIT_GOV_CHAIN_ID=0x1
|
||||
INIT_GOV_CONTRACT=0x0000000000000000000000000000000000000000000000000000000000000004
|
||||
INIT_EVM_CHAIN_ID=44787
|
||||
|
||||
# Bridge Migrations
|
||||
BRIDGE_INIT_CHAIN_ID=0xE
|
||||
|
|
|
@ -6,6 +6,7 @@ INIT_SIGNERS=["0x58CC3AE5C097b213cE3c81979e1B9f9570746AA5"]
|
|||
INIT_CHAIN_ID=0xa
|
||||
INIT_GOV_CHAIN_ID=0x1
|
||||
INIT_GOV_CONTRACT=0x0000000000000000000000000000000000000000000000000000000000000004
|
||||
INIT_EVM_CHAIN_ID=250
|
||||
|
||||
# Bridge Migrations
|
||||
BRIDGE_INIT_CHAIN_ID=0xa
|
||||
|
|
|
@ -6,6 +6,7 @@ INIT_SIGNERS=["0x13947Bd48b18E53fdAeEe77F3473391aC727C638"]
|
|||
INIT_CHAIN_ID=0xa
|
||||
INIT_GOV_CHAIN_ID=0x1
|
||||
INIT_GOV_CONTRACT=0x0000000000000000000000000000000000000000000000000000000000000004
|
||||
INIT_EVM_CHAIN_ID=4002
|
||||
|
||||
# Bridge Migrations
|
||||
BRIDGE_INIT_CHAIN_ID=0xa
|
||||
|
|
|
@ -6,3 +6,4 @@ INIT_SIGNERS=["0x58CC3AE5C097b213cE3c81979e1B9f9570746AA5"]
|
|||
INIT_CHAIN_ID=25
|
||||
INIT_GOV_CHAIN_ID=0x1
|
||||
INIT_GOV_CONTRACT=0x0000000000000000000000000000000000000000000000000000000000000004
|
||||
INIT_EVM_CHAIN_ID=100
|
||||
|
|
|
@ -6,3 +6,4 @@ INIT_SIGNERS=["0x13947Bd48b18E53fdAeEe77F3473391aC727C638"]
|
|||
INIT_CHAIN_ID=25
|
||||
INIT_GOV_CHAIN_ID=0x1
|
||||
INIT_GOV_CONTRACT=0x0000000000000000000000000000000000000000000000000000000000000004
|
||||
INIT_EVM_CHAIN_ID=77
|
||||
|
|
|
@ -6,6 +6,7 @@ INIT_SIGNERS=["0x58CC3AE5C097b213cE3c81979e1B9f9570746AA5"]
|
|||
INIT_CHAIN_ID=0xb
|
||||
INIT_GOV_CHAIN_ID=0x1
|
||||
INIT_GOV_CONTRACT=0x0000000000000000000000000000000000000000000000000000000000000004
|
||||
INIT_EVM_CHAIN_ID=686
|
||||
|
||||
# Bridge Migrations
|
||||
BRIDGE_INIT_CHAIN_ID=0xb
|
||||
|
|
|
@ -6,6 +6,7 @@ INIT_SIGNERS=["0x13947Bd48b18E53fdAeEe77F3473391aC727C638"]
|
|||
INIT_CHAIN_ID=0xb
|
||||
INIT_GOV_CHAIN_ID=0x1
|
||||
INIT_GOV_CONTRACT=0x0000000000000000000000000000000000000000000000000000000000000004
|
||||
INIT_EVM_CHAIN_ID=596
|
||||
|
||||
# Bridge Migrations
|
||||
BRIDGE_INIT_CHAIN_ID=0xb
|
||||
|
|
|
@ -6,6 +6,7 @@ INIT_SIGNERS=["0x58CC3AE5C097b213cE3c81979e1B9f9570746AA5"]
|
|||
INIT_CHAIN_ID=0xd
|
||||
INIT_GOV_CHAIN_ID=0x1
|
||||
INIT_GOV_CONTRACT=0x0000000000000000000000000000000000000000000000000000000000000004
|
||||
INIT_EVM_CHAIN_ID=8217
|
||||
|
||||
# Bridge Migrations
|
||||
BRIDGE_INIT_CHAIN_ID=0xd
|
||||
|
|
|
@ -6,6 +6,7 @@ INIT_SIGNERS=["0x13947Bd48b18E53fdAeEe77F3473391aC727C638"]
|
|||
INIT_CHAIN_ID=0xd
|
||||
INIT_GOV_CHAIN_ID=0x1
|
||||
INIT_GOV_CONTRACT=0x0000000000000000000000000000000000000000000000000000000000000004
|
||||
INIT_EVM_CHAIN_ID=1001
|
||||
|
||||
# Bridge Migrations
|
||||
BRIDGE_INIT_CHAIN_ID=0xd
|
||||
|
|
|
@ -6,3 +6,4 @@ INIT_SIGNERS=["0x58CC3AE5C097b213cE3c81979e1B9f9570746AA5"]
|
|||
INIT_CHAIN_ID=16
|
||||
INIT_GOV_CHAIN_ID=0x1
|
||||
INIT_GOV_CONTRACT=0x0000000000000000000000000000000000000000000000000000000000000004
|
||||
INIT_CHAIN_ID=1284
|
||||
|
|
|
@ -6,6 +6,7 @@ INIT_SIGNERS=["0x13947Bd48b18E53fdAeEe77F3473391aC727C638"]
|
|||
INIT_CHAIN_ID=0x10
|
||||
INIT_GOV_CHAIN_ID=0x1
|
||||
INIT_GOV_CONTRACT=0x0000000000000000000000000000000000000000000000000000000000000004
|
||||
INIT_CHAIN_ID=1287
|
||||
|
||||
# Bridge Migrations
|
||||
BRIDGE_INIT_CHAIN_ID=0x10
|
||||
|
|
|
@ -6,6 +6,7 @@ INIT_SIGNERS=["0x13947Bd48b18E53fdAeEe77F3473391aC727C638"]
|
|||
INIT_CHAIN_ID=0x11
|
||||
INIT_GOV_CHAIN_ID=0x1
|
||||
INIT_GOV_CONTRACT=0x0000000000000000000000000000000000000000000000000000000000000004
|
||||
INIT_EVM_CHAIN_ID=245022926
|
||||
|
||||
# Bridge Migrations
|
||||
BRIDGE_INIT_CHAIN_ID=0x11
|
||||
|
|
|
@ -6,3 +6,4 @@ INIT_SIGNERS=["0x58CC3AE5C097b213cE3c81979e1B9f9570746AA5"]
|
|||
INIT_CHAIN_ID=24
|
||||
INIT_GOV_CHAIN_ID=0x1
|
||||
INIT_GOV_CONTRACT=0x0000000000000000000000000000000000000000000000000000000000000004
|
||||
INIT_EVM_CHAIN_ID=10
|
||||
|
|
|
@ -6,3 +6,4 @@ INIT_SIGNERS=["0x13947Bd48b18E53fdAeEe77F3473391aC727C638"]
|
|||
INIT_CHAIN_ID=24
|
||||
INIT_GOV_CHAIN_ID=0x1
|
||||
INIT_GOV_CONTRACT=0x0000000000000000000000000000000000000000000000000000000000000004
|
||||
INIT_EVM_CHAIN_ID=420
|
||||
|
|
|
@ -10,6 +10,7 @@ INIT_SIGNERS= # ["0x0000000000000000000000000000000000000000"]
|
|||
INIT_CHAIN_ID= # 0x2
|
||||
INIT_GOV_CHAIN_ID= # 0x3
|
||||
INIT_GOV_CONTRACT= # 0x000000000000000000000000000000000000000000000000000000000000000
|
||||
INIT_EVM_CHAIN_ID= # 1
|
||||
|
||||
# Bridge Migrations # Example Format
|
||||
BRIDGE_INIT_CHAIN_ID= # 0x02
|
||||
|
|
|
@ -3,6 +3,7 @@ INIT_SIGNERS=["0xbeFA429d57cD18b7F8A4d91A2da9AB4AF05d0FBe"]
|
|||
INIT_CHAIN_ID=0x2
|
||||
INIT_GOV_CHAIN_ID=0x1
|
||||
INIT_GOV_CONTRACT=0x0000000000000000000000000000000000000000000000000000000000000004
|
||||
INIT_EVM_CHAIN_ID=1
|
||||
|
||||
# Bridge Migrations
|
||||
BRIDGE_INIT_CHAIN_ID=0x2
|
||||
|
|
|
@ -27,9 +27,17 @@ contract Getters is State {
|
|||
}
|
||||
|
||||
function chainId() public view returns (uint16) {
|
||||
if (evmChainId() != block.chainid) {
|
||||
// reduce the likelihood of forked chain ID collisions
|
||||
return type(uint16).max - 32 + uint16(block.chainid % 32);
|
||||
}
|
||||
return _state.provider.chainId;
|
||||
}
|
||||
|
||||
function evmChainId() public view returns (uint256) {
|
||||
return _state.evmChainId;
|
||||
}
|
||||
|
||||
function governanceChainId() public view returns (uint16){
|
||||
return _state.provider.governanceChainId;
|
||||
}
|
||||
|
|
|
@ -32,6 +32,31 @@ contract Implementation is Governance {
|
|||
|
||||
function initialize() initializer public virtual {
|
||||
// this function needs to be exposed for an upgrade to pass
|
||||
uint256 evmChainId;
|
||||
uint16 chain = _state.provider.chainId;
|
||||
|
||||
// Wormhole chain ids explicitly enumerated
|
||||
if (chain == 2) { evmChainId = 1; // ethereum
|
||||
} else if (chain == 4) { evmChainId = 56; // bsc
|
||||
} else if (chain == 5) { evmChainId = 137; // polygon
|
||||
} else if (chain == 6) { evmChainId = 43114; // avalanche
|
||||
} else if (chain == 7) { evmChainId = 42262; // oasis
|
||||
} else if (chain == 9) { evmChainId = 1313161554; // aurora
|
||||
} else if (chain == 10) { evmChainId = 250; // fantom
|
||||
} else if (chain == 11) { evmChainId = 686; // karura
|
||||
} else if (chain == 12) { evmChainId = 787; // acala
|
||||
} else if (chain == 13) { evmChainId = 8217; // klaytn
|
||||
} else if (chain == 14) { evmChainId = 42220; // celo
|
||||
} else if (chain == 16) { evmChainId = 1284; // moonbeam
|
||||
} else if (chain == 17) { evmChainId = 245022934; // neon
|
||||
} else if (chain == 23) { evmChainId = 42161; // arbitrum
|
||||
} else if (chain == 24) { evmChainId = 10; // optimism
|
||||
} else if (chain == 25) { evmChainId = 100; // gnosis
|
||||
} else {
|
||||
revert("Unknown chain id.");
|
||||
}
|
||||
|
||||
setEvmChainId(evmChainId);
|
||||
}
|
||||
|
||||
modifier initializer() {
|
||||
|
|
|
@ -45,4 +45,9 @@ contract Setters is State {
|
|||
function setNextSequence(address emitter, uint64 sequence) internal {
|
||||
_state.sequences[emitter] = sequence;
|
||||
}
|
||||
|
||||
function setEvmChainId(uint256 evmChainId) internal {
|
||||
require(evmChainId == block.chainid, "invalid evmChainId");
|
||||
_state.evmChainId = evmChainId;
|
||||
}
|
||||
}
|
|
@ -14,7 +14,8 @@ contract Setup is Setters, ERC1967Upgrade {
|
|||
address[] memory initialGuardians,
|
||||
uint16 chainId,
|
||||
uint16 governanceChainId,
|
||||
bytes32 governanceContract
|
||||
bytes32 governanceContract,
|
||||
uint256 evmChainId
|
||||
) public {
|
||||
require(initialGuardians.length > 0, "no guardians specified");
|
||||
|
||||
|
@ -31,6 +32,8 @@ contract Setup is Setters, ERC1967Upgrade {
|
|||
setGovernanceChainId(governanceChainId);
|
||||
setGovernanceContract(governanceContract);
|
||||
|
||||
setEvmChainId(evmChainId);
|
||||
|
||||
_upgradeTo(implementation);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -41,6 +41,9 @@ contract Storage {
|
|||
mapping(address => bool) initializedImplementations;
|
||||
|
||||
uint256 messageFee;
|
||||
|
||||
// EIP-155 Chain ID
|
||||
uint256 evmChainId;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -20,10 +20,15 @@ import "./token/TokenImplementation.sol";
|
|||
contract Bridge is BridgeGovernance, ReentrancyGuard {
|
||||
using BytesLib for bytes;
|
||||
|
||||
modifier onlyEvmChainId() {
|
||||
require(evmChainId() == block.chainid, "invalid evmChainId");
|
||||
_;
|
||||
}
|
||||
|
||||
/*
|
||||
* @dev Produce a AssetMeta message for a given token
|
||||
*/
|
||||
function attestToken(address tokenAddress, uint32 nonce) public payable returns (uint64 sequence) {
|
||||
function attestToken(address tokenAddress, uint32 nonce) public payable onlyEvmChainId returns (uint64 sequence) {
|
||||
// decimals, symbol & token are not part of the core ERC20 token standard, so we need to support contracts that dont implement them
|
||||
(,bytes memory queriedDecimals) = tokenAddress.staticcall(abi.encodeWithSignature("decimals()"));
|
||||
(,bytes memory queriedSymbol) = tokenAddress.staticcall(abi.encodeWithSignature("symbol()"));
|
||||
|
@ -66,7 +71,7 @@ contract Bridge is BridgeGovernance, ReentrancyGuard {
|
|||
bytes32 recipient,
|
||||
uint256 arbiterFee,
|
||||
uint32 nonce
|
||||
) public payable returns (uint64 sequence) {
|
||||
) public payable onlyEvmChainId returns (uint64 sequence) {
|
||||
BridgeStructs.TransferResult
|
||||
memory transferResult = _wrapAndTransferETH(arbiterFee);
|
||||
sequence = logTransfer(
|
||||
|
@ -98,7 +103,7 @@ contract Bridge is BridgeGovernance, ReentrancyGuard {
|
|||
bytes32 recipient,
|
||||
uint32 nonce,
|
||||
bytes memory payload
|
||||
) public payable returns (uint64 sequence) {
|
||||
) public payable onlyEvmChainId returns (uint64 sequence) {
|
||||
BridgeStructs.TransferResult
|
||||
memory transferResult = _wrapAndTransferETH(0);
|
||||
sequence = logTransferWithPayload(
|
||||
|
@ -158,7 +163,7 @@ contract Bridge is BridgeGovernance, ReentrancyGuard {
|
|||
bytes32 recipient,
|
||||
uint256 arbiterFee,
|
||||
uint32 nonce
|
||||
) public payable nonReentrant returns (uint64 sequence) {
|
||||
) public payable nonReentrant onlyEvmChainId returns (uint64 sequence) {
|
||||
BridgeStructs.TransferResult memory transferResult = _transferTokens(
|
||||
token,
|
||||
amount,
|
||||
|
@ -195,7 +200,7 @@ contract Bridge is BridgeGovernance, ReentrancyGuard {
|
|||
bytes32 recipient,
|
||||
uint32 nonce,
|
||||
bytes memory payload
|
||||
) public payable nonReentrant returns (uint64 sequence) {
|
||||
) public payable nonReentrant onlyEvmChainId returns (uint64 sequence) {
|
||||
BridgeStructs.TransferResult memory transferResult = _transferTokens(
|
||||
token,
|
||||
amount,
|
||||
|
@ -354,7 +359,7 @@ contract Bridge is BridgeGovernance, ReentrancyGuard {
|
|||
finality()
|
||||
);
|
||||
}
|
||||
function updateWrapped(bytes memory encodedVm) external returns (address token) {
|
||||
function updateWrapped(bytes memory encodedVm) external onlyEvmChainId returns (address token) {
|
||||
(IWormhole.VM memory vm, bool valid, string memory reason) = wormhole().parseAndVerifyVM(encodedVm);
|
||||
|
||||
require(valid, reason);
|
||||
|
@ -374,7 +379,7 @@ contract Bridge is BridgeGovernance, ReentrancyGuard {
|
|||
return wrapped;
|
||||
}
|
||||
|
||||
function createWrapped(bytes memory encodedVm) external returns (address token) {
|
||||
function createWrapped(bytes memory encodedVm) external onlyEvmChainId returns (address token) {
|
||||
(IWormhole.VM memory vm, bool valid, string memory reason) = wormhole().parseAndVerifyVM(encodedVm);
|
||||
|
||||
require(valid, reason);
|
||||
|
@ -484,7 +489,7 @@ contract Bridge is BridgeGovernance, ReentrancyGuard {
|
|||
}
|
||||
|
||||
// Execute a Transfer message
|
||||
function _completeTransfer(bytes memory encodedVm, bool unwrapWETH) internal returns (bytes memory) {
|
||||
function _completeTransfer(bytes memory encodedVm, bool unwrapWETH) internal onlyEvmChainId returns (bytes memory) {
|
||||
(IWormhole.VM memory vm, bool valid, string memory reason) = wormhole().parseAndVerifyVM(encodedVm);
|
||||
|
||||
require(valid, reason);
|
||||
|
|
|
@ -27,9 +27,17 @@ contract BridgeGetters is BridgeState {
|
|||
}
|
||||
|
||||
function chainId() public view returns (uint16){
|
||||
if (evmChainId() != block.chainid) {
|
||||
// reduce the likelihood of forked chain ID collisions
|
||||
return type(uint16).max - 32 + uint16(block.chainid % 32);
|
||||
}
|
||||
return _state.provider.chainId;
|
||||
}
|
||||
|
||||
function evmChainId() public view returns (uint256) {
|
||||
return _state.evmChainId;
|
||||
}
|
||||
|
||||
function governanceChainId() public view returns (uint16){
|
||||
return _state.provider.governanceChainId;
|
||||
}
|
||||
|
|
|
@ -17,27 +17,31 @@ contract BridgeImplementation is Bridge {
|
|||
|
||||
function initialize() initializer public virtual {
|
||||
// this function needs to be exposed for an upgrade to pass
|
||||
address tokenContract;
|
||||
uint16 chain = chainId();
|
||||
uint256 evmChainId;
|
||||
uint16 chain = _state.provider.chainId;
|
||||
|
||||
// Wormhole chain ids explicitly enumerated
|
||||
if (chain == 2) { tokenContract = 0x44bD47a8Bc18398227d6f40E1693Cf897bb9855E; // ethereum
|
||||
} else if (chain == 4) { tokenContract = 0x1877a83023A87849D89a076466531b6a5DEa7eb2; // bsc
|
||||
} else if (chain == 5) { tokenContract = 0xB9A1c8873a7a36c2Eb6D8c1A19702106CdAE6edd; // polygon
|
||||
} else if (chain == 6) { tokenContract = 0x276a65900C97A3726319742e74F75bC4f56A0BfD; // avalanche
|
||||
} else if (chain == 7) { tokenContract = 0x95BeDdFba786Aa1A5b3294aa6166cB125B961e34; // oasis
|
||||
} else if (chain == 9) { tokenContract = 0x1Cd0b07Dc82482f057b3cf19775e8453309c5356; // aurora
|
||||
} else if (chain == 10) { tokenContract = 0x40D0A808241cafd9D70700963d205FeA9c0B1C9D; // fantom
|
||||
} else if (chain == 11) { tokenContract = 0x9002933919Aa83c38D01bDfBd788A9dfF42f3880; // karura
|
||||
// Acala EVM was down at the time of this migration
|
||||
// } else if (chain == 12) { tokenContract = 0x0000000000000000000000000000000000000000; // acala
|
||||
} else if (chain == 13) { tokenContract = 0xA7601785478622E720d41454CB390852cd2B9788; // klaytn
|
||||
} else if (chain == 14) { tokenContract = 0xADE06bc75Dc1FC3fB7442e0CFb8Ca544B23aF789; // celo
|
||||
if (chain == 2) { evmChainId = 1; // ethereum
|
||||
} else if (chain == 4) { evmChainId = 56; // bsc
|
||||
} else if (chain == 5) { evmChainId = 137; // polygon
|
||||
} else if (chain == 6) { evmChainId = 43114; // avalanche
|
||||
} else if (chain == 7) { evmChainId = 42262; // oasis
|
||||
} else if (chain == 9) { evmChainId = 1313161554; // aurora
|
||||
} else if (chain == 10) { evmChainId = 250; // fantom
|
||||
} else if (chain == 11) { evmChainId = 686; // karura
|
||||
} else if (chain == 12) { evmChainId = 787; // acala
|
||||
} else if (chain == 13) { evmChainId = 8217; // klaytn
|
||||
} else if (chain == 14) { evmChainId = 42220; // celo
|
||||
} else if (chain == 16) { evmChainId = 1284; // moonbeam
|
||||
} else if (chain == 17) { evmChainId = 245022934; // neon
|
||||
} else if (chain == 23) { evmChainId = 42161; // arbitrum
|
||||
} else if (chain == 24) { evmChainId = 10; // optimism
|
||||
} else if (chain == 25) { evmChainId = 100; // gnosis
|
||||
} else {
|
||||
revert("Unknown chain id.");
|
||||
}
|
||||
|
||||
setTokenImplementation(tokenContract);
|
||||
setEvmChainId(evmChainId);
|
||||
}
|
||||
|
||||
modifier initializer() {
|
||||
|
|
|
@ -58,4 +58,9 @@ contract BridgeSetters is BridgeState {
|
|||
function setFinality(uint8 finality) internal {
|
||||
_state.provider.finality = finality;
|
||||
}
|
||||
|
||||
function setEvmChainId(uint256 evmChainId) internal {
|
||||
require(evmChainId == block.chainid, "invalid evmChainId");
|
||||
_state.evmChainId = evmChainId;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,7 +17,8 @@ contract BridgeSetup is BridgeSetters, ERC1967Upgrade {
|
|||
bytes32 governanceContract,
|
||||
address tokenImplementation,
|
||||
address WETH,
|
||||
uint8 finality
|
||||
uint8 finality,
|
||||
uint256 evmChainId
|
||||
) public {
|
||||
setChainId(chainId);
|
||||
|
||||
|
@ -32,6 +33,8 @@ contract BridgeSetup is BridgeSetters, ERC1967Upgrade {
|
|||
|
||||
setFinality(finality);
|
||||
|
||||
setEvmChainId(evmChainId);
|
||||
|
||||
_upgradeTo(implementation);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -46,6 +46,9 @@ contract BridgeStorage {
|
|||
|
||||
// Mapping of bridge contracts on other chains
|
||||
mapping(uint16 => bytes32) bridgeImplementations;
|
||||
|
||||
// EIP-155 Chain ID
|
||||
uint256 evmChainId;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -19,8 +19,13 @@ import "./token/NFTImplementation.sol";
|
|||
contract NFTBridge is NFTBridgeGovernance {
|
||||
using BytesLib for bytes;
|
||||
|
||||
modifier onlyEvmChainId() {
|
||||
require(evmChainId() == block.chainid, "invalid evmChainId");
|
||||
_;
|
||||
}
|
||||
|
||||
// Initiate a Transfer
|
||||
function transferNFT(address token, uint256 tokenID, uint16 recipientChain, bytes32 recipient, uint32 nonce) public payable returns (uint64 sequence) {
|
||||
function transferNFT(address token, uint256 tokenID, uint16 recipientChain, bytes32 recipient, uint32 nonce) public payable onlyEvmChainId returns (uint64 sequence) {
|
||||
// determine token parameters
|
||||
uint16 tokenChain;
|
||||
bytes32 tokenAddress;
|
||||
|
@ -97,7 +102,7 @@ contract NFTBridge is NFTBridgeGovernance {
|
|||
}(nonce, encoded, finality());
|
||||
}
|
||||
|
||||
function completeTransfer(bytes memory encodedVm) public {
|
||||
function completeTransfer(bytes memory encodedVm) public onlyEvmChainId {
|
||||
_completeTransfer(encodedVm);
|
||||
}
|
||||
|
||||
|
|
|
@ -27,9 +27,17 @@ contract NFTBridgeGetters is NFTBridgeState {
|
|||
}
|
||||
|
||||
function chainId() public view returns (uint16){
|
||||
if (evmChainId() != block.chainid) {
|
||||
// reduce the likelihood of forked chain ID collisions
|
||||
return type(uint16).max - 32 + uint16(block.chainid % 32);
|
||||
}
|
||||
return _state.provider.chainId;
|
||||
}
|
||||
|
||||
function evmChainId() public view returns (uint256) {
|
||||
return _state.evmChainId;
|
||||
}
|
||||
|
||||
function governanceChainId() public view returns (uint16){
|
||||
return _state.provider.governanceChainId;
|
||||
}
|
||||
|
|
|
@ -17,28 +17,31 @@ contract NFTBridgeImplementation is NFTBridge {
|
|||
|
||||
function initialize() initializer public virtual {
|
||||
// this function needs to be exposed for an upgrade to pass
|
||||
uint8 finality;
|
||||
uint16 chain = chainId();
|
||||
uint256 evmChainId;
|
||||
uint16 chain = _state.provider.chainId;
|
||||
|
||||
// Wormhole chain ids explicitly enumerated
|
||||
if (chain == 2) { finality = 15; // ethereum
|
||||
} else if (chain == 4) { finality = 15; // bsc
|
||||
} else if (chain == 5) { finality = 15; // polygon
|
||||
} else if (chain == 6) { finality = 1; // avalanche
|
||||
} else if (chain == 7) { finality = 1; // oasis
|
||||
} else if (chain == 9) { finality = 1; // aurora
|
||||
} else if (chain == 10) { finality = 1; // fantom
|
||||
} else if (chain == 11) { finality = 1; // karura
|
||||
} else if (chain == 12) { finality = 1; // acala
|
||||
} else if (chain == 13) { finality = 1; // klaytn
|
||||
} else if (chain == 14) { finality = 1; // celo
|
||||
} else if (chain == 16) { finality = 1; // moonbeam
|
||||
} else if (chain == 17) { finality = 32; // neon
|
||||
if (chain == 2) { evmChainId = 1; // ethereum
|
||||
} else if (chain == 4) { evmChainId = 56; // bsc
|
||||
} else if (chain == 5) { evmChainId = 137; // polygon
|
||||
} else if (chain == 6) { evmChainId = 43114; // avalanche
|
||||
} else if (chain == 7) { evmChainId = 42262; // oasis
|
||||
} else if (chain == 9) { evmChainId = 1313161554; // aurora
|
||||
} else if (chain == 10) { evmChainId = 250; // fantom
|
||||
} else if (chain == 11) { evmChainId = 686; // karura
|
||||
} else if (chain == 12) { evmChainId = 787; // acala
|
||||
} else if (chain == 13) { evmChainId = 8217; // klaytn
|
||||
} else if (chain == 14) { evmChainId = 42220; // celo
|
||||
} else if (chain == 16) { evmChainId = 1284; // moonbeam
|
||||
} else if (chain == 17) { evmChainId = 245022934; // neon
|
||||
} else if (chain == 23) { evmChainId = 42161; // arbitrum
|
||||
} else if (chain == 24) { evmChainId = 10; // optimism
|
||||
} else if (chain == 25) { evmChainId = 100; // gnosis
|
||||
} else {
|
||||
revert("Unknown chain id.");
|
||||
}
|
||||
|
||||
setFinality(finality);
|
||||
setEvmChainId(evmChainId);
|
||||
}
|
||||
|
||||
modifier initializer() {
|
||||
|
|
|
@ -58,4 +58,9 @@ contract NFTBridgeSetters is NFTBridgeState {
|
|||
function setFinality(uint8 finality) internal {
|
||||
_state.provider.finality = finality;
|
||||
}
|
||||
|
||||
function setEvmChainId(uint256 evmChainId) internal {
|
||||
require(evmChainId == block.chainid, "invalid evmChainId");
|
||||
_state.evmChainId = evmChainId;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,7 +16,8 @@ contract NFTBridgeSetup is NFTBridgeSetters, ERC1967Upgrade {
|
|||
uint16 governanceChainId,
|
||||
bytes32 governanceContract,
|
||||
address tokenImplementation,
|
||||
uint8 finality
|
||||
uint8 finality,
|
||||
uint256 evmChainId
|
||||
) public {
|
||||
setChainId(chainId);
|
||||
|
||||
|
@ -29,6 +30,8 @@ contract NFTBridgeSetup is NFTBridgeSetters, ERC1967Upgrade {
|
|||
|
||||
setFinality(finality);
|
||||
|
||||
setEvmChainId(evmChainId);
|
||||
|
||||
_upgradeTo(implementation);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -50,6 +50,9 @@ contract NFTBridgeStorage {
|
|||
|
||||
// Mapping of spl token info caches (chainID => nativeAddress => SPLCache)
|
||||
mapping(uint256 => SPLCache) splCache;
|
||||
|
||||
// EIP-155 Chain ID
|
||||
uint256 evmChainId;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -13,4 +13,26 @@ contract TestBridge is Bridge, Test {
|
|||
bytes32 converted = bytes32(uint256(uint160(bytes20(_truncateAddress(b)))));
|
||||
require(converted == b, "truncate does not roundrip");
|
||||
}
|
||||
|
||||
function testChainId() public {
|
||||
vm.chainId(1);
|
||||
setChainId(1);
|
||||
setEvmChainId(1);
|
||||
assertEq(chainId(), 1);
|
||||
assertEq(evmChainId(), 1);
|
||||
|
||||
vm.expectRevert("invalid evmChainId");
|
||||
setEvmChainId(1337);
|
||||
assertEq(chainId(), 1);
|
||||
assertEq(evmChainId(), 1);
|
||||
|
||||
// fork occurs, block.chainid changes
|
||||
vm.chainId(10001);
|
||||
assertEq(chainId(), 65520);
|
||||
assertEq(evmChainId(), 1);
|
||||
|
||||
setEvmChainId(10001);
|
||||
assertEq(chainId(), 1);
|
||||
assertEq(evmChainId(), 10001);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ const initialSigners = JSON.parse(process.env.INIT_SIGNERS);
|
|||
const chainId = process.env.INIT_CHAIN_ID;
|
||||
const governanceChainId = process.env.INIT_GOV_CHAIN_ID;
|
||||
const governanceContract = process.env.INIT_GOV_CONTRACT; // bytes32
|
||||
const evmChainId = process.env.INIT_EVM_CHAIN_ID;
|
||||
|
||||
module.exports = async function (deployer) {
|
||||
// deploy setup
|
||||
|
@ -24,7 +25,8 @@ module.exports = async function (deployer) {
|
|||
initialSigners,
|
||||
chainId,
|
||||
governanceChainId,
|
||||
governanceContract
|
||||
governanceContract,
|
||||
evmChainId
|
||||
).encodeABI();
|
||||
|
||||
// deploy proxy
|
||||
|
|
|
@ -11,6 +11,7 @@ const governanceChainId = process.env.BRIDGE_INIT_GOV_CHAIN_ID;
|
|||
const governanceContract = process.env.BRIDGE_INIT_GOV_CONTRACT; // bytes32
|
||||
const WETH = process.env.BRIDGE_INIT_WETH;
|
||||
const finality = process.env.BRIDGE_INIT_FINALITY;
|
||||
const evmChainId = process.env.INIT_EVM_CHAIN_ID;
|
||||
|
||||
module.exports = async function (deployer) {
|
||||
// deploy token implementation
|
||||
|
@ -32,7 +33,8 @@ module.exports = async function (deployer) {
|
|||
governanceContract,
|
||||
TokenImplementation.address,
|
||||
WETH,
|
||||
finality
|
||||
finality,
|
||||
evmChainId
|
||||
).encodeABI();
|
||||
|
||||
// deploy proxy
|
||||
|
|
|
@ -10,6 +10,7 @@ const chainId = process.env.BRIDGE_INIT_CHAIN_ID;
|
|||
const governanceChainId = process.env.BRIDGE_INIT_GOV_CHAIN_ID;
|
||||
const governanceContract = process.env.BRIDGE_INIT_GOV_CONTRACT; // bytes32
|
||||
const finality = process.env.BRIDGE_INIT_FINALITY;
|
||||
const evmChainId = process.env.INIT_EVM_CHAIN_ID;
|
||||
|
||||
module.exports = async function (deployer) {
|
||||
// deploy token implementation
|
||||
|
@ -30,7 +31,8 @@ module.exports = async function (deployer) {
|
|||
governanceChainId,
|
||||
governanceContract,
|
||||
TokenImplementation.address,
|
||||
finality
|
||||
finality,
|
||||
evmChainId
|
||||
).encodeABI();
|
||||
|
||||
// deploy proxy
|
||||
|
|
|
@ -22,6 +22,7 @@ contract("Bridge", function () {
|
|||
const testSigner1 = web3.eth.accounts.privateKeyToAccount(testSigner1PK);
|
||||
const testSigner2 = web3.eth.accounts.privateKeyToAccount(testSigner2PK);
|
||||
const testChainId = "2";
|
||||
const testEvmChainId = "1";
|
||||
const testFinality = "1";
|
||||
const testGovernanceChainId = "1";
|
||||
const testGovernanceContract = "0x0000000000000000000000000000000000000000000000000000000000000004";
|
||||
|
@ -49,6 +50,10 @@ contract("Bridge", function () {
|
|||
const chainId = await initialized.methods.chainId().call();
|
||||
assert.equal(chainId, testChainId);
|
||||
|
||||
// evm chain id
|
||||
const evmChainId = await initialized.methods.evmChainId().call();
|
||||
assert.equal(evmChainId, testEvmChainId);
|
||||
|
||||
// finality
|
||||
const finality = await initialized.methods.finality().call();
|
||||
assert.equal(finality, testFinality);
|
||||
|
|
|
@ -19,6 +19,7 @@ contract("NFT", function () {
|
|||
const testSigner1 = web3.eth.accounts.privateKeyToAccount(testSigner1PK);
|
||||
const testSigner2 = web3.eth.accounts.privateKeyToAccount(testSigner2PK);
|
||||
const testChainId = "2";
|
||||
const testEvmChainId = "1";
|
||||
const testFinality = "1";
|
||||
const testGovernanceChainId = "1";
|
||||
const testGovernanceContract = "0x0000000000000000000000000000000000000000000000000000000000000004";
|
||||
|
@ -43,6 +44,10 @@ contract("NFT", function () {
|
|||
const chainId = await initialized.methods.chainId().call();
|
||||
assert.equal(chainId, testChainId);
|
||||
|
||||
// evm chain id
|
||||
const evmChainId = await initialized.methods.evmChainId().call();
|
||||
assert.equal(evmChainId, testEvmChainId);
|
||||
|
||||
// finality
|
||||
const finality = await initialized.methods.finality().call();
|
||||
assert.equal(finality, testFinality);
|
||||
|
|
|
@ -20,6 +20,7 @@ const BridgeImplementationFullABI = jsonfile.readFileSync("build/contracts/Bridg
|
|||
contract("Update Bridge", function (accounts) {
|
||||
if (config.network === "test") return;
|
||||
const testChainId = "2";
|
||||
const testEvmChainId = "1";
|
||||
const testGovernanceChainId = "1";
|
||||
const testGovernanceContract = "0x0000000000000000000000000000000000000000000000000000000000000004";
|
||||
let WETH = "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2";
|
||||
|
@ -41,7 +42,8 @@ contract("Update Bridge", function (accounts) {
|
|||
testGovernanceContract,
|
||||
TokenImplementation.address,
|
||||
WETH,
|
||||
testFinality
|
||||
testFinality,
|
||||
testEvmChainId
|
||||
).encodeABI();
|
||||
|
||||
const deploy = await TokenBridge.new(BridgeSetup.address, initData);
|
||||
|
|
|
@ -68,6 +68,7 @@ contract("Wormhole", function () {
|
|||
const testSigner2 = web3.eth.accounts.privateKeyToAccount(testSigner2PK);
|
||||
const testSigner3 = web3.eth.accounts.privateKeyToAccount(testSigner3PK);
|
||||
const testChainId = "2";
|
||||
const testEvmChainId = "1";
|
||||
const testGovernanceChainId = "1";
|
||||
const testGovernanceContract = "0x0000000000000000000000000000000000000000000000000000000000000004";
|
||||
|
||||
|
@ -88,6 +89,10 @@ contract("Wormhole", function () {
|
|||
const chainId = await initialized.methods.chainId().call();
|
||||
assert.equal(chainId, testChainId);
|
||||
|
||||
// evm chain id
|
||||
const evmChainId = await initialized.methods.evmChainId().call();
|
||||
assert.equal(evmChainId, testEvmChainId);
|
||||
|
||||
// governance
|
||||
const governanceChainId = await initialized.methods.governanceChainId().call();
|
||||
assert.equal(governanceChainId, testGovernanceChainId);
|
||||
|
|
Loading…
Reference in New Issue