* grelayer: start #2758, create2 factory, merge lib & forward wrapper, forward wrapper stored as immutable var * debug governance * fw inherits from lib * forge tests work * cleanup * fix typechain imports * fix salt * calldata packing :( * relayer: things work * relayer: moving code into corerelayerlibrary * relayer: other file changes for code moving * remove debugging statement * fixing tilt deployment scripts * relayer: relayer-engine does not start in ci * passthrough number of guardians * relayer: fix self signing script for multiple signers * relayer fix ordering of guardian key load --------- Co-authored-by: chase-45 <chasemoran45@gmail.com> Co-authored-by: chase-45 <88348425+chase-45@users.noreply.github.com>
This commit is contained in:
parent
9dd4b7c67e
commit
cb6fb1c4a2
3
Tiltfile
3
Tiltfile
|
@ -453,6 +453,7 @@ docker_build(
|
|||
|
||||
# ignore local node_modules (in case they're present)
|
||||
ignore = ["./node_modules", "./ts-test"],
|
||||
build_args = {"num_guardians": str(num_guardians)},
|
||||
|
||||
# sync external scripts for incremental development
|
||||
# (everything else needs to be restarted from scratch for determinism)
|
||||
|
@ -482,7 +483,7 @@ if spy_relayer or redis or generic_relayer or ci_tests:
|
|||
|
||||
k8s_yaml_with_ns("devnet/redis.yaml")
|
||||
|
||||
if generic_relayer or ci_tests:
|
||||
if generic_relayer:
|
||||
k8s_resource(
|
||||
"relayer-engine",
|
||||
resource_deps = ["guardian", "redis", "spy"],
|
||||
|
|
|
@ -59,3 +59,6 @@ RUN rm -rf node_modules && mv node_modules_cache node_modules
|
|||
|
||||
COPY --chown=node:node . .
|
||||
RUN make forge_dependencies
|
||||
|
||||
ARG num_guardians
|
||||
ENV NUM_GUARDIANS=$num_guardians
|
||||
|
|
|
@ -13,5 +13,9 @@ interface IForwardWrapper {
|
|||
bytes[] memory signedVaas
|
||||
) external payable returns (bool callToTargetContractSucceeded, uint256 transactionFeeRefundAmount);
|
||||
|
||||
function safeRelayProviderSupportsChain(IRelayProvider relayProvider, uint16 chainId) external view returns(bool isSupported);
|
||||
function safeRelayProviderSupportsChain(IRelayProvider relayProvider, uint16 chainId)
|
||||
external
|
||||
view
|
||||
returns (bool isSupported);
|
||||
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@ import "../../interfaces/relayer/IWormholeRelayer.sol";
|
|||
import "./CoreRelayerDelivery.sol";
|
||||
import "../../interfaces/relayer/IWormholeRelayerInternalStructs.sol";
|
||||
|
||||
contract CoreRelayer is CoreRelayerDelivery {
|
||||
abstract contract CoreRelayer is CoreRelayerDelivery {
|
||||
/**
|
||||
* @notice This 'send' function emits a wormhole message (VAA) that alerts the default wormhole relay provider to
|
||||
* call the 'deliver' endpoint of the contract on chain 'targetChain' and address 'targetAddress'
|
||||
|
|
|
@ -9,7 +9,7 @@ import "./CoreRelayerGovernance.sol";
|
|||
import "../../interfaces/relayer/IWormholeRelayerInternalStructs.sol";
|
||||
import "./CoreRelayerMessages.sol";
|
||||
|
||||
contract CoreRelayerDelivery is CoreRelayerGovernance {
|
||||
abstract contract CoreRelayerDelivery is CoreRelayerGovernance {
|
||||
enum DeliveryStatus {
|
||||
SUCCESS,
|
||||
RECEIVER_FAILURE,
|
||||
|
|
|
@ -9,19 +9,14 @@ import "../../interfaces/relayer/IWormholeRelayerInternalStructs.sol";
|
|||
import "./CoreRelayerState.sol";
|
||||
import "../../libraries/external/BytesLib.sol";
|
||||
|
||||
contract CoreRelayerGetters is CoreRelayerState {
|
||||
abstract contract CoreRelayerGetters is CoreRelayerState {
|
||||
using BytesLib for bytes;
|
||||
|
||||
function governanceActionIsConsumed(bytes32 hash) public view returns (bool) {
|
||||
return _state.consumedGovernanceActions[hash];
|
||||
}
|
||||
// immutable var set in implementation, not proxy state
|
||||
address immutable forwardWrapper;
|
||||
|
||||
function governanceChainId() public view returns (uint16) {
|
||||
return _state.provider.governanceChainId;
|
||||
}
|
||||
|
||||
function governanceContract() public view returns (bytes32) {
|
||||
return _state.provider.governanceContract;
|
||||
constructor(address _forwardWrapper) {
|
||||
forwardWrapper = _forwardWrapper;
|
||||
}
|
||||
|
||||
function isInitialized(address impl) public view returns (bool) {
|
||||
|
@ -52,12 +47,16 @@ contract CoreRelayerGetters is CoreRelayerState {
|
|||
return _state.defaultRelayProvider;
|
||||
}
|
||||
|
||||
function getForwardInstructions() public view returns (IWormholeRelayerInternalStructs.ForwardInstruction[] memory) {
|
||||
function getForwardInstructions()
|
||||
public
|
||||
view
|
||||
returns (IWormholeRelayerInternalStructs.ForwardInstruction[] memory)
|
||||
{
|
||||
return _state.forwardInstructions;
|
||||
}
|
||||
|
||||
function getWormholeRelayerCallerAddress() public view returns (address) {
|
||||
return _state.forwardWrapper;
|
||||
return forwardWrapper;
|
||||
}
|
||||
|
||||
function isContractLocked() internal view returns (bool) {
|
||||
|
|
|
@ -2,17 +2,17 @@
|
|||
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import "@openzeppelin/contracts/proxy/ERC1967/ERC1967Upgrade.sol";
|
||||
|
||||
import "../../libraries/external/BytesLib.sol";
|
||||
|
||||
import "./CoreRelayerGetters.sol";
|
||||
import "./CoreRelayerSetters.sol";
|
||||
import "../../interfaces/relayer/IWormholeRelayerInternalStructs.sol";
|
||||
import "../../interfaces/relayer/IForwardWrapper.sol";
|
||||
import "./CoreRelayerMessages.sol";
|
||||
|
||||
import "@openzeppelin/contracts/proxy/ERC1967/ERC1967Upgrade.sol";
|
||||
|
||||
import "../../interfaces/IWormhole.sol";
|
||||
import "./CoreRelayerLibrary.sol";
|
||||
|
||||
abstract contract CoreRelayerGovernance is
|
||||
CoreRelayerGetters,
|
||||
|
@ -22,109 +22,19 @@ abstract contract CoreRelayerGovernance is
|
|||
{
|
||||
using BytesLib for bytes;
|
||||
|
||||
error InvalidFork();
|
||||
error InvalidGovernanceVM(string reason);
|
||||
error WrongChainId(uint16 chainId);
|
||||
error InvalidChainId(uint16 chainId);
|
||||
error FailedToInitializeImplementation(string reason);
|
||||
|
||||
event ContractUpgraded(address indexed oldContract, address indexed newContract);
|
||||
|
||||
// "CoreRelayer" (left padded)
|
||||
bytes32 constant module = 0x000000000000000000000000000000000000000000436f726552656c61796572;
|
||||
|
||||
function submitContractUpgrade(bytes memory _vm) public {
|
||||
if (isFork()) {
|
||||
revert InvalidFork();
|
||||
}
|
||||
|
||||
(IWormhole.VM memory vm, bool valid, string memory reason) = verifyGovernanceVM(_vm);
|
||||
if (!valid) {
|
||||
revert InvalidGovernanceVM(string(reason));
|
||||
}
|
||||
|
||||
setConsumedGovernanceAction(vm.hash);
|
||||
|
||||
CoreRelayerLibrary.ContractUpgrade memory contractUpgrade = CoreRelayerLibrary.parseUpgrade(vm.payload, module);
|
||||
if (contractUpgrade.chain != chainId()) {
|
||||
revert WrongChainId(contractUpgrade.chain);
|
||||
}
|
||||
|
||||
upgradeImplementation(contractUpgrade.newContract);
|
||||
function submitContractUpgrade(bytes memory vaa) public {
|
||||
(bool success, bytes memory reason) = getWormholeRelayerCallerAddress().delegatecall(abi.encodeWithSignature("submitContractUpgrade(bytes)", vaa));
|
||||
require(success, string(reason));
|
||||
}
|
||||
|
||||
function registerCoreRelayerContract(bytes memory vaa) public {
|
||||
(IWormhole.VM memory vm, bool valid, string memory reason) = verifyGovernanceVM(vaa);
|
||||
if (!valid) {
|
||||
revert InvalidGovernanceVM(string(reason));
|
||||
}
|
||||
|
||||
setConsumedGovernanceAction(vm.hash);
|
||||
|
||||
CoreRelayerLibrary.RegisterChain memory rc = CoreRelayerLibrary.parseRegisterChain(vm.payload, module);
|
||||
|
||||
if ((rc.chain != chainId() || isFork()) && rc.chain != 0) {
|
||||
revert InvalidChainId(rc.chain);
|
||||
}
|
||||
|
||||
setRegisteredCoreRelayerContract(rc.emitterChain, rc.emitterAddress);
|
||||
(bool success, bytes memory reason) = getWormholeRelayerCallerAddress().delegatecall(abi.encodeWithSignature("registerCoreRelayerContract(bytes)", vaa));
|
||||
require(success, string(reason));
|
||||
}
|
||||
|
||||
function setDefaultRelayProvider(bytes memory vaa) public {
|
||||
(IWormhole.VM memory vm, bool valid, string memory reason) = verifyGovernanceVM(vaa);
|
||||
if (!valid) {
|
||||
revert InvalidGovernanceVM(string(reason));
|
||||
}
|
||||
|
||||
setConsumedGovernanceAction(vm.hash);
|
||||
|
||||
CoreRelayerLibrary.UpdateDefaultProvider memory provider =
|
||||
CoreRelayerLibrary.parseUpdateDefaultProvider(vm.payload, module);
|
||||
|
||||
if ((provider.chain != chainId() || isFork()) && provider.chain != 0) {
|
||||
revert InvalidChainId(provider.chain);
|
||||
}
|
||||
|
||||
setRelayProvider(provider.newProvider);
|
||||
(bool success, bytes memory reason) = getWormholeRelayerCallerAddress().delegatecall(abi.encodeWithSignature("setDefaultRelayProvider(bytes)", vaa));
|
||||
require(success, string(reason));
|
||||
}
|
||||
|
||||
function upgradeImplementation(address newImplementation) internal {
|
||||
address currentImplementation = _getImplementation();
|
||||
|
||||
_upgradeTo(newImplementation);
|
||||
|
||||
// Call initialize function of the new implementation
|
||||
(bool success, bytes memory reason) = newImplementation.delegatecall(abi.encodeWithSignature("initialize()"));
|
||||
|
||||
if (!success) {
|
||||
revert FailedToInitializeImplementation(string(reason));
|
||||
}
|
||||
|
||||
emit ContractUpgraded(currentImplementation, newImplementation);
|
||||
}
|
||||
|
||||
function verifyGovernanceVM(bytes memory encodedVM)
|
||||
internal
|
||||
view
|
||||
returns (IWormhole.VM memory parsedVM, bool isValid, string memory invalidReason)
|
||||
{
|
||||
(IWormhole.VM memory vm, bool valid, string memory reason) = wormhole().parseAndVerifyVM(encodedVM);
|
||||
|
||||
if (!valid) {
|
||||
return (vm, valid, reason);
|
||||
}
|
||||
|
||||
if (vm.emitterChainId != governanceChainId()) {
|
||||
return (vm, false, "wrong governance chain");
|
||||
}
|
||||
if (vm.emitterAddress != governanceContract()) {
|
||||
return (vm, false, "wrong governance contract");
|
||||
}
|
||||
|
||||
if (governanceActionIsConsumed(vm.hash)) {
|
||||
return (vm, false, "governance action already consumed");
|
||||
}
|
||||
|
||||
return (vm, true, "");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,6 +9,8 @@ import "./CoreRelayer.sol";
|
|||
contract CoreRelayerImplementation is CoreRelayer {
|
||||
error ImplementationAlreadyInitialized();
|
||||
|
||||
constructor(address _forwardWrapper) CoreRelayerGetters(_forwardWrapper) {}
|
||||
|
||||
function initialize() public virtual initializer {
|
||||
// this function needs to be exposed for an upgrade to pass
|
||||
}
|
||||
|
|
|
@ -1,11 +1,52 @@
|
|||
// SPDX-License-Identifier: Apache 2
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import "../../libraries/external/BytesLib.sol";
|
||||
import "@openzeppelin/contracts/proxy/ERC1967/ERC1967Upgrade.sol";
|
||||
|
||||
library CoreRelayerLibrary {
|
||||
import "../../libraries/external/BytesLib.sol";
|
||||
import "../../interfaces/relayer/IForwardWrapper.sol";
|
||||
import "../../interfaces/IWormhole.sol";
|
||||
import "./CoreRelayerState.sol";
|
||||
import "../../interfaces/relayer/IForwardInstructionViewer.sol";
|
||||
|
||||
contract CoreRelayerLibrary is
|
||||
CoreRelayerState,
|
||||
ERC1967Upgrade {
|
||||
using BytesLib for bytes;
|
||||
|
||||
//structs, consts, errors, events
|
||||
struct ContractUpgrade {
|
||||
bytes32 module;
|
||||
uint8 action;
|
||||
uint16 chain;
|
||||
address newContract;
|
||||
}
|
||||
|
||||
struct RegisterChain {
|
||||
bytes32 module;
|
||||
uint8 action;
|
||||
uint16 chain; //TODO Why is this on this object?
|
||||
uint16 emitterChain;
|
||||
bytes32 emitterAddress;
|
||||
}
|
||||
|
||||
//This could potentially be combined with ContractUpgrade
|
||||
struct UpdateDefaultProvider {
|
||||
bytes32 module;
|
||||
uint8 action;
|
||||
uint16 chain;
|
||||
address newProvider;
|
||||
}
|
||||
|
||||
bytes32 constant module = 0x000000000000000000000000000000000000000000436f726552656c61796572;
|
||||
IForwardInstructionViewer public immutable forwardInstructionViewer;
|
||||
IWormhole immutable wormhole;
|
||||
|
||||
error InvalidFork();
|
||||
error InvalidGovernanceVM(string reason);
|
||||
error WrongChainId(uint16 chainId);
|
||||
error InvalidChainId(uint16 chainId);
|
||||
error FailedToInitializeImplementation(string reason);
|
||||
error WrongModule(bytes32 module);
|
||||
error InvalidContractUpgradeAction(uint8 action);
|
||||
error InvalidContractUpgradeLength(uint256 length);
|
||||
|
@ -13,9 +54,86 @@ library CoreRelayerLibrary {
|
|||
error InvalidRegisterChainLength(uint256);
|
||||
error InvalidDefaultProviderAction(uint8);
|
||||
error InvalidDefaultProviderLength(uint256);
|
||||
error RequesterNotCoreRelayer();
|
||||
|
||||
function parseUpgrade(bytes memory encodedUpgrade, bytes32 module)
|
||||
public
|
||||
event ContractUpgraded(address indexed oldContract, address indexed newContract);
|
||||
|
||||
//This modifier is used to ensure that only the wormhole relayer can call the functions in this contract via delegate call
|
||||
modifier onlyWormholeRelayer() {
|
||||
if (address(this) != address(forwardInstructionViewer)) {
|
||||
revert RequesterNotCoreRelayer();
|
||||
}
|
||||
_;
|
||||
}
|
||||
|
||||
constructor(address _wormholeRelayer, address _wormhole) {
|
||||
forwardInstructionViewer = IForwardInstructionViewer(_wormholeRelayer);
|
||||
wormhole = IWormhole(_wormhole);
|
||||
}
|
||||
|
||||
|
||||
//external functions
|
||||
function submitContractUpgrade(bytes memory _vm) external onlyWormholeRelayer {
|
||||
if (isFork()) {
|
||||
revert InvalidFork();
|
||||
}
|
||||
|
||||
(IWormhole.VM memory vm, bool valid, string memory reason) = verifyGovernanceVM(_vm);
|
||||
if (!valid) {
|
||||
revert InvalidGovernanceVM(string(reason));
|
||||
}
|
||||
|
||||
setConsumedGovernanceAction(vm.hash);
|
||||
|
||||
ContractUpgrade memory contractUpgrade = parseUpgrade(vm.payload);
|
||||
if (contractUpgrade.chain != chainId()) {
|
||||
revert WrongChainId(contractUpgrade.chain);
|
||||
}
|
||||
|
||||
upgradeImplementation(contractUpgrade.newContract);
|
||||
}
|
||||
|
||||
function registerCoreRelayerContract(bytes memory vaa) external onlyWormholeRelayer {
|
||||
(IWormhole.VM memory vm, bool valid, string memory reason) = verifyGovernanceVM(vaa);
|
||||
if (!valid) {
|
||||
revert InvalidGovernanceVM(string(reason));
|
||||
}
|
||||
|
||||
setConsumedGovernanceAction(vm.hash);
|
||||
|
||||
RegisterChain memory rc = parseRegisterChain(vm.payload);
|
||||
|
||||
if ((rc.chain != chainId() || isFork()) && rc.chain != 0) {
|
||||
revert InvalidChainId(rc.chain);
|
||||
}
|
||||
|
||||
setRegisteredCoreRelayerContract(rc.emitterChain, rc.emitterAddress);
|
||||
}
|
||||
|
||||
function setDefaultRelayProvider(bytes memory vaa) external onlyWormholeRelayer {
|
||||
(IWormhole.VM memory vm, bool valid, string memory reason) = verifyGovernanceVM(vaa);
|
||||
if (!valid) {
|
||||
revert InvalidGovernanceVM(string(reason));
|
||||
}
|
||||
|
||||
setConsumedGovernanceAction(vm.hash);
|
||||
|
||||
UpdateDefaultProvider memory provider = parseUpdateDefaultProvider(vm.payload);
|
||||
|
||||
if ((provider.chain != chainId() || isFork()) && provider.chain != 0) {
|
||||
revert InvalidChainId(provider.chain);
|
||||
}
|
||||
|
||||
setRelayProvider(provider.newProvider);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//parser functions
|
||||
function parseUpgrade(bytes memory encodedUpgrade)
|
||||
internal
|
||||
pure
|
||||
returns (ContractUpgrade memory cu)
|
||||
{
|
||||
|
@ -46,8 +164,8 @@ library CoreRelayerLibrary {
|
|||
}
|
||||
}
|
||||
|
||||
function parseRegisterChain(bytes memory encodedRegistration, bytes32 module)
|
||||
public
|
||||
function parseRegisterChain(bytes memory encodedRegistration)
|
||||
internal
|
||||
pure
|
||||
returns (RegisterChain memory registerChain)
|
||||
{
|
||||
|
@ -81,8 +199,8 @@ library CoreRelayerLibrary {
|
|||
}
|
||||
}
|
||||
|
||||
function parseUpdateDefaultProvider(bytes memory encodedDefaultProvider, bytes32 module)
|
||||
public
|
||||
function parseUpdateDefaultProvider(bytes memory encodedDefaultProvider)
|
||||
internal
|
||||
pure
|
||||
returns (UpdateDefaultProvider memory defaultProvider)
|
||||
{
|
||||
|
@ -113,26 +231,105 @@ library CoreRelayerLibrary {
|
|||
}
|
||||
}
|
||||
|
||||
struct ContractUpgrade {
|
||||
bytes32 module;
|
||||
uint8 action;
|
||||
uint16 chain;
|
||||
address newContract;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//helper functions
|
||||
function upgradeImplementation(address newImplementation) internal {
|
||||
address currentImplementation = _getImplementation();
|
||||
|
||||
_upgradeTo(newImplementation);
|
||||
|
||||
// Call initialize function of the new implementation
|
||||
(bool success, bytes memory reason) = newImplementation.delegatecall(abi.encodeWithSignature("initialize()"));
|
||||
|
||||
if (!success) {
|
||||
revert FailedToInitializeImplementation(string(reason));
|
||||
}
|
||||
|
||||
emit ContractUpgraded(currentImplementation, newImplementation);
|
||||
}
|
||||
|
||||
struct RegisterChain {
|
||||
bytes32 module;
|
||||
uint8 action;
|
||||
uint16 chain; //TODO Why is this on this object?
|
||||
uint16 emitterChain;
|
||||
bytes32 emitterAddress;
|
||||
function verifyGovernanceVM(bytes memory encodedVM)
|
||||
internal
|
||||
view
|
||||
returns (IWormhole.VM memory parsedVM, bool isValid, string memory invalidReason)
|
||||
{
|
||||
(IWormhole.VM memory vm, bool valid, string memory reason) = getWormholeState().parseAndVerifyVM(encodedVM);
|
||||
|
||||
if (!valid) {
|
||||
return (vm, valid, reason);
|
||||
}
|
||||
|
||||
if (vm.emitterChainId != governanceChainId()) {
|
||||
return (vm, false, "wrong governance chain");
|
||||
}
|
||||
if (vm.emitterAddress != governanceContract()) {
|
||||
return (vm, false, "wrong governance contract");
|
||||
}
|
||||
|
||||
if (governanceActionIsConsumed(vm.hash)) {
|
||||
return (vm, false, "governance action already consumed");
|
||||
}
|
||||
|
||||
return (vm, true, "");
|
||||
}
|
||||
|
||||
//This could potentially be combined with ContractUpgrade
|
||||
struct UpdateDefaultProvider {
|
||||
bytes32 module;
|
||||
uint8 action;
|
||||
uint16 chain;
|
||||
address newProvider;
|
||||
|
||||
|
||||
|
||||
|
||||
//setters
|
||||
function setConsumedGovernanceAction(bytes32 hash) internal {
|
||||
_state.consumedGovernanceActions[hash] = true;
|
||||
}
|
||||
|
||||
function setRelayProvider(address defaultRelayProvider) internal {
|
||||
_state.defaultRelayProvider = defaultRelayProvider;
|
||||
}
|
||||
|
||||
function setRegisteredCoreRelayerContract(uint16 targetChain, bytes32 relayerAddress) internal {
|
||||
_state.registeredCoreRelayerContract[targetChain] = relayerAddress;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//getters
|
||||
function getWormholeState() internal view returns (IWormhole) {
|
||||
return IWormhole(_state.provider.wormhole);
|
||||
}
|
||||
|
||||
function chainId() internal view returns (uint16) {
|
||||
return _state.provider.chainId;
|
||||
}
|
||||
|
||||
function evmChainId() internal view returns (uint256) {
|
||||
return _state.evmChainId;
|
||||
}
|
||||
|
||||
function isFork() internal view returns (bool) {
|
||||
return evmChainId() != block.chainid;
|
||||
}
|
||||
|
||||
function governanceActionIsConsumed(bytes32 hash) internal view returns (bool) {
|
||||
return _state.consumedGovernanceActions[hash];
|
||||
}
|
||||
|
||||
function governanceChainId() internal view returns (uint16) {
|
||||
return _state.provider.governanceChainId;
|
||||
}
|
||||
|
||||
function governanceContract() internal view returns (bytes32) {
|
||||
return _state.provider.governanceContract;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ import "../../interfaces/relayer/IWormholeRelayerInternalStructs.sol";
|
|||
import "../../interfaces/relayer/IWormholeRelayer.sol";
|
||||
import "../../interfaces/relayer/IDelivery.sol";
|
||||
|
||||
contract CoreRelayerMessages is CoreRelayerGetters {
|
||||
abstract contract CoreRelayerMessages is CoreRelayerGetters {
|
||||
using BytesLib for bytes;
|
||||
|
||||
error InvalidPayloadId(uint8 payloadId);
|
||||
|
|
|
@ -5,5 +5,5 @@ pragma solidity ^0.8.0;
|
|||
import "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol";
|
||||
|
||||
contract CoreRelayerProxy is ERC1967Proxy {
|
||||
constructor(address implementation, bytes memory initData) ERC1967Proxy(implementation, initData) {}
|
||||
constructor(address implementation) ERC1967Proxy(implementation, new bytes(0)) {}
|
||||
}
|
||||
|
|
|
@ -38,10 +38,6 @@ contract CoreRelayerSetters is CoreRelayerState, Context {
|
|||
_state.defaultRelayProvider = defaultRelayProvider;
|
||||
}
|
||||
|
||||
function setRegisteredCoreRelayerContract(uint16 chainId, bytes32 relayerAddress) internal {
|
||||
_state.registeredCoreRelayerContract[chainId] = relayerAddress;
|
||||
}
|
||||
|
||||
function appendForwardInstruction(IWormholeRelayerInternalStructs.ForwardInstruction memory forwardInstruction) internal {
|
||||
_state.forwardInstructions.push(forwardInstruction);
|
||||
}
|
||||
|
@ -58,10 +54,6 @@ contract CoreRelayerSetters is CoreRelayerState, Context {
|
|||
_state.targetAddress = targetAddress;
|
||||
}
|
||||
|
||||
function setForwardWrapper(address newForwardWrapperAddress) internal {
|
||||
_state.forwardWrapper = newForwardWrapperAddress;
|
||||
}
|
||||
|
||||
function setEvmChainId(uint256 evmChainId) internal {
|
||||
if (evmChainId != block.chainid) {
|
||||
revert InvalidEvmChainId();
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
pragma solidity ^0.8.0;
|
||||
|
||||
import "./CoreRelayerGovernance.sol";
|
||||
import "./ForwardWrapper.sol";
|
||||
|
||||
import "@openzeppelin/contracts/proxy/ERC1967/ERC1967Upgrade.sol";
|
||||
|
||||
|
@ -34,16 +33,12 @@ contract CoreRelayerSetup is CoreRelayerSetters, ERC1967Upgrade {
|
|||
}
|
||||
|
||||
setChainId(chainId);
|
||||
setEvmChainId(evmChainId);
|
||||
setGovernanceChainId(governanceChainId);
|
||||
|
||||
setWormhole(wormhole);
|
||||
|
||||
setRelayProvider(defaultRelayProvider);
|
||||
|
||||
setGovernanceChainId(governanceChainId);
|
||||
setGovernanceContract(governanceContract);
|
||||
setEvmChainId(evmChainId);
|
||||
|
||||
setForwardWrapper(address(new ForwardWrapper(address(this), wormhole)));
|
||||
|
||||
_upgradeTo(implementation);
|
||||
|
||||
|
|
|
@ -26,8 +26,6 @@ contract CoreRelayerStorage {
|
|||
address defaultRelayProvider;
|
||||
// Requests which will be forwarded from the current delivery.
|
||||
IWormholeRelayerInternalStructs.ForwardInstruction[] forwardInstructions;
|
||||
// Wrapper contract to facilitate forwards
|
||||
address forwardWrapper;
|
||||
// mapping of initialized implementations
|
||||
mapping(address => bool) initializedImplementations;
|
||||
// mapping of relayer contracts on other chains
|
||||
|
|
|
@ -10,17 +10,13 @@ import "../../interfaces/relayer/IWormholeRelayerInternalStructs.sol";
|
|||
import "../../interfaces/relayer/IForwardWrapper.sol";
|
||||
import "../../interfaces/relayer/IWormholeReceiver.sol";
|
||||
import "../../interfaces/relayer/IRelayProvider.sol";
|
||||
import {CoreRelayerLibrary} from "../coreRelayer/CoreRelayerLibrary.sol";
|
||||
|
||||
contract ForwardWrapper {
|
||||
IForwardInstructionViewer forwardInstructionViewer;
|
||||
IWormhole wormhole;
|
||||
contract ForwardWrapper is CoreRelayerLibrary {
|
||||
|
||||
error RequesterNotCoreRelayer();
|
||||
error ForwardNotSufficientlyFunded(uint256 amountOfFunds, uint256 amountOfFundsNeeded);
|
||||
|
||||
constructor(address _wormholeRelayer, address _wormhole) {
|
||||
forwardInstructionViewer = IForwardInstructionViewer(_wormholeRelayer);
|
||||
wormhole = IWormhole(_wormhole);
|
||||
constructor(address _wormholeRelayer, address _wormhole) CoreRelayerLibrary( _wormholeRelayer, _wormhole) {
|
||||
}
|
||||
|
||||
function executeInstruction(
|
||||
|
@ -56,7 +52,7 @@ contract ForwardWrapper {
|
|||
if (forwardInstructions.length > 0) {
|
||||
uint256 totalMsgValue = 0;
|
||||
uint256 totalFee = 0;
|
||||
for(uint8 i=0; i<forwardInstructions.length; i++) {
|
||||
for (uint8 i = 0; i < forwardInstructions.length; i++) {
|
||||
totalMsgValue += forwardInstructions[i].msgValue;
|
||||
totalFee += forwardInstructions[i].totalFee;
|
||||
}
|
||||
|
@ -71,7 +67,12 @@ contract ForwardWrapper {
|
|||
}
|
||||
}
|
||||
|
||||
function safeRelayProviderSupportsChain(IRelayProvider relayProvider, uint16 chainId) view external returns (bool isSupported){
|
||||
function safeRelayProviderSupportsChain(IRelayProvider relayProvider, uint16 chainId)
|
||||
external
|
||||
view
|
||||
returns (bool isSupported)
|
||||
{
|
||||
return relayProvider.isChainSupported(chainId);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
// SPDX-License-Identifier: Apache 2
|
||||
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import "@openzeppelin/contracts/utils/Create2.sol";
|
||||
|
||||
/**
|
||||
* Contract factory that facilitates predfictable deployment addresses
|
||||
*/
|
||||
contract Create2Factory {
|
||||
event Created(address);
|
||||
|
||||
/// @dev create2 hashes the userSalt with msg.sender, then uses the CREATE2 opcode to deterministically create a contract
|
||||
function create2(bytes memory userSalt, bytes memory bytecode) public payable returns (address payable) {
|
||||
address addr = Create2.deploy(msg.value, salt(msg.sender, userSalt), bytecode);
|
||||
emit Created(addr);
|
||||
return payable(addr);
|
||||
}
|
||||
|
||||
function computeAddress(address creator, bytes memory userSalt, bytes32 bytecodeHash)
|
||||
public
|
||||
view
|
||||
returns (address)
|
||||
{
|
||||
return Create2.computeAddress(salt(creator, userSalt), bytecodeHash);
|
||||
}
|
||||
|
||||
function salt(address creator, bytes memory userSalt) internal pure returns (bytes32) {
|
||||
return keccak256(abi.encodePacked(creator, userSalt));
|
||||
}
|
||||
}
|
|
@ -8,7 +8,9 @@ import {RelayProviderSetup} from "../../contracts/relayer/relayProvider/RelayPro
|
|||
import {RelayProviderImplementation} from "../../contracts/relayer/relayProvider/RelayProviderImplementation.sol";
|
||||
import {RelayProviderProxy} from "../../contracts/relayer/relayProvider/RelayProviderProxy.sol";
|
||||
import {IWormholeRelayer} from "../../contracts/interfaces/relayer/IWormholeRelayer.sol";
|
||||
import {ForwardWrapper} from "../../contracts/relayer/coreRelayer/ForwardWrapper.sol";
|
||||
import {CoreRelayer} from "../../contracts/relayer/coreRelayer/CoreRelayer.sol";
|
||||
import {Create2Factory} from "../../contracts/relayer/create2Factory/Create2Factory.sol";
|
||||
import {CoreRelayerSetup} from "../../contracts/relayer/coreRelayer/CoreRelayerSetup.sol";
|
||||
import {CoreRelayerImplementation} from "../../contracts/relayer/coreRelayer/CoreRelayerImplementation.sol";
|
||||
import {CoreRelayerProxy} from "../../contracts/relayer/coreRelayer/CoreRelayerProxy.sol";
|
||||
|
@ -106,23 +108,34 @@ contract TestHelpers {
|
|||
public
|
||||
returns (IWormholeRelayer coreRelayer)
|
||||
{
|
||||
CoreRelayerSetup coreRelayerSetup = new CoreRelayerSetup();
|
||||
CoreRelayerImplementation coreRelayerImplementation = new CoreRelayerImplementation();
|
||||
CoreRelayerProxy myCoreRelayer = new CoreRelayerProxy(
|
||||
address(coreRelayerSetup),
|
||||
abi.encodeCall(
|
||||
CoreRelayerSetup.setup,
|
||||
(
|
||||
address(coreRelayerImplementation),
|
||||
chainId,
|
||||
address(wormhole),
|
||||
defaultRelayProvider,
|
||||
wormhole.governanceChainId(),
|
||||
wormhole.governanceContract(),
|
||||
block.chainid
|
||||
)
|
||||
Create2Factory create2Factory = new Create2Factory();
|
||||
CoreRelayerSetup coreRelayerSetup =
|
||||
CoreRelayerSetup(create2Factory.create2("0xSetup", type(CoreRelayerSetup).creationCode));
|
||||
|
||||
address proxyAddressComputed = create2Factory.computeAddress(
|
||||
address(this),
|
||||
"0xGenericRelayer",
|
||||
keccak256(abi.encodePacked(type(CoreRelayerProxy).creationCode, abi.encode(address(coreRelayerSetup))))
|
||||
);
|
||||
ForwardWrapper forwardWrapper = new ForwardWrapper(proxyAddressComputed, address(wormhole));
|
||||
|
||||
CoreRelayerImplementation coreRelayerImplementation = new CoreRelayerImplementation(address(forwardWrapper));
|
||||
|
||||
CoreRelayerProxy myCoreRelayer = CoreRelayerProxy(
|
||||
create2Factory.create2(
|
||||
"0xGenericRelayer",
|
||||
abi.encodePacked(type(CoreRelayerProxy).creationCode, abi.encode(address(coreRelayerSetup)))
|
||||
)
|
||||
);
|
||||
CoreRelayerSetup(address(myCoreRelayer)).setup(
|
||||
address(coreRelayerImplementation),
|
||||
chainId,
|
||||
address(wormhole),
|
||||
defaultRelayProvider,
|
||||
wormhole.governanceChainId(),
|
||||
wormhole.governanceContract(),
|
||||
block.chainid
|
||||
);
|
||||
coreRelayer = IWormholeRelayer(address(myCoreRelayer));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@ import {CoreRelayerSetup} from "../../contracts/relayer/coreRelayer/CoreRelayerS
|
|||
import {CoreRelayerImplementation} from "../../contracts/relayer/coreRelayer/CoreRelayerImplementation.sol";
|
||||
import {CoreRelayerProxy} from "../../contracts/relayer/coreRelayer/CoreRelayerProxy.sol";
|
||||
import {CoreRelayerMessages} from "../../contracts/relayer/coreRelayer/CoreRelayerMessages.sol";
|
||||
import {ForwardWrapper} from "../../contracts/relayer/coreRelayer/ForwardWrapper.sol";
|
||||
import {CoreRelayerGovernance} from "../../contracts/relayer/coreRelayer/CoreRelayerGovernance.sol";
|
||||
import {MockGenericRelayer} from "./MockGenericRelayer.sol";
|
||||
import {MockWormhole} from "./MockWormhole.sol";
|
||||
|
@ -159,26 +160,11 @@ contract WormholeRelayerGovernanceTests is Test {
|
|||
}
|
||||
|
||||
function testUpgradeContractToItself() public {
|
||||
CoreRelayerSetup coreRelayerSetup = new CoreRelayerSetup();
|
||||
CoreRelayerImplementation coreRelayerImplementation = new CoreRelayerImplementation();
|
||||
CoreRelayerProxy myCoreRelayer = new CoreRelayerProxy(
|
||||
address(coreRelayerSetup),
|
||||
abi.encodeCall(
|
||||
CoreRelayerSetup.setup,
|
||||
(
|
||||
address(coreRelayerImplementation),
|
||||
1,
|
||||
address(wormhole),
|
||||
address(relayProvider),
|
||||
wormhole.governanceChainId(),
|
||||
wormhole.governanceContract(),
|
||||
block.chainid
|
||||
)
|
||||
)
|
||||
);
|
||||
address myCoreRelayer = address(helpers.setUpCoreRelayer(wormhole.chainId(), wormhole, address(relayProvider)));
|
||||
|
||||
for (uint256 i = 0; i < 10; i++) {
|
||||
CoreRelayerImplementation coreRelayerImplementationNew = new CoreRelayerImplementation();
|
||||
address forwardWrapper = address(new ForwardWrapper(myCoreRelayer, address(wormhole)));
|
||||
CoreRelayerImplementation coreRelayerImplementationNew = new CoreRelayerImplementation(forwardWrapper);
|
||||
|
||||
bytes memory message = abi.encodePacked(
|
||||
relayerModule,
|
||||
|
|
|
@ -37,8 +37,7 @@
|
|||
"abigen": "truffle run abigen",
|
||||
"deploy-relayers-evm1": "ENV=kubernetes CONTAINER=evm1 bash ./ts-scripts/relayer/shell/deployInContainer.sh",
|
||||
"deploy-relayers-evm2": "ENV=kubernetes CONTAINER=evm2 bash ./ts-scripts/relayer/shell/deployInContainer.sh",
|
||||
"relayer-tilt-test": "ENV=tilt WALLET_KEY=4f3edf983ac636a65a842ce7c78d9aa706d3b113bce9c46f30d7d21715b23b1d npx ts-mocha -t 1000000 ts-test/relayer/*.ts",
|
||||
"relayer-tilt-test-other": "ENV=tilt WALLET_KEY=4f3edf983ac636a65a842ce7c78d9aa706d3b113bce9c46f30d7d21715b23b1d ts-mocha -t 1000000 ts-test/relayer/*.ts",
|
||||
"relayer-tilt-test": "ENV=tilt WALLET_KEY=4f3edf983ac636a65a842ce7c78d9aa706d3b113bce9c46f30d7d21715b23b1d ts-mocha -t 1000000 ts-test/relayer/*.ts",
|
||||
"relayer-ci-test": "ENV=ci WALLET_KEY=4f3edf983ac636a65a842ce7c78d9aa706d3b113bce9c46f30d7d21715b23b1d npx ts-mocha -t 1000000 ts-test/relayer/*.ts"
|
||||
},
|
||||
"author": "",
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
@openzeppelin/=node_modules/@openzeppelin/
|
||||
@solidity-parser/=node_modules/@solidity-parser/
|
||||
ds-test/=lib/forge-std/lib/ds-test/src/
|
||||
forge-std/=lib/forge-std/src/
|
||||
truffle/=node_modules/truffle/
|
|
@ -1,4 +1,5 @@
|
|||
GUARDIAN_KEY=cfb12303a19cde580bb4dd771639b0d26bc68353645571a8cff516ab2ee113a0
|
||||
GUARDIAN_KEY2=c3b2e45c422a1602333a64078aeb42637370b0f48fe385f9cfa6ad54a8e0c47e
|
||||
WALLET_KEY=0x6370fd033278c143179d81c5526140625662b8daa446c22ee2d73db3707e620c
|
||||
#the wallet key is private key 2 on the ganache instance, it is a different private key than is used for other deployments, which is private key 0.
|
||||
# 0x22d491Bde2303f2f43325b2108D26f1eAbA1e32b is the public address
|
|
@ -1 +1 @@
|
|||
output/*
|
||||
output/**/*
|
|
@ -41,7 +41,7 @@ async function main() {
|
|||
throw Error("Failed to find contracts file for this process!");
|
||||
}
|
||||
const contracts = JSON.parse(contractsFile.toString());
|
||||
contracts.lastRun = true;
|
||||
contracts.useLastRun = true;
|
||||
writeFileSync(path, JSON.stringify(contracts, undefined, 2));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,31 +4,41 @@
|
|||
"relayProviders": [
|
||||
{
|
||||
"chainId": 2,
|
||||
"address": "0x83752ecAfeBf4707258dedFFbD9c7443148169db"
|
||||
"address": "0x1ef9e15c3bbf0555860b5009B51722027134d53a"
|
||||
},
|
||||
{
|
||||
"chainId": 4,
|
||||
"address": "0x83752ecAfeBf4707258dedFFbD9c7443148169db"
|
||||
"address": "0x1ef9e15c3bbf0555860b5009B51722027134d53a"
|
||||
}
|
||||
],
|
||||
"coreRelayers": [
|
||||
{
|
||||
"chainId": 2,
|
||||
"address": "0x0eb0dD3aa41bD15C706BC09bC03C002b7B85aeAC"
|
||||
"address": "0xFD66d75a5EF7755ef99345B344730af7cE47D2cD"
|
||||
},
|
||||
{
|
||||
"chainId": 4,
|
||||
"address": "0x0eb0dD3aa41bD15C706BC09bC03C002b7B85aeAC"
|
||||
"address": "0xFD66d75a5EF7755ef99345B344730af7cE47D2cD"
|
||||
}
|
||||
],
|
||||
"mockIntegrations": [
|
||||
{
|
||||
"chainId": 2,
|
||||
"address": "0xd80054abb128B007A6ef286b38D8082d50839bF7"
|
||||
"address": "0xD697292d18f9c6bc9e2aD089e823d562eD4A9766"
|
||||
},
|
||||
{
|
||||
"chainId": 4,
|
||||
"address": "0xd80054abb128B007A6ef286b38D8082d50839bF7"
|
||||
"address": "0xD697292d18f9c6bc9e2aD089e823d562eD4A9766"
|
||||
}
|
||||
],
|
||||
"create2Factories": [
|
||||
{
|
||||
"chainId": 2,
|
||||
"address": "0x17e91224c30c5b0B13ba2ef1E84FE880Cb902352"
|
||||
},
|
||||
{
|
||||
"chainId": 4,
|
||||
"address": "0x17e91224c30c5b0B13ba2ef1E84FE880Cb902352"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -4,31 +4,41 @@
|
|||
"relayProviders": [
|
||||
{
|
||||
"chainId": 2,
|
||||
"address": "0x83752ecAfeBf4707258dedFFbD9c7443148169db"
|
||||
"address": "0x1ef9e15c3bbf0555860b5009B51722027134d53a"
|
||||
},
|
||||
{
|
||||
"chainId": 4,
|
||||
"address": "0x83752ecAfeBf4707258dedFFbD9c7443148169db"
|
||||
"address": "0x1ef9e15c3bbf0555860b5009B51722027134d53a"
|
||||
}
|
||||
],
|
||||
"coreRelayers": [
|
||||
{
|
||||
"chainId": 2,
|
||||
"address": "0x0eb0dD3aa41bD15C706BC09bC03C002b7B85aeAC"
|
||||
"address": "0xFD66d75a5EF7755ef99345B344730af7cE47D2cD"
|
||||
},
|
||||
{
|
||||
"chainId": 4,
|
||||
"address": "0x0eb0dD3aa41bD15C706BC09bC03C002b7B85aeAC"
|
||||
"address": "0xFD66d75a5EF7755ef99345B344730af7cE47D2cD"
|
||||
}
|
||||
],
|
||||
"mockIntegrations": [
|
||||
{
|
||||
"chainId": 2,
|
||||
"address": "0xd80054abb128B007A6ef286b38D8082d50839bF7"
|
||||
"address": "0xD697292d18f9c6bc9e2aD089e823d562eD4A9766"
|
||||
},
|
||||
{
|
||||
"chainId": 4,
|
||||
"address": "0xd80054abb128B007A6ef286b38D8082d50839bF7"
|
||||
"address": "0xD697292d18f9c6bc9e2aD089e823d562eD4A9766"
|
||||
}
|
||||
],
|
||||
"create2Factories": [
|
||||
{
|
||||
"chainId": 2,
|
||||
"address": "0x17e91224c30c5b0B13ba2ef1E84FE880Cb902352"
|
||||
},
|
||||
{
|
||||
"chainId": 4,
|
||||
"address": "0x17e91224c30c5b0B13ba2ef1E84FE880Cb902352"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import { readFileSync, writeFileSync } from "fs";
|
||||
import {
|
||||
getCoreRelayer,
|
||||
getCreate2Factory,
|
||||
getMockIntegration,
|
||||
getRelayProvider,
|
||||
init,
|
||||
|
@ -18,6 +19,7 @@ interface ContractsJson {
|
|||
relayProviders: Address[];
|
||||
coreRelayers: Address[];
|
||||
mockIntegrations: Address[];
|
||||
create2Factories: Address[];
|
||||
}
|
||||
|
||||
async function main() {
|
||||
|
@ -29,6 +31,7 @@ async function main() {
|
|||
contracts.relayProviders = [] as any;
|
||||
contracts.coreRelayers = [] as any;
|
||||
contracts.mockIntegrations = [] as any;
|
||||
contracts.create2Factories = [] as any;
|
||||
for (const chain of chains) {
|
||||
update(contracts.relayProviders, {
|
||||
chainId: chain.chainId,
|
||||
|
@ -36,12 +39,16 @@ async function main() {
|
|||
});
|
||||
update(contracts.coreRelayers, {
|
||||
chainId: chain.chainId,
|
||||
address: getCoreRelayer(chain).address,
|
||||
address: (await getCoreRelayer(chain)).address,
|
||||
});
|
||||
update(contracts.mockIntegrations, {
|
||||
chainId: chain.chainId,
|
||||
address: getMockIntegration(chain).address,
|
||||
});
|
||||
update(contracts.create2Factories, {
|
||||
chainId: chain.chainId,
|
||||
address: getCreate2Factory(chain).address,
|
||||
});
|
||||
}
|
||||
const newStr = JSON.stringify(contracts, undefined, 2);
|
||||
console.log("New:");
|
||||
|
|
|
@ -1,34 +1,44 @@
|
|||
{
|
||||
"description": "This file contains the addresses for the contracts on each chain. If useLastRun is true, this file will be ignored, and the addresses will be taken from the lastrun.json of the deployment scripts.",
|
||||
"useLastRun": false,
|
||||
"useLastRun": true,
|
||||
"relayProviders": [
|
||||
{
|
||||
"chainId": 6,
|
||||
"address": "0x79357aA0CC8f1B4Bf3AC51Ae365cED1A83850870"
|
||||
"address": "0x58DFf38a3E97568CA2acfd95ca0901E8B4D3D3A8"
|
||||
},
|
||||
{
|
||||
"chainId": 14,
|
||||
"address": "0xd5A128895A4fe5b1E9615755698F65e45E42ee2f"
|
||||
"address": "0x64847cD62c8116231BD082d0b3E0eC93F205A7A3"
|
||||
}
|
||||
],
|
||||
"coreRelayers": [
|
||||
{
|
||||
"chainId": 6,
|
||||
"address": "0x607cE9D0f9Cd772Dab917507C331257FF561DBA5"
|
||||
"address": "0xeF5d96cC539dae286513A498f54B17f8b49ecae2"
|
||||
},
|
||||
{
|
||||
"chainId": 14,
|
||||
"address": "0x38bCfa6D311154824Bb98EE9D7e9bD6f5C706aab"
|
||||
"address": "0x4406CE49fD696C5eB1b30dfece71eb1b9322514d"
|
||||
}
|
||||
],
|
||||
"mockIntegrations": [
|
||||
{
|
||||
"chainId": 6,
|
||||
"address": "0x05cDBE523b45a33e866C5199394C7C559816CDaD"
|
||||
"address": "0x66dd3fBFf7fF50C074B6Bb159519dCa98ECC552F"
|
||||
},
|
||||
{
|
||||
"chainId": 14,
|
||||
"address": "0xC8865eFc8F73a8A3C3e590Bee9491F0EB5bf66b2"
|
||||
"address": "0xb9E73a5c623f241a6a676BA830cfB0C677b37ca1"
|
||||
}
|
||||
],
|
||||
"create2Factories": [
|
||||
{
|
||||
"chainId": 6,
|
||||
"address": "0xBD49c3FEd4d972D2125D6B12DaA93881E92eaA2d"
|
||||
},
|
||||
{
|
||||
"chainId": 14,
|
||||
"address": "0x030005bA700CE16b13c249B8029fc7d8f4e0b134"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"description": "This file contains the addresses for the contracts on each chain. If useLastRun is true, this file will be ignored, and the addresses will be taken from the lastrun.json of the deployment scripts.",
|
||||
"useLastRun": false,
|
||||
"useLastRun": true,
|
||||
"relayProviders": [
|
||||
{
|
||||
"chainId": 2,
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
import {
|
||||
deployCoreRelayerImplementation,
|
||||
deployCoreRelayerLibrary,
|
||||
deployCoreRelayerProxy,
|
||||
deployCoreRelayerSetup,
|
||||
deployForwardWrapper,
|
||||
} from "../helpers/deployments";
|
||||
import {
|
||||
init,
|
||||
loadChains,
|
||||
writeOutputFiles,
|
||||
getRelayProviderAddress,
|
||||
getOperatingChains,
|
||||
getCoreRelayerAddress,
|
||||
} from "../helpers/env";
|
||||
|
||||
const processName = "deployCoreRelayer";
|
||||
|
@ -28,10 +28,14 @@ async function run() {
|
|||
|
||||
for (const chain of chains) {
|
||||
console.log(`Deploying for chain ${chain.chainId}...`);
|
||||
const coreRelayerLibrary = await deployCoreRelayerLibrary(chain);
|
||||
const forwardWrapper = await deployForwardWrapper(
|
||||
chain,
|
||||
// uses create2 to determine address before deployment
|
||||
await getCoreRelayerAddress(chain)
|
||||
);
|
||||
const coreRelayerImplementation = await deployCoreRelayerImplementation(
|
||||
chain,
|
||||
coreRelayerLibrary.address
|
||||
forwardWrapper.address
|
||||
);
|
||||
const coreRelayerSetup = await deployCoreRelayerSetup(chain);
|
||||
const coreRelayerProxy = await deployCoreRelayerProxy(
|
||||
|
@ -42,7 +46,7 @@ async function run() {
|
|||
getRelayProviderAddress(chain)
|
||||
);
|
||||
|
||||
output.coreRelayerLibraries.push(coreRelayerLibrary);
|
||||
output.coreRelayerLibraries.push(forwardWrapper);
|
||||
output.coreRelayerImplementations.push(coreRelayerImplementation);
|
||||
output.coreRelayerSetups.push(coreRelayerSetup);
|
||||
output.coreRelayerProxies.push(coreRelayerProxy);
|
||||
|
|
|
@ -1,37 +0,0 @@
|
|||
import {
|
||||
deployCoreRelayerImplementation,
|
||||
deployCoreRelayerLibrary,
|
||||
} from "../helpers/deployments";
|
||||
import {
|
||||
getOperatingChains,
|
||||
init,
|
||||
loadChains,
|
||||
writeOutputFiles,
|
||||
} from "../helpers/env";
|
||||
|
||||
const processName = "deployCoreRelayerImpl";
|
||||
init();
|
||||
const chains = getOperatingChains();
|
||||
|
||||
async function run() {
|
||||
console.log("Start! " + processName);
|
||||
|
||||
const output: any = {
|
||||
coreRelayerLibraries: [],
|
||||
coreRelayerImplementations: [],
|
||||
};
|
||||
|
||||
for (let i = 0; i < chains.length; i++) {
|
||||
const coreRelayerLibrary = await deployCoreRelayerLibrary(chains[i]);
|
||||
const coreRelayerImplementation = await deployCoreRelayerImplementation(
|
||||
chains[i],
|
||||
coreRelayerLibrary.address
|
||||
);
|
||||
output.coreRelayerImplementations.push(coreRelayerImplementation);
|
||||
output.coreRelayerLibraries.push(coreRelayerLibrary);
|
||||
}
|
||||
|
||||
writeOutputFiles(output, processName);
|
||||
}
|
||||
|
||||
run().then(() => console.log("Done! " + processName));
|
|
@ -50,8 +50,8 @@ async function readState(
|
|||
);
|
||||
|
||||
try {
|
||||
const coreRelayer = getCoreRelayer(chain, getProvider(chain));
|
||||
const contractAddress = getCoreRelayerAddress(chain);
|
||||
const coreRelayer = await getCoreRelayer(chain, getProvider(chain));
|
||||
const contractAddress = await getCoreRelayerAddress(chain);
|
||||
const defaultProvider = await coreRelayer.getDefaultRelayProvider();
|
||||
const registeredContracts: { chainId: number; contract: string }[] = [];
|
||||
|
||||
|
@ -59,7 +59,7 @@ async function readState(
|
|||
registeredContracts.push({
|
||||
chainId: chainInfo.chainId,
|
||||
contract: (
|
||||
await coreRelayer.registeredCoreRelayerContract(chain.chainId)
|
||||
await coreRelayer.registeredCoreRelayerContract(chainInfo.chainId)
|
||||
).toString(),
|
||||
});
|
||||
}
|
||||
|
|
|
@ -30,7 +30,7 @@ async function run() {
|
|||
async function registerChainsCoreRelayer(chain: ChainInfo) {
|
||||
console.log("registerChainsCoreRelayer " + chain.chainId);
|
||||
|
||||
const coreRelayer = getCoreRelayer(chain);
|
||||
const coreRelayer = await getCoreRelayer(chain);
|
||||
for (const targetChain of chains) {
|
||||
await coreRelayer
|
||||
.registerCoreRelayerContract(createRegisterChainVAA(targetChain))
|
||||
|
|
|
@ -51,7 +51,7 @@ async function upgradeCoreRelayer(
|
|||
) {
|
||||
console.log("upgradeCoreRelayer " + chain.chainId);
|
||||
|
||||
const coreRelayer = getCoreRelayer(chain);
|
||||
const coreRelayer = await getCoreRelayer(chain);
|
||||
|
||||
await coreRelayer.submitContractUpgrade(
|
||||
createCoreRelayerUpgradeVAA(chain, newImplementationAddress)
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
import {
|
||||
init,
|
||||
loadChains,
|
||||
writeOutputFiles,
|
||||
getMockIntegration,
|
||||
Deployment,
|
||||
getOperatingChains,
|
||||
getMockIntegrationAddress,
|
||||
} from "../helpers/env";
|
||||
import { deployCreate2Factory } from "../helpers/deployments";
|
||||
import { BigNumberish, BytesLike } from "ethers";
|
||||
import { tryNativeToHexString } from "@certusone/wormhole-sdk";
|
||||
import { wait } from "../helpers/utils";
|
||||
|
||||
const processName = "deployCreate2Factory";
|
||||
init();
|
||||
const chains = loadChains();
|
||||
const operatingChains = getOperatingChains();
|
||||
|
||||
async function run() {
|
||||
console.log("Start!");
|
||||
|
||||
const create2Factories = await Promise.all(
|
||||
operatingChains.map(deployCreate2Factory)
|
||||
);
|
||||
|
||||
writeOutputFiles({ create2Factories }, processName);
|
||||
}
|
||||
|
||||
run().then(() => console.log("Done!"));
|
|
@ -1,11 +1,10 @@
|
|||
import { RelayProviderProxy__factory } from "../../../ethers-contracts/factories/RelayProviderProxy__factory";
|
||||
import { RelayProviderSetup__factory } from "../../../ethers-contracts/factories/RelayProviderSetup__factory";
|
||||
import { RelayProviderImplementation__factory } from "../../../ethers-contracts/factories/RelayProviderImplementation__factory";
|
||||
import { MockRelayerIntegration__factory } from "../../../ethers-contracts/factories/MockRelayerIntegration__factory";
|
||||
import { CoreRelayerProxy__factory } from "../../../ethers-contracts/factories/CoreRelayerProxy__factory";
|
||||
import { CoreRelayerSetup__factory } from "../../../ethers-contracts/factories/CoreRelayerSetup__factory";
|
||||
import { CoreRelayerImplementation__factory } from "../../../ethers-contracts/factories/CoreRelayerImplementation__factory";
|
||||
import { CoreRelayerLibrary__factory } from "../../../ethers-contracts/factories/CoreRelayerLibrary__factory";
|
||||
import { RelayProviderProxy__factory } from "../../../ethers-contracts";
|
||||
import { RelayProviderSetup__factory } from "../../../ethers-contracts";
|
||||
import { RelayProviderImplementation__factory } from "../../../ethers-contracts";
|
||||
import { MockRelayerIntegration__factory } from "../../../ethers-contracts";
|
||||
import { CoreRelayerProxy__factory } from "../../../ethers-contracts";
|
||||
import { CoreRelayerSetup__factory } from "../../../ethers-contracts";
|
||||
import { CoreRelayerImplementation__factory } from "../../../ethers-contracts";
|
||||
|
||||
import {
|
||||
init,
|
||||
|
@ -16,8 +15,19 @@ import {
|
|||
Deployment,
|
||||
getSigner,
|
||||
getCoreRelayerAddress,
|
||||
getCreate2Factory,
|
||||
getCoreRelayer,
|
||||
fetchSetupAddressCreate2,
|
||||
} from "./env";
|
||||
import { ethers } from "ethers";
|
||||
import {
|
||||
Create2Factory__factory,
|
||||
ForwardWrapper__factory,
|
||||
} from "../../../ethers-contracts";
|
||||
import { wait } from "./utils";
|
||||
|
||||
export const setupContractSalt = Buffer.from("0xSetup");
|
||||
export const proxyContractSalt = Buffer.from("0xGenericRelayer");
|
||||
|
||||
export async function deployRelayProviderImplementation(
|
||||
chain: ChainInfo
|
||||
|
@ -105,7 +115,7 @@ export async function deployMockIntegration(
|
|||
);
|
||||
const contract = await factory.deploy(
|
||||
chain.wormholeAddress,
|
||||
getCoreRelayerAddress(chain)
|
||||
await getCoreRelayerAddress(chain)
|
||||
);
|
||||
return await contract.deployed().then((result) => {
|
||||
console.log("Successfully deployed contract at " + result.address);
|
||||
|
@ -113,78 +123,60 @@ export async function deployMockIntegration(
|
|||
});
|
||||
}
|
||||
|
||||
export async function deployCoreRelayerLibrary(
|
||||
export async function deployCreate2Factory(
|
||||
chain: ChainInfo
|
||||
): Promise<Deployment> {
|
||||
console.log("deployCreate2Factory " + chain.chainId);
|
||||
|
||||
const result = await new Create2Factory__factory(getSigner(chain))
|
||||
.deploy()
|
||||
.then(deployed);
|
||||
console.log(`Successfully deployed contract at ${result.address}`);
|
||||
return { address: result.address, chainId: chain.chainId };
|
||||
}
|
||||
|
||||
export async function deployForwardWrapper(
|
||||
chain: ChainInfo,
|
||||
coreRelayerProxyAddress: string
|
||||
): Promise<Deployment> {
|
||||
console.log("deployCoreRelayerLibrary " + chain.chainId);
|
||||
|
||||
let signer = getSigner(chain);
|
||||
const contractInterface = CoreRelayerLibrary__factory.createInterface();
|
||||
const bytecode = CoreRelayerLibrary__factory.bytecode;
|
||||
const factory = new ethers.ContractFactory(
|
||||
contractInterface,
|
||||
bytecode,
|
||||
signer
|
||||
);
|
||||
const contract = await factory.deploy();
|
||||
return await contract.deployed().then((result) => {
|
||||
console.log("Successfully deployed contract at " + result.address);
|
||||
return { address: result.address, chainId: chain.chainId };
|
||||
});
|
||||
const result = await new ForwardWrapper__factory(getSigner(chain))
|
||||
.deploy(coreRelayerProxyAddress, chain.wormholeAddress)
|
||||
.then(deployed);
|
||||
console.log("Successfully deployed contract at " + result.address);
|
||||
return { address: result.address, chainId: chain.chainId };
|
||||
}
|
||||
|
||||
export async function deployCoreRelayerImplementation(
|
||||
chain: ChainInfo,
|
||||
coreRelayerLibraryAddress: string
|
||||
forwardWrapperAddress: string
|
||||
): Promise<Deployment> {
|
||||
console.log("deployCoreRelayerImplementation " + chain.chainId);
|
||||
const signer = getSigner(chain);
|
||||
const contractInterface = CoreRelayerImplementation__factory.createInterface();
|
||||
const bytecode: string = CoreRelayerImplementation__factory.bytecode;
|
||||
|
||||
/*
|
||||
Linked libraries in EVM are contained in the bytecode and linked at compile time.
|
||||
However, the linked address of the CoreRelayerLibrary is not known until deployment time,
|
||||
So, rather that recompiling the contracts with a static link, we modify the bytecode directly
|
||||
once we have the CoreRelayLibraryAddress.
|
||||
*/
|
||||
const bytecodeWithLibraryLink = link(
|
||||
bytecode,
|
||||
"CoreRelayerLibrary",
|
||||
coreRelayerLibraryAddress
|
||||
);
|
||||
const result = await new CoreRelayerImplementation__factory(getSigner(chain))
|
||||
.deploy(forwardWrapperAddress)
|
||||
.then(deployed);
|
||||
|
||||
//@ts-ignore
|
||||
const factory = new ethers.ContractFactory(
|
||||
contractInterface,
|
||||
bytecodeWithLibraryLink,
|
||||
signer
|
||||
);
|
||||
const contract = await factory.deploy();
|
||||
return await contract.deployed().then((result) => {
|
||||
console.log("Successfully deployed contract at " + result.address);
|
||||
return { address: result.address, chainId: chain.chainId };
|
||||
});
|
||||
console.log("Successfully deployed contract at " + result.address);
|
||||
return { address: result.address, chainId: chain.chainId };
|
||||
}
|
||||
export async function deployCoreRelayerSetup(
|
||||
chain: ChainInfo
|
||||
): Promise<Deployment> {
|
||||
console.log("deployCoreRelayerSetup " + chain.chainId);
|
||||
const signer = getSigner(chain);
|
||||
const contractInterface = CoreRelayerSetup__factory.createInterface();
|
||||
const bytecode = CoreRelayerSetup__factory.bytecode;
|
||||
//@ts-ignore
|
||||
const factory = new ethers.ContractFactory(
|
||||
contractInterface,
|
||||
bytecode,
|
||||
signer
|
||||
);
|
||||
const contract = await factory.deploy();
|
||||
return await contract.deployed().then((result) => {
|
||||
console.log("Successfully deployed contract at " + result.address);
|
||||
return { address: result.address, chainId: chain.chainId };
|
||||
});
|
||||
|
||||
const create2Factory = getCreate2Factory(chain);
|
||||
const rx = await create2Factory
|
||||
.create2(setupContractSalt, CoreRelayerSetup__factory.bytecode)
|
||||
.then(wait);
|
||||
const address = Create2Factory__factory.createInterface().parseLog(rx.logs[0])
|
||||
.args[0];
|
||||
|
||||
console.log("Successfully deployed contract at " + address);
|
||||
return { address, chainId: chain.chainId };
|
||||
}
|
||||
|
||||
export async function deployCoreRelayerProxy(
|
||||
chain: ChainInfo,
|
||||
coreRelayerSetupAddress: string,
|
||||
|
@ -193,40 +185,47 @@ export async function deployCoreRelayerProxy(
|
|||
relayProviderProxyAddress: string
|
||||
): Promise<Deployment> {
|
||||
console.log("deployCoreRelayerProxy " + chain.chainId);
|
||||
const signer = getSigner(chain);
|
||||
const contractInterface = CoreRelayerProxy__factory.createInterface();
|
||||
const bytecode = CoreRelayerProxy__factory.bytecode;
|
||||
//@ts-ignore
|
||||
const factory = new ethers.ContractFactory(
|
||||
contractInterface,
|
||||
bytecode,
|
||||
signer
|
||||
);
|
||||
|
||||
const create2Factory = getCreate2Factory(chain);
|
||||
const expectedSetupAddr = await fetchSetupAddressCreate2(
|
||||
chain,
|
||||
create2Factory
|
||||
);
|
||||
if (coreRelayerSetupAddress !== expectedSetupAddr) {
|
||||
throw new Error(
|
||||
`coreRelayerSetupAddress different than expected. Expected: ${expectedSetupAddr} Actual: ${coreRelayerSetupAddress}`
|
||||
);
|
||||
}
|
||||
|
||||
// deploy proxy and point at setup contract
|
||||
const data = new CoreRelayerProxy__factory().getDeployTransaction(
|
||||
coreRelayerSetupAddress
|
||||
).data!;
|
||||
const rx = await create2Factory.create2(proxyContractSalt, data).then(wait);
|
||||
|
||||
// call setup
|
||||
const governanceChainId = 1;
|
||||
const governanceContract =
|
||||
"0x0000000000000000000000000000000000000000000000000000000000000004";
|
||||
|
||||
let ABI = [
|
||||
"function setup(address,uint16,address,address,uint16,bytes32,uint256)",
|
||||
];
|
||||
let iface = new ethers.utils.Interface(ABI);
|
||||
let encodedData = iface.encodeFunctionData("setup", [
|
||||
coreRelayerImplementationAddress,
|
||||
chain.chainId,
|
||||
wormholeAddress,
|
||||
relayProviderProxyAddress,
|
||||
governanceChainId,
|
||||
governanceContract,
|
||||
chain.evmNetworkId,
|
||||
]);
|
||||
|
||||
const contract = await factory.deploy(coreRelayerSetupAddress, encodedData);
|
||||
return await contract.deployed().then((result) => {
|
||||
console.log("Successfully deployed contract at " + result.address);
|
||||
return { address: result.address, chainId: chain.chainId };
|
||||
});
|
||||
const proxy = CoreRelayerSetup__factory.connect(
|
||||
await getCoreRelayerAddress(chain),
|
||||
getSigner(chain)
|
||||
);
|
||||
await proxy
|
||||
.setup(
|
||||
coreRelayerImplementationAddress,
|
||||
chain.chainId,
|
||||
wormholeAddress,
|
||||
relayProviderProxyAddress,
|
||||
governanceChainId,
|
||||
governanceContract,
|
||||
chain.evmNetworkId
|
||||
)
|
||||
.then(wait);
|
||||
console.log("Successfully deployed contract at " + proxy.address);
|
||||
return { address: proxy.address, chainId: chain.chainId };
|
||||
}
|
||||
|
||||
function link(bytecode: string, libName: String, libAddress: string) {
|
||||
//This doesn't handle the libName, because Forge embed a psuedonym into the bytecode, like
|
||||
//__$a7dd444e34bd28bbe3641e0101a6826fa7$__
|
||||
|
@ -235,3 +234,5 @@ function link(bytecode: string, libName: String, libAddress: string) {
|
|||
let symbol = /__.*?__/g;
|
||||
return bytecode.replace(symbol, libAddress.toLowerCase().substr(2));
|
||||
}
|
||||
|
||||
const deployed = (x: ethers.Contract) => x.deployed();
|
||||
|
|
|
@ -1,14 +1,21 @@
|
|||
import type { ChainId } from "@certusone/wormhole-sdk";
|
||||
import { ChainId } from "@certusone/wormhole-sdk";
|
||||
import { ethers, Signer } from "ethers";
|
||||
import fs from "fs";
|
||||
|
||||
import { CoreRelayer } from "../../../ethers-contracts/CoreRelayer";
|
||||
import { RelayProvider } from "../../../ethers-contracts/RelayProvider";
|
||||
import { MockRelayerIntegration } from "../../../ethers-contracts/MockRelayerIntegration";
|
||||
import { CoreRelayer } from "../../../ethers-contracts";
|
||||
import { RelayProvider } from "../../../ethers-contracts";
|
||||
import { MockRelayerIntegration } from "../../../ethers-contracts";
|
||||
|
||||
import { RelayProvider__factory } from "../../../ethers-contracts/factories/RelayProvider__factory";
|
||||
import { CoreRelayer__factory } from "../../../ethers-contracts/factories/CoreRelayer__factory";
|
||||
import { MockRelayerIntegration__factory } from "../../../ethers-contracts/factories/MockRelayerIntegration__factory";
|
||||
import { RelayProvider__factory } from "../../../ethers-contracts";
|
||||
import { CoreRelayer__factory } from "../../../ethers-contracts";
|
||||
import { MockRelayerIntegration__factory } from "../../../ethers-contracts";
|
||||
import {
|
||||
CoreRelayerProxy__factory,
|
||||
Create2Factory,
|
||||
Create2Factory__factory,
|
||||
} from "../../../ethers-contracts";
|
||||
import { CoreRelayerSetup__factory } from "../../../ethers-contracts";
|
||||
import { proxyContractSalt, setupContractSalt } from "./deployments";
|
||||
|
||||
export type ChainInfo = {
|
||||
evmNetworkId: number;
|
||||
|
@ -216,19 +223,61 @@ export function loadMockIntegrations(): Deployment[] {
|
|||
}
|
||||
}
|
||||
|
||||
export function loadCreate2Factories(): Deployment[] {
|
||||
const contractsFile = fs.readFileSync(
|
||||
`./ts-scripts/relayer/config/${env}/contracts.json`
|
||||
);
|
||||
if (!contractsFile) {
|
||||
throw Error("Failed to find contracts file for this process!");
|
||||
}
|
||||
const contracts = JSON.parse(contractsFile.toString());
|
||||
if (contracts.useLastRun || lastRunOverride) {
|
||||
const lastRunFile = fs.readFileSync(
|
||||
`./ts-scripts/relayer/output/${env}/deployCreate2Factory/lastrun.json`
|
||||
);
|
||||
if (!lastRunFile) {
|
||||
throw Error(
|
||||
"Failed to find last run file for the deployCreate2Factory process!"
|
||||
);
|
||||
}
|
||||
const lastRun = JSON.parse(lastRunFile.toString());
|
||||
return lastRun.create2Factories;
|
||||
} else {
|
||||
return contracts.create2Factories;
|
||||
}
|
||||
}
|
||||
|
||||
//TODO load these keys more intelligently,
|
||||
//potentially from devnet-consts
|
||||
//potentially from devnet-consts.
|
||||
//Also, make sure the signers are correctly ordered by index,
|
||||
//As the index gets encoded into the signature.
|
||||
export function loadGuardianKeys(): string[] {
|
||||
const output = [];
|
||||
const NUM_GUARDIANS = get_env_var("NUM_GUARDIANS");
|
||||
const guardianKey = get_env_var("GUARDIAN_KEY");
|
||||
const guardianKey2 = get_env_var("GUARDIAN_KEY2");
|
||||
|
||||
let numGuardians: number = 0;
|
||||
console.log("NUM_GUARDIANS variable : " + NUM_GUARDIANS);
|
||||
|
||||
if (!NUM_GUARDIANS) {
|
||||
numGuardians = 1;
|
||||
} else {
|
||||
numGuardians = parseInt(NUM_GUARDIANS);
|
||||
}
|
||||
|
||||
if (!guardianKey) {
|
||||
throw Error("Failed to find guardian key for this process!");
|
||||
}
|
||||
if(guardianKey2) {
|
||||
output.push(guardianKey2);
|
||||
}
|
||||
output.push(guardianKey);
|
||||
|
||||
if (numGuardians >= 2) {
|
||||
if (!guardianKey2) {
|
||||
throw Error("Failed to find guardian key 2 for this process!");
|
||||
}
|
||||
output.push(guardianKey2);
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
|
@ -248,7 +297,7 @@ export function writeOutputFiles(output: any, processName: string) {
|
|||
);
|
||||
}
|
||||
|
||||
export function getSigner(chain: ChainInfo): Signer {
|
||||
export function getSigner(chain: ChainInfo): ethers.Wallet {
|
||||
let provider = getProvider(chain);
|
||||
let signer = new ethers.Wallet(loadPrivateKey(), provider);
|
||||
return signer;
|
||||
|
@ -289,28 +338,73 @@ export function getRelayProvider(
|
|||
return contract;
|
||||
}
|
||||
|
||||
export function getCoreRelayerAddress(chain: ChainInfo): string {
|
||||
const thisChainsRelayer = loadCoreRelayers().find(
|
||||
(x: any) => x.chainId == chain.chainId
|
||||
)?.address;
|
||||
if (!thisChainsRelayer) {
|
||||
throw new Error(
|
||||
"Failed to find a CoreRelayer contract address on chain " + chain.chainId
|
||||
);
|
||||
}
|
||||
return thisChainsRelayer;
|
||||
export function fetchSetupAddressCreate2(
|
||||
chain: ChainInfo,
|
||||
create2Factory = getCreate2Factory(chain)
|
||||
): Promise<string> {
|
||||
const signer = getSigner(chain).address;
|
||||
return create2Factory.computeAddress(
|
||||
signer,
|
||||
setupContractSalt,
|
||||
ethers.utils.solidityKeccak256(
|
||||
["bytes"],
|
||||
[CoreRelayerSetup__factory.bytecode]
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
export function getCoreRelayer(
|
||||
const coreRelayerAddressesCache: Partial<Record<ChainId, string>> = {};
|
||||
export async function getCoreRelayerAddress(chain: ChainInfo): Promise<string> {
|
||||
const contractsFile = fs.readFileSync(
|
||||
`./ts-scripts/relayer/config/${env}/contracts.json`
|
||||
);
|
||||
if (!contractsFile) {
|
||||
throw Error("Failed to find contracts file for this process!");
|
||||
}
|
||||
const contracts = JSON.parse(contractsFile.toString());
|
||||
//If useLastRun is false, then we want to bypass the calculations and just use what the contracts file says.
|
||||
if (!contracts.useLastRun && !lastRunOverride) {
|
||||
const thisChainsRelayer = loadCoreRelayers().find(
|
||||
(x: any) => x.chainId == chain.chainId
|
||||
)?.address;
|
||||
if (thisChainsRelayer) {
|
||||
return thisChainsRelayer;
|
||||
} else {
|
||||
throw Error(
|
||||
"Failed to find a CoreRelayer contract address on chain " +
|
||||
chain.chainId
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (!coreRelayerAddressesCache[chain.chainId]) {
|
||||
const create2Factory = getCreate2Factory(chain);
|
||||
const signer = getSigner(chain).address;
|
||||
const setupAddr = await fetchSetupAddressCreate2(chain, create2Factory);
|
||||
|
||||
const data = new CoreRelayerProxy__factory().getDeployTransaction(setupAddr)
|
||||
.data!;
|
||||
coreRelayerAddressesCache[
|
||||
chain.chainId
|
||||
] = await create2Factory.computeAddress(
|
||||
signer,
|
||||
proxyContractSalt,
|
||||
ethers.utils.solidityKeccak256(["bytes"], [data])
|
||||
);
|
||||
}
|
||||
|
||||
return coreRelayerAddressesCache[chain.chainId]!;
|
||||
}
|
||||
|
||||
export async function getCoreRelayer(
|
||||
chain: ChainInfo,
|
||||
provider?: ethers.providers.StaticJsonRpcProvider
|
||||
): CoreRelayer {
|
||||
const thisChainsRelayer = getCoreRelayerAddress(chain);
|
||||
const contract = CoreRelayer__factory.connect(
|
||||
): Promise<CoreRelayer> {
|
||||
const thisChainsRelayer = await getCoreRelayerAddress(chain);
|
||||
return CoreRelayer__factory.connect(
|
||||
thisChainsRelayer,
|
||||
provider || getSigner(chain)
|
||||
);
|
||||
return contract;
|
||||
}
|
||||
|
||||
export function getMockIntegrationAddress(chain: ChainInfo): string {
|
||||
|
@ -334,3 +428,22 @@ export function getMockIntegration(chain: ChainInfo): MockRelayerIntegration {
|
|||
);
|
||||
return contract;
|
||||
}
|
||||
|
||||
export function getCreate2FactoryAddress(chain: ChainInfo): string {
|
||||
const address = loadCreate2Factories().find(
|
||||
(x: any) => x.chainId == chain.chainId
|
||||
)?.address;
|
||||
if (!address) {
|
||||
throw new Error(
|
||||
"Failed to find a create2Factory contract address on chain " +
|
||||
chain.chainId
|
||||
);
|
||||
}
|
||||
return address;
|
||||
}
|
||||
|
||||
export const getCreate2Factory = (chain: ChainInfo): Create2Factory =>
|
||||
Create2Factory__factory.connect(
|
||||
getCreate2FactoryAddress(chain),
|
||||
getSigner(chain)
|
||||
);
|
||||
|
|
|
@ -61,8 +61,11 @@ export function createDefaultRelayProviderVAA(chain: ChainInfo) {
|
|||
return encodeAndSignGovernancePayload(payload);
|
||||
}
|
||||
|
||||
export function createRegisterChainVAA(chain: ChainInfo): string {
|
||||
const coreRelayerAddress = getCoreRelayerAddress(chain);
|
||||
export async function createRegisterChainVAA(
|
||||
chain: ChainInfo
|
||||
): Promise<string> {
|
||||
const coreRelayerAddress = await getCoreRelayerAddress(chain);
|
||||
console.log(`Registering ${coreRelayerAddress} on chain ${chain.chainId}`);
|
||||
|
||||
// bytes32 module;
|
||||
// uint8 action;
|
||||
|
@ -105,18 +108,18 @@ export function encodeAndSignGovernancePayload(payload: string): string {
|
|||
|
||||
const hash = doubleKeccak256(encodedVAABody);
|
||||
|
||||
const pks = loadGuardianKeys();
|
||||
const signers = loadGuardianKeys();
|
||||
let signatures = "";
|
||||
|
||||
for (let pk of pks) {
|
||||
for (const i in signers) {
|
||||
// sign the hash
|
||||
const ec = new elliptic.ec("secp256k1");
|
||||
const key = ec.keyFromPrivate(pk);
|
||||
const key = ec.keyFromPrivate(signers[i]);
|
||||
const signature = key.sign(hash.substring(2), { canonical: true });
|
||||
|
||||
// pack the signatures
|
||||
const packSig = [
|
||||
ethers.utils.solidityPack(["uint8"], [0]).substring(2),
|
||||
ethers.utils.solidityPack(["uint8"], [i]).substring(2),
|
||||
zeroPadBytes(signature.r.toString(16), 32),
|
||||
zeroPadBytes(signature.s.toString(16), 32),
|
||||
ethers.utils
|
||||
|
@ -131,7 +134,7 @@ export function encodeAndSignGovernancePayload(payload: string): string {
|
|||
ethers.utils
|
||||
.solidityPack(["uint32"], [loadGuardianSetIndex()])
|
||||
.substring(2), // guardianSetIndex
|
||||
ethers.utils.solidityPack(["uint8"], [pks.length]).substring(2), // number of signers
|
||||
ethers.utils.solidityPack(["uint8"], [signers.length]).substring(2), // number of signers
|
||||
signatures,
|
||||
encodedVAABody.substring(2),
|
||||
].join("");
|
||||
|
|
|
@ -8,9 +8,11 @@ import {
|
|||
getMockIntegrationAddress,
|
||||
getProvider,
|
||||
getRelayProvider,
|
||||
getSigner,
|
||||
} from "../helpers/env";
|
||||
import * as grpcWebNodeHttpTransport from "@improbable-eng/grpc-web-node-http-transport";
|
||||
import { ethers } from "ethers";
|
||||
import { RelayProvider__factory } from "../../../ethers-contracts";
|
||||
|
||||
export async function sendMessage(
|
||||
sourceChain: ChainInfo,
|
||||
|
@ -22,7 +24,7 @@ export async function sendMessage(
|
|||
`Sending message from chain ${sourceChain.chainId} to ${targetChain.chainId}...`
|
||||
);
|
||||
|
||||
const sourceRelayer = getCoreRelayer(sourceChain);
|
||||
const sourceRelayer = await getCoreRelayer(sourceChain);
|
||||
const sourceProvider = await sourceRelayer.getDefaultRelayProvider();
|
||||
|
||||
const relayQuote = await (
|
||||
|
|
|
@ -17,7 +17,7 @@ async function run(
|
|||
sourceTxHash: string,
|
||||
deliveryVAASequence: number,
|
||||
) {
|
||||
const coreRelayer = getCoreRelayer(sourceChain)
|
||||
const coreRelayer = await getCoreRelayer(sourceChain)
|
||||
const relayProvider = await coreRelayer.getDefaultRelayProvider()
|
||||
|
||||
const relayQuote = await (
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -42,7 +42,7 @@ async function run() {
|
|||
async function configureChainsRelayProvider(chain: ChainInfo) {
|
||||
console.log("about to perform RelayProvider configuration for chain " + chain.chainId);
|
||||
const relayProvider = getRelayProvider(chain);
|
||||
const coreRelayer = getCoreRelayerAddress(chain);
|
||||
const coreRelayer = await getCoreRelayerAddress(chain);
|
||||
|
||||
const thisChainsConfigInfo = config.addresses.find(
|
||||
(x: any) => x.chainId == chain.chainId
|
||||
|
|
|
@ -1,8 +1,11 @@
|
|||
npx ts-node ./ts-scripts/relayer/config/checkNetworks.ts --last-run=true \
|
||||
&& npx ts-node ./ts-scripts/relayer/relayProvider/deployRelayProvider.ts \
|
||||
npx ts-node ./ts-scripts/relayer/config/checkNetworks.ts --set-last-run \
|
||||
&& npx ts-node ./ts-scripts/relayer/create2Factory/deployCreate2Factory.ts \
|
||||
&& npx ts-node ./ts-scripts/relayer/coreRelayer/deployCoreRelayer.ts \
|
||||
&& npx ts-node ./ts-scripts/relayer/coreRelayer/registerChainsCoreRelayerSelfSign.ts \
|
||||
&& npx ts-node ./ts-scripts/relayer/relayProvider/deployRelayProvider.ts \
|
||||
&& npx ts-node ./ts-scripts/relayer/relayProvider/configureRelayProvider.ts \
|
||||
&& npx ts-node ./ts-scripts/relayer/coreRelayer/registerChainsCoreRelayerSelfSign.ts \
|
||||
&& npx ts-node ./ts-scripts/relayer/mockIntegration/deployMockIntegration.ts \
|
||||
&& npx ts-node ./ts-scripts/relayer/mockIntegration/messageTest.ts \
|
||||
&& npx ts-node ./ts-scripts/relayer/config/syncContractsJson.ts
|
||||
&& npx ts-node ./ts-scripts/relayer/config/syncContractsJson.ts \
|
||||
&& npx ts-node ./ts-scripts/relayer/mockIntegration/messageTest.ts
|
||||
|
||||
# put this as 2nd script if not deployed aleady
|
|
@ -1,6 +1,7 @@
|
|||
echo "deploying generic relayer contracts" \
|
||||
npx ts-node ./ts-scripts/relayer/relayProvider/deployRelayProvider.ts \
|
||||
npx ts-node ./ts-scripts/relayer/create2Factory/deployCreate2Factory.ts \
|
||||
&& npx ts-node ./ts-scripts/relayer/relayProvider/deployRelayProvider.ts \
|
||||
&& npx ts-node ./ts-scripts/relayer/coreRelayer/deployCoreRelayer.ts \
|
||||
&& npx ts-node ./ts-scripts/relayer/mockIntegration/deployMockIntegration.ts \
|
||||
&& npx ts-node ./ts-scripts/relayer/coreRelayer/registerChainsCoreRelayerSelfSign.ts \
|
||||
&& npx ts-node ./ts-scripts/relayer/relayProvider/configureRelayProvider.ts \
|
||||
&& npx ts-node ./ts-scripts/relayer/relayProvider/configureRelayProvider.ts \
|
||||
&& npx ts-node ./ts-scripts/relayer/mockIntegration/deployMockIntegration.ts \
|
|
@ -0,0 +1,5 @@
|
|||
@openzeppelin/=ethereum/node_modules/@openzeppelin/
|
||||
@solidity-parser/=ethereum/node_modules/@solidity-parser/
|
||||
ds-test/=ethereum/lib/forge-std/lib/ds-test/src/
|
||||
forge-std/=ethereum/lib/forge-std/src/
|
||||
truffle/=ethereum/node_modules/truffle/
|
Loading…
Reference in New Issue