diff --git a/helix-contract/address/ln-dev.json b/helix-contract/address/ln-dev.json index e76e07d2..b492acab 100644 --- a/helix-contract/address/ln-dev.json +++ b/helix-contract/address/ln-dev.json @@ -1,73 +1,76 @@ { - "messagers": { - "zksync-goerli": { - "layerzeroMessager": "0x7e303b0A3F08F9fa5F5629Abb998B8Deba89049B" - }, - "goerli": { - "Eth2ArbSendService": "0xa4eE139bE76d277D997aCf9D58053D8DaF7E050a", - "Eth2LineaSendService": "0x9878e74634544d92a043f1826a94465035FA51f4", - "layerzeroMessager": "0xca4490875739BEb1c4ec9ee5d6814774114e1973", - "axelarMessager": "0x037c7b64c80251Cf5C64Ed8f731c799Dc1856701", - "debugMessager": "0x2e8D237226041FAFe3F66b6cfc54b064923D454E" - }, + "chains": { "sepolia": { - "Eth2ScrollSendService": "0x89AF830781A2C1d3580Db930bea11094F55AfEae" - }, - "arbitrum-goerli": { - "Eth2ArbReceiveService": "0x102F8D7Cfe692AA79c17E3958aB00D060Df0B88f", - "layerzeroMessager": "0x953bE65E685099277F1f09Ebe10746810dC0593D", - "axelarMessager": "0xBc30913CC01A2eC70483681841bbb43D2f77caEd", - "debugMessager": "0x7f431D5ba484Eb96811C469BE3DcbB23c67ae4a8" + "name": "sepolia", + "url": "https://rpc2.sepolia.org", + "dao": "0x88a39B052d477CfdE47600a7C9950a441Ce61cb4", + "chainId": 11155111, + "lzChainId": 10161, + "lzEndpoint": "0xae92d5aD7583AD66E49A0c67BAd18F6ba52dDDc1", + "deployer": "0x80D4c766C5142D1313D531Afe7384D0D5E108Db3" }, - "linea-goerli": { - "Eth2LineaReceiveService": "0x8200b3130416F633A696FB9bb0e689a356625075", - "layerzeroMessager": "0xfB09042050868594a54a59EdEAEa96e2765dAd0B", - "axelarMessager": "0x14DB1d462ED061b037C7920857Fc66522ed5bf85", - "debugMessager": "0x25Ce9C92526D002a11aBA105563a713357429A99" - }, - "mantle-goerli": { - "layerzeroMessager": "0xBE4a32f37d11e8227444837DFb3c634d189ccEDc", - "axelarMessager": "0xbb593913a4f3E4eE77861f743c697A4cb95837eF", - "debugMessager": "0x84f7a56483C100ECb12CbB4A31b7873dAE0d8E9B" + "arbitrum-sepolia": { + "name": "arbitrum-sepolia", + "url": "https://sepolia-rollup.arbitrum.io/rpc", + "dao": "0x88a39B052d477CfdE47600a7C9950a441Ce61cb4", + "chainId": 421614, + "lzChainId": 10231, + "lzEndpoint": "0x6098e96a28E02f27B1e6BD381f870F1C8Bd169d3", + "deployer": "0x80D4c766C5142D1313D531Afe7384D0D5E108Db3" }, - "base-goerli": { - "layerzeroMessager": "0x463D1730a8527CA58d48EF70C7460B9920346567" + "zksync": { + "name": "zksync", + "url": "https://sepolia.era.zksync.dev", + "dao": "0x88a39B052d477CfdE47600a7C9950a441Ce61cb4", + "chainId": 300 + } + }, + "messagers": { + "sepolia": { + "chainId": 11155111, + "Eth2ScrollSendService": "0x89AF830781A2C1d3580Db930bea11094F55AfEae", + "layerzeroMessager": "0x33C9916a43507aa0a89a3e889522f840aa1245fE" }, "arbitrum-sepolia": { - "darwiniaMsglineMessager": "0xCddD3e43dA1e9485d4FcD3782DFba04aADCfC9B2" + "chainId": "421614", + "darwiniaMsglineMessager": "0xCddD3e43dA1e9485d4FcD3782DFba04aADCfC9B2", + "layerzeroMessager": "0x87A649246974732f7AbBe01F2DD81E3D829EF0B7" + }, + "zksync": { + "layerzeroMessager": "0xf29244511DA9242D8A452f7EB1264B52A19f5058" } }, "ProxyAdmin": { - "zkSync": "0xd7b3aC0c9E99e9B2EF1C9D2a5ff397867c8c8A3E", + "zksync": "0x57E8fcaAfDE61b179BAe86cDAbfaca99E2A16484", "others": "0xE3979fFa68BBa1F53c6F502c8F5788B370d28730" }, "LnDefaultBridgeLogic": { - "zkSync": "0x6213E3bc566f7d7A73Fd7565c97ac5Ffb8624674", - "others": "0x310bbebF08cbCC1DB41299E602Ef0319b9D1d979" + "zksync": "0xa1C2a266Ba82ce80243B975090016EE68C6d125B", + "others": "0x7CE46A6Bd9FB685b4fd6AE18888D71A9D4750e6E" }, "LnDefaultBridgeProxy": { - "zkSync": "0xe8d55759c32fb608fD092aB2C0ef8A1F52B254d4", - "others": "0x7e101911E5FB461d78FBde3992f76F3Bf8BbA829" + "zksync": "0xBe23e871318E49C747CB909AC65aCCFAEAac3a37", + "others": "0x8429D7Dfd91D6F970ba89fFC005e67D15f1E4739" + }, + "LnOppositeBridgeLogic": "0x08F2a6B3F8f67E6604aBb731FC318cf1f3EAaF53", + "LnOppositeBridgeProxy": "0xbA96d83E2A04c4E50F2D6D7eCA03D70bA2426e5f", + "LnV3BridgeLogic": { + "zksync": "0x67C3C81113Afb9A73d7ce5868046D97D0e44db59", + "others": "0xdf383487CB33a3C78a884494e2456910d79d361c" + }, + "LnV3BridgeProxy": { + "zksync": "0xDc55fF59F82AA50D8A4A61dB8CcaDffD26Fb7dD2", + "others": "0x38627Cb033De66a1E07e73f5D0a7a7adFB6741fa" }, - "LnOppositeBridgeLogic": "0x3CFe649a4d5530AA2c716F0ca279b937687684f9", - "LnOppositeBridgeProxy": "0x4C538EfA6e3f9Dfb939AA4F0B224577DA665923a", "deployer": "0xbe6b2860d3c17a719be0A4911EA0EE689e8357f3", "usdt": { - "goerli": "0xa39cffE89567eBfb5c306a07dfb6e5B3ba41F358", - "mantle-goerli": "0xDb06D904AC5Bdff3b8E6Ac96AFedd3381d94CFDD", - "arbitrum-goerli": "0x543bf1AC41485dc78039b9351563E4Dd13A288cb", - "linea-goerli": "0x8f3663930211f3DE17619FEB2eeB44c9c3F44a06", - "zksync-goerli": "0xb5372ed3bb2CbA63e7908066ac10ee94d30eA839", - "base-goerli": "0x876A4f6eCF13EEb101F9E75FCeF58f19Ff383eEB", + "zksync": "0x3350f1ef046e21E052dCbA60Fc575919CCaFEdeb", "sepolia": "0x876A4f6eCF13EEb101F9E75FCeF58f19Ff383eEB", - "scroll-sepolia": "0x9C80EdD342b5D179c3a87946fC1F0963BfcaAa09" + "scroll-sepolia": "0x9C80EdD342b5D179c3a87946fC1F0963BfcaAa09", + "arbitrum-sepolia": "0x3b8Bb7348D4F581e67E2498574F73e4B9Fc51855" }, "usdc": { - "goerli": "0xe9784E0d9A939dbe966b021DE3cd877284DB1B99", - "mantle-goerli": "0xD610DE267f7590D5bCCE89489ECd2C1A4AfdF76B", - "arbitrum-goerli": "0xBAD026e314a77e727dF643B02f63adA573a3757c", - "linea-goerli": "0xeC89AF5FF618bbF667755BE9d63C69F21F1c00C8", - "zksync-goerli": "0xAe60e005C560E869a2bad271e38e3C9D78381aFF", + "zksync": "0x253adBFE99Fcd096B9b5502753F96CF78D42eaD0", "crab": "0x4bA86B5D0F8D2DCB3FC23757cAA6EA71157F74E9", "arbitrum-sepolia": "0x8A87497488073307E1a17e8A12475a94Afcb413f", "sepolia": "0x0ac58Df0cc3542beC4cDa71B16D06C3cCc39f405", diff --git a/helix-contract/address/ln-product.json b/helix-contract/address/ln-product.json index 9cb2534b..5060a32a 100644 --- a/helix-contract/address/ln-product.json +++ b/helix-contract/address/ln-product.json @@ -1,4 +1,33 @@ { + "chains": { + "arbitrum": { + "name": "arbitrum", + "url": "https://arb1.arbitrum.io/rpc", + "dao": "0x88a39B052d477CfdE47600a7C9950a441Ce61cb4", + "chainId": 42161, + "lzChainId": 110, + "lzEndpoint": "0x3c2269811836af69497E5F486A85D7316753cf62", + "deployer": "0x80D4c766C5142D1313D531Afe7384D0D5E108Db3" + }, + "polygon-pos": { + "name": "polygon-pos", + "url": "https://polygon-rpc.com", + "dao": "0x88a39B052d477CfdE47600a7C9950a441Ce61cb4", + "chainId": 137, + "lzChainId": 109, + "lzEndpoint": "0x3c2269811836af69497E5F486A85D7316753cf62", + "deployer": "0x80D4c766C5142D1313D531Afe7384D0D5E108Db3" + }, + "bsc": { + "name": "bsc", + "url": "https://bsc-dataseed1.defibit.io", + "dao": "0x88a39B052d477CfdE47600a7C9950a441Ce61cb4", + "chainId": 56, + "lzChainId": 102, + "lzEndpoint": "0x3c2269811836af69497E5F486A85D7316753cf62", + "deployer": "0x80D4c766C5142D1313D531Afe7384D0D5E108Db3" + } + }, "messagers": { "ethereum": { "Eth2ArbSendService": "0x78a6831Da2293fbEFd0d8aFB4D1f7CBB751e0119" @@ -64,6 +93,12 @@ "common": "0x94C614DAeFDbf151E1BB53d6A201ae5fF56A9337", "zkSync": "0x767Bc046c989f5e63683fB530f939DD34b91ceAC" }, + "LnV3BridgeLogic": { + "common": "0xdf383487CB33a3C78a884494e2456910d79d361c" + }, + "LnV3BridgeProxy": { + "common": "0xbA5D580B18b6436411562981e02c8A9aA1776D10" + }, "deployer": "0x80D4c766C5142D1313D531Afe7384D0D5E108Db3", "ring": { "arbitrum": "0x9e523234D36973f9e38642886197D023C88e307e", diff --git a/helix-contract/contracts/ln/HelixLnBridgeV3.sol b/helix-contract/contracts/ln/HelixLnBridgeV3.sol new file mode 100644 index 00000000..65b3b8ae --- /dev/null +++ b/helix-contract/contracts/ln/HelixLnBridgeV3.sol @@ -0,0 +1,46 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.17; + +import "@zeppelin-solidity/contracts/proxy/utils/Initializable.sol"; +import "./base/LnBridgeSourceV3.sol"; +import "./base/LnBridgeTargetV3.sol"; +import "../interfaces/IMessager.sol"; + +contract HelixLnBridgeV3 is Initializable, LnBridgeSourceV3, LnBridgeTargetV3 { + struct MessagerService { + address sendService; + address receiveService; + } + + // remoteChainId => messager + mapping(uint256=>MessagerService) public messagers; + + receive() external payable {} + + function initialize(address dao) public initializer { + _initialize(dao); + } + + // the remote endpoint is unique, if we want multi-path to remote endpoint, then the messager should support multi-path + function setSendService(uint256 _remoteChainId, address _remoteBridge, address _service) external onlyDao { + messagers[_remoteChainId].sendService = _service; + ILowLevelMessageSender(_service).registerRemoteReceiver(_remoteChainId, _remoteBridge); + } + + function setReceiveService(uint256 _remoteChainId, address _remoteBridge, address _service) external onlyDao { + messagers[_remoteChainId].receiveService = _service; + ILowLevelMessageReceiver(_service).registerRemoteSender(_remoteChainId, _remoteBridge); + } + + function _sendMessageToSource(uint256 _remoteChainId, bytes memory _payload, uint256 feePrepaid, bytes memory _extParams) whenNotPaused internal override { + address sendService = messagers[_remoteChainId].sendService; + require(sendService != address(0), "invalid messager"); + ILowLevelMessageSender(sendService).sendMessage{value: feePrepaid}(_remoteChainId, _payload, _extParams); + } + + function _verifyRemote(uint256 _remoteChainId) whenNotPaused internal view override { + address receiveService = messagers[_remoteChainId].receiveService; + require(receiveService == msg.sender, "invalid messager"); + } +} + diff --git a/helix-contract/contracts/ln/base/LnAccessController.sol b/helix-contract/contracts/ln/base/LnAccessController.sol index 8f2cb263..9bc8a050 100644 --- a/helix-contract/contracts/ln/base/LnAccessController.sol +++ b/helix-contract/contracts/ln/base/LnAccessController.sol @@ -7,6 +7,7 @@ pragma solidity ^0.8.17; contract LnAccessController { address public dao; address public operator; + address public pendingDao; mapping(address=>bool) public callerWhiteList; @@ -39,7 +40,14 @@ contract LnAccessController { } function transferOwnership(address _dao) onlyDao external { - dao = _dao; + pendingDao = _dao; + } + + function acceptOwnership() external { + address newDao = msg.sender; + require(pendingDao == newDao, "!pendingDao"); + delete pendingDao; + dao = newDao; } } diff --git a/helix-contract/contracts/ln/base/LnBridgeHelper.sol b/helix-contract/contracts/ln/base/LnBridgeHelper.sol index 76fad68b..535ac390 100644 --- a/helix-contract/contracts/ln/base/LnBridgeHelper.sol +++ b/helix-contract/contracts/ln/base/LnBridgeHelper.sol @@ -6,7 +6,7 @@ import "@zeppelin-solidity/contracts/token/ERC20/IERC20.sol"; library LnBridgeHelper { // the time(seconds) for liquidity provider to delivery message // if timeout, slasher can work. - uint256 constant public SLASH_EXPIRE_TIME = 30 * 60; + uint256 constant public SLASH_EXPIRE_TIME = 60 * 60; bytes32 constant public INIT_SLASH_TRANSFER_ID = bytes32(uint256(1)); // liquidity fee base rate // liquidityFee = liquidityFeeRate / LIQUIDITY_FEE_RATE_BASE * sendAmount diff --git a/helix-contract/contracts/ln/base/LnBridgeSourceV3.sol b/helix-contract/contracts/ln/base/LnBridgeSourceV3.sol new file mode 100644 index 00000000..0aaa9e4f --- /dev/null +++ b/helix-contract/contracts/ln/base/LnBridgeSourceV3.sol @@ -0,0 +1,490 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.17; + +import "@zeppelin-solidity/contracts/security/Pausable.sol"; +import "../../utils/AccessController.sol"; +import "../../utils/TokenTransferHelper.sol"; + +/// @title LnBridgeSourceV3 +/// @notice LnBridgeSourceV3 is a contract to help user lock token and then trigger remote chain relay +/// @dev See https://github.com/helix-bridge/contracts/tree/master/helix-contract +contract LnBridgeSourceV3 is Pausable, AccessController { + uint256 constant public LOCK_TIME_DISTANCE = 15 minutes; + uint256 constant public MAX_TRANSFER_AMOUNT = type(uint112).max; + // liquidity fee base rate + // liquidityFee = liquidityFeeRate / LIQUIDITY_FEE_RATE_BASE * sendAmount + // totalProviderFee = baseFee + liquidityFee + uint256 constant public LIQUIDITY_FEE_RATE_BASE = 100000; + uint8 constant public LOCK_STATUS_LOCKED = 1; + uint8 constant public LOCK_STATUS_WITHDRAWN = 2; + uint8 constant public LOCK_STATUS_SLASHED = 3; + // the configure information can be updated + struct TokenConfigure { + // pay to system for each tx + uint112 protocolFee; + // Used to penalise relayer for each slashed transaction + uint112 penalty; + uint8 sourceDecimals; + uint8 targetDecimals; + } + // registered token info + struct TokenInfo { + TokenConfigure config; + // zero index is invalid + // use this index to indict the token info to save gas + uint32 index; + address sourceToken; + address targetToken; + // accumulated system revenues + uint256 protocolFeeIncome; + } + struct TransferParams { + uint256 remoteChainId; + address provider; + address sourceToken; + address targetToken; + uint112 totalFee; + uint112 amount; + address receiver; + // use this timestamp as the lock time + // can't be too far from the block that the transaction confirmed + // This timestamp can also be adjusted to produce different transferId + uint256 timestamp; + } + // hash(remoteChainId, sourceToken, targetToken) => TokenInfo + mapping(bytes32=>TokenInfo) public tokenInfos; + // the token index is used to be stored in lockInfo to save gas + mapping(uint32=>bytes32) public tokenIndexer; + // amountWithFeeAndPenalty = transferAmount + providerFee + penalty < type(uint112).max + // the status only has the following 4 values + // status == 0: lockInfo not exist -> can update to status 1 + // status == 1: lockInfo confirmed on source chain(has not been withdrawn or slashed) -> can update to status 2 or 3 + // status == 2: lockInfo has been withdrawn -> can't update anymore + // status == 3: lockInfo has been slashed -> can't update anymore + // we don't clean lockInfo after withdraw or slash to avoid the hash collision(generate the same transferId) + // when we wan't to get tokenInfo from lockInfo, we should get the key(bytes32) from tokenIndex, then get tokenInfo from key + struct LockInfo { + uint112 amountWithFeeAndPenalty; + uint32 tokenIndex; + uint8 status; + } + // transferId => LockInfo + mapping(bytes32 => LockInfo) public lockInfos; + + struct SourceProviderInfo { + uint112 baseFee; + uint16 liquidityFeeRate; + uint112 transferLimit; + bool pause; + } + + // hash(remoteChainId, provider, sourceToken, targetToken) => SourceProviderInfo + mapping(bytes32=>SourceProviderInfo) public srcProviders; + // for a special source token, all the path start from this chain use the same panaltyReserve + // 1. when a lock tx sent, the penaltyReserves decrease and the penalty move to lockInfo.amountWithFeeAndPenalty + // 2. when withdraw liquidity, it tries to move this penalty lockInfo.amountWithFeeAndPenalty back to penaltyReserves + // 3. when the penaltyReserves is not enough to support one lock tx, the provider is paused to work + // hash(sourceToken, provider) => penalty reserve + mapping(bytes32=>uint256) public penaltyReserves; + + event TokenRegistered( + bytes32 key, + uint256 remoteChainId, + address sourceToken, + address targetToken, + uint112 protocolFee, + uint112 penalty, + uint32 index + ); + event TokenInfoUpdated(bytes32 tokenInfoKey, uint112 protocolFee, uint112 penalty, uint112 sourceDecimals, uint112 targetDecimals); + event FeeIncomeClaimed(bytes32 tokenInfoKey, uint256 amount, address receiver); + event TokenLocked( + TransferParams params, + bytes32 transferId, + uint112 targetAmount, + uint112 fee + ); + event LnProviderUpdated( + uint256 remoteChainId, + address provider, + address sourceToken, + address targetToken, + uint112 baseFee, + uint16 liquidityfeeRate, + uint112 transferLimit + ); + event PenaltyReserveUpdated(address provider, address sourceToken, uint256 updatedPanaltyReserve); + event LiquidityWithdrawn(bytes32[] transferIds, address provider, uint256 amount); + event TransferSlashed(bytes32 transferId, address provider, address slasher, uint112 slashAmount); + event LnProviderPaused(address provider, uint256 remoteChainId, address sourceToken, address targetToken, bool paused); + + modifier allowRemoteCall(uint256 _remoteChainId) { + _verifyRemote(_remoteChainId); + _; + } + + function _verifyRemote(uint256 _remoteChainId) internal virtual {} + + function unpause() external onlyOperator { + _unpause(); + } + + function pause() external onlyOperator { + _pause(); + } + + // register a new token pair by Helix Dao + // if the token pair has been registered, it will revert + // select an unused _index to save the tokenInfo, it's not required that the _index is continous or increased + function registerTokenInfo( + uint256 _remoteChainId, + address _sourceToken, + address _targetToken, + uint112 _protocolFee, + uint112 _penalty, + uint8 _sourceDecimals, + uint8 _targetDecimals, + uint32 _index + ) onlyDao external { + require(_index > 0, "invalid index"); + bytes32 key = getTokenKey(_remoteChainId, _sourceToken, _targetToken); + TokenInfo memory oldInfo = tokenInfos[key]; + require(oldInfo.index == 0, "token info exist"); + require(tokenIndexer[_index] == bytes32(0), "the index exist"); + TokenConfigure memory tokenConfig = TokenConfigure( + _protocolFee, + _penalty, + _sourceDecimals, + _targetDecimals + ); + tokenInfos[key] = TokenInfo( + tokenConfig, + _index, + _sourceToken, + _targetToken, + 0 + ); + tokenIndexer[_index] = key; + emit TokenRegistered(key, _remoteChainId, _sourceToken, _targetToken, _protocolFee, _penalty, _index); + } + + // update a registered token pair + // the key or index cannot be updated + // Attention! source decimals and target decimals + function updateTokenInfo( + uint256 _remoteChainId, + address _sourceToken, + address _targetToken, + uint112 _protocolFee, + uint112 _penalty, + uint8 _sourceDecimals, + uint8 _targetDecimals + ) onlyDao external { + bytes32 key = getTokenKey(_remoteChainId, _sourceToken, _targetToken); + TokenInfo memory tokenInfo = tokenInfos[key]; + require(tokenInfo.index > 0, "token not registered"); + tokenInfos[key].config = TokenConfigure( + _protocolFee, + _penalty, + _sourceDecimals, + _targetDecimals + ); + emit TokenInfoUpdated(key, _protocolFee, _penalty, _sourceDecimals, _targetDecimals); + } + + // delete a token pair by Helix Dao + // This interface should be called with exceptional caution, only when correcting registration errors, to conserve index resources. + // Attention! DON'T delete a used token pair + function deleteTokenInfo(bytes32 key) onlyDao external { + TokenInfo memory tokenInfo = tokenInfos[key]; + require(tokenInfo.index > 0, "token not registered"); + require(tokenIndexer[tokenInfo.index] == key, "indexer exception"); + delete tokenInfos[key]; + delete tokenIndexer[tokenInfo.index]; + } + + // claim the protocol fee + function claimProtocolFeeIncome( + bytes32 _tokenInfoKey, + uint256 _amount, + address _receiver + ) onlyDao external { + TokenInfo memory tokenInfo = tokenInfos[_tokenInfoKey]; + require(tokenInfo.protocolFeeIncome > _amount, "not enough income"); + tokenInfos[_tokenInfoKey].protocolFeeIncome = tokenInfo.protocolFeeIncome - _amount; + + if (tokenInfo.sourceToken == address(0)) { + TokenTransferHelper.safeTransferNative(_receiver, _amount); + } else { + TokenTransferHelper.safeTransfer(tokenInfo.sourceToken, _receiver, _amount); + } + emit FeeIncomeClaimed(_tokenInfoKey, _amount, _receiver); + } + + // called by lnProvider + // this func can be called to register a new or update an exist LnProvider info + function registerLnProvider( + uint256 _remoteChainId, + address _sourceToken, + address _targetToken, + uint112 _baseFee, + uint16 _liquidityFeeRate, + uint112 _transferLimit + ) external { + bytes32 key = getTokenKey(_remoteChainId, _sourceToken, _targetToken); + TokenInfo memory tokenInfo = tokenInfos[key]; + require(tokenInfo.index > 0, "token not registered"); + bytes32 providerKey = getProviderKey(_remoteChainId, msg.sender, _sourceToken, _targetToken); + + require(_liquidityFeeRate < LIQUIDITY_FEE_RATE_BASE, "liquidity fee too large"); + + // we only update the field fee of the provider info + // if the provider has not been registered, then this line will register, otherwise update fee + SourceProviderInfo storage providerInfo = srcProviders[providerKey]; + providerInfo.baseFee = _baseFee; + providerInfo.liquidityFeeRate = _liquidityFeeRate; + providerInfo.transferLimit = _transferLimit; + + emit LnProviderUpdated(_remoteChainId, msg.sender, _sourceToken, _targetToken, _baseFee, _liquidityFeeRate, _transferLimit); + } + + function depositPenaltyReserve( + address _sourceToken, + uint256 _amount + ) external payable { + bytes32 key = getProviderStateKey(_sourceToken, msg.sender); + uint256 updatedPanaltyReserve = penaltyReserves[key] + _amount; + penaltyReserves[key] = updatedPanaltyReserve; + + if (_sourceToken == address(0)) { + require(msg.value == _amount, "invalid penaltyReserve value"); + } else { + require(msg.value == 0, "value not need"); + TokenTransferHelper.safeTransferFrom( + _sourceToken, + msg.sender, + address(this), + _amount + ); + } + emit PenaltyReserveUpdated(msg.sender, _sourceToken, updatedPanaltyReserve); + } + + function withdrawPenaltyReserve( + address _sourceToken, + uint256 _amount + ) external { + bytes32 key = getProviderStateKey(_sourceToken, msg.sender); + uint256 updatedPanaltyReserve = penaltyReserves[key] - _amount; + penaltyReserves[key] = updatedPanaltyReserve; + + if (_sourceToken == address(0)) { + TokenTransferHelper.safeTransferNative(msg.sender, _amount); + } else { + TokenTransferHelper.safeTransfer(_sourceToken, msg.sender, _amount); + } + emit PenaltyReserveUpdated(msg.sender, _sourceToken, updatedPanaltyReserve); + } + + function providerPause( + uint256 _remoteChainId, + address _sourceToken, + address _targetToken + ) external { + bytes32 providerKey = getProviderKey(_remoteChainId, msg.sender, _sourceToken, _targetToken); + srcProviders[providerKey].pause = true; + emit LnProviderPaused(msg.sender, _remoteChainId, _sourceToken, _targetToken, true); + } + + function providerUnpause( + uint256 _remoteChainId, + address _sourceToken, + address _targetToken + ) external { + bytes32 providerKey = getProviderKey(_remoteChainId, msg.sender, _sourceToken, _targetToken); + srcProviders[providerKey].pause = false; + emit LnProviderPaused(msg.sender, _remoteChainId, _sourceToken, _targetToken, false); + } + + function totalFee( + uint256 _remoteChainId, + address _provider, + address _sourceToken, + address _targetToken, + uint112 _amount + ) external view returns(uint112) { + TokenInfo memory tokenInfo = getTokenInfo(_remoteChainId, _sourceToken, _targetToken); + SourceProviderInfo memory providerInfo = getProviderInfo(_remoteChainId, _provider, _sourceToken, _targetToken); + uint256 providerFee = uint256(providerInfo.baseFee) + uint256(providerInfo.liquidityFeeRate) * uint256(_amount) / LIQUIDITY_FEE_RATE_BASE; + require(providerFee < type(uint112).max, "overflow fee"); + return uint112(providerFee) + tokenInfo.config.protocolFee; + } + + function lockAndRemoteRelease(TransferParams calldata _params) whenNotPaused external payable { + // timestamp must be close to the block time + require( + _params.timestamp >= block.timestamp - LOCK_TIME_DISTANCE && _params.timestamp <= block.timestamp + LOCK_TIME_DISTANCE, + "timestamp is too far from block time" + ); + + // check transfer info + bytes32 tokenKey = getTokenKey(_params.remoteChainId, _params.sourceToken, _params.targetToken); + TokenInfo memory tokenInfo = tokenInfos[tokenKey]; + SourceProviderInfo memory providerInfo = getProviderInfo(_params.remoteChainId, _params.provider, _params.sourceToken, _params.targetToken); + require(providerInfo.transferLimit >= _params.amount && _params.amount > 0, "invalid transfer amount"); + uint256 providerFee = uint256(providerInfo.baseFee) + uint256(providerInfo.liquidityFeeRate) * uint256(_params.amount) / LIQUIDITY_FEE_RATE_BASE; + require(providerFee < type(uint112).max, "overflow fee"); + uint112 amountWithFeeAndPenalty = _params.amount + uint112(providerFee) + tokenInfo.config.penalty; + require(_params.totalFee >= providerFee + tokenInfo.config.protocolFee, "fee not matched"); + require(!providerInfo.pause, "provider paused"); + + // update provider state + bytes32 stateKey = getProviderStateKey(_params.sourceToken, _params.provider); + uint256 penaltyReserved = penaltyReserves[stateKey]; + require(penaltyReserved >= tokenInfo.config.penalty, "penalty reserve not enough"); + penaltyReserved -= tokenInfo.config.penalty; + penaltyReserves[stateKey] = penaltyReserved; + emit PenaltyReserveUpdated(_params.provider, _params.sourceToken, penaltyReserved); + + // save lock info + uint256 remoteAmount = uint256(_params.amount) * 10**tokenInfo.config.targetDecimals / 10**tokenInfo.config.sourceDecimals; + require(remoteAmount < MAX_TRANSFER_AMOUNT && remoteAmount > 0, "overflow amount"); + bytes32 transferId = getTransferId(_params, uint112(remoteAmount)); + require(lockInfos[transferId].status == 0, "transferId exist"); + lockInfos[transferId] = LockInfo(amountWithFeeAndPenalty, tokenInfo.index, LOCK_STATUS_LOCKED); + emit TokenLocked(_params, transferId, uint112(remoteAmount), uint112(providerFee)); + + // update protocol fee income + // leave the protocol fee into contract, and admin can withdraw this fee anytime + tokenInfos[tokenKey].protocolFeeIncome = tokenInfo.protocolFeeIncome + tokenInfo.config.protocolFee; + + // transfer token + uint112 totalPayAmount = _params.amount + uint112(providerFee) + tokenInfo.config.protocolFee; + if (_params.sourceToken == address(0)) { + require(msg.value >= totalPayAmount, "value not enough"); + if (msg.value > totalPayAmount) { + // refund + TokenTransferHelper.safeTransferNative(msg.sender, msg.value - totalPayAmount); + } + } else { + require(msg.value == 0, "no value need"); + TokenTransferHelper.safeTransferFrom(_params.sourceToken, msg.sender, address(this), totalPayAmount); + } + } + + // we require the same token to withdrawn + function withdrawLiquidity( + bytes32[] calldata _transferIds, + uint256 _remoteChainId, + // provider is verified on the target chain + address _provider + ) external allowRemoteCall(_remoteChainId) { + require(_transferIds.length > 0, "invalid transferIds size"); + uint32 tokenIndex = lockInfos[_transferIds[0]].tokenIndex; + uint256 totalAmount = 0; + for (uint i = 0; i < _transferIds.length; i++) { + bytes32 transferId = _transferIds[i]; + LockInfo memory lockInfo = lockInfos[transferId]; + require(lockInfo.amountWithFeeAndPenalty > 0, "invalid transferId"); + require(lockInfo.tokenIndex == tokenIndex, "token index not matched"); + require(lockInfo.status == LOCK_STATUS_LOCKED, "token has been withdrawn"); + + totalAmount += lockInfo.amountWithFeeAndPenalty; + lockInfos[transferId].status = LOCK_STATUS_WITHDRAWN; + } + emit LiquidityWithdrawn(_transferIds, _provider, totalAmount); + bytes32 key = tokenIndexer[tokenIndex]; + TokenInfo memory tokenInfo = tokenInfos[key]; + require(tokenInfo.index == tokenIndex, "invalid token info"); + + uint256 withdrawAmount = totalAmount; + // if penalty updated, the relayer may not redeposit + if (tokenInfo.config.penalty * _transferIds.length < withdrawAmount) { + // restore the penalty reserve + uint112 redepositPenalty = tokenInfo.config.penalty * uint112(_transferIds.length); + bytes32 stateKey = getProviderStateKey(tokenInfo.sourceToken, _provider); + uint256 penaltyReserved = penaltyReserves[stateKey] + uint256(redepositPenalty); + penaltyReserves[stateKey] = penaltyReserved; + withdrawAmount -= redepositPenalty; + emit PenaltyReserveUpdated(_provider, tokenInfo.sourceToken, penaltyReserved); + } + + if (tokenInfo.sourceToken == address(0)) { + TokenTransferHelper.safeTransferNative(_provider, withdrawAmount); + } else { + TokenTransferHelper.safeTransfer(tokenInfo.sourceToken, _provider, withdrawAmount); + } + } + + function slash( + uint256 _remoteChainId, + bytes32 _transferId, + // slasher, amount and lnProvider is verified on the target chain + address _lnProvider, + address _slasher + ) external allowRemoteCall(_remoteChainId) { + LockInfo memory lockInfo = lockInfos[_transferId]; + require(lockInfo.status == LOCK_STATUS_LOCKED, "invalid lock status"); + bytes32 tokenKey = tokenIndexer[lockInfo.tokenIndex]; + TokenInfo memory tokenInfo = tokenInfos[tokenKey]; + lockInfos[_transferId].status = LOCK_STATUS_SLASHED; + + // pause this provider if slashed + bytes32 providerKey = getProviderKey(_remoteChainId, _lnProvider, tokenInfo.sourceToken, tokenInfo.targetToken); + srcProviders[providerKey].pause = true; + emit LnProviderPaused(_lnProvider, _remoteChainId, tokenInfo.sourceToken, tokenInfo.targetToken, true); + + // transfer token to slasher + if (tokenInfo.sourceToken == address(0)) { + TokenTransferHelper.safeTransferNative(_slasher, lockInfo.amountWithFeeAndPenalty); + } else { + TokenTransferHelper.safeTransfer(tokenInfo.sourceToken, _slasher, lockInfo.amountWithFeeAndPenalty); + } + emit TransferSlashed(_transferId, _lnProvider, _slasher, lockInfo.amountWithFeeAndPenalty); + } + + function getProviderKey(uint256 _remoteChainId, address _provider, address _sourceToken, address _targetToken) pure public returns(bytes32) { + return keccak256(abi.encodePacked(_remoteChainId, _provider, _sourceToken, _targetToken)); + } + + function getTokenKey(uint256 _remoteChainId, address _sourceToken, address _targetToken) pure public returns(bytes32) { + return keccak256(abi.encodePacked(_remoteChainId, _sourceToken, _targetToken)); + } + + function getProviderStateKey(address _sourceToken, address provider) pure public returns(bytes32) { + return keccak256(abi.encodePacked(_sourceToken, provider)); + } + + function getTransferId( + TransferParams memory _params, + uint112 _remoteAmount + ) public view returns(bytes32) { + return keccak256(abi.encodePacked( + block.chainid, + _params.remoteChainId, + _params.provider, + _params.sourceToken, + _params.targetToken, + _params.receiver, + _params.amount, + _remoteAmount, + _params.timestamp + )); + } + + function getTokenInfo(uint256 _remoteChainId, address _sourceToken, address _targetToken) view internal returns(TokenInfo memory) { + bytes32 key = keccak256(abi.encodePacked(_remoteChainId, _sourceToken, _targetToken)); + return tokenInfos[key]; + } + + function getProviderInfo( + uint256 _remoteChainId, + address _provider, + address _sourceToken, + address _targetToken + ) view internal returns(SourceProviderInfo memory) { + bytes32 key = keccak256(abi.encodePacked(_remoteChainId, _provider, _sourceToken, _targetToken)); + return srcProviders[key]; + } +} + diff --git a/helix-contract/contracts/ln/base/LnBridgeTargetV3.sol b/helix-contract/contracts/ln/base/LnBridgeTargetV3.sol new file mode 100644 index 00000000..a5142738 --- /dev/null +++ b/helix-contract/contracts/ln/base/LnBridgeTargetV3.sol @@ -0,0 +1,187 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.17; + +import "../interface/ILnBridgeSourceV3.sol"; +import "../../utils/TokenTransferHelper.sol"; + +contract LnBridgeTargetV3 { + uint256 constant public SLASH_EXPIRE_TIME = 60 * 60; + // timestamp: the time when transfer filled, this is also the flag that the transfer is filled(relayed or slashed) + // provider: the transfer lnProvider + struct FillTransfer { + uint64 timestamp; + address provider; + } + + // lockTimestamp: the time when the transfer start from source chain + // the lockTimestamp is verified on source chain + // 1. lockTimestamp verified successed: slasher get the transfer amount, fee and penalty on source chain + // 2. lockTimestamp verified failed: slasher get the transfer amount, but the fee and penalty back to the provider + // sourceAmount: the send amount on source chain + struct SlashInfo { + uint256 remoteChainId; + address slasher; + } + + struct RelayParams { + uint256 remoteChainId; + address provider; + address sourceToken; + address targetToken; + uint112 sourceAmount; + uint112 targetAmount; + address receiver; + uint256 timestamp; + } + + // transferId => FillTransfer + mapping(bytes32 => FillTransfer) public fillTransfers; + // transferId => SlashInfo + mapping(bytes32 => SlashInfo) public slashInfos; + + event TransferFilled(bytes32 transferId, address provider); + event SlashRequest(bytes32 transferId, uint256 remoteChainId, address provider, address sourceToken, address targetToken, address slasher); + event LiquidityWithdrawRequested(bytes32[] transferIds, uint256 remoteChainId); + + function _sendMessageToSource(uint256 _remoteChainId, bytes memory _payload, uint256 feePrepaid, bytes memory _extParams) internal virtual {} + + // relay a tx, usually called by lnProvider + // 1. update the fillTransfers storage to save the relay proof + // 2. transfer token from lnProvider to the receiver + function relay( + RelayParams calldata _params, + bytes32 _expectedTransferId, + bool _relayBySelf + ) external payable { + // _relayBySelf = true to protect that the msg.sender don't relay for others + // _relayBySelf = false to allow that lnProvider can use different account between source chain and target chain + require(!_relayBySelf || _params.provider == msg.sender, "invalid provider"); + bytes32 transferId = keccak256(abi.encodePacked( + _params.remoteChainId, + block.chainid, + _params.provider, + _params.sourceToken, + _params.targetToken, + _params.receiver, + _params.sourceAmount, + _params.targetAmount, + _params.timestamp + )); + require(_expectedTransferId == transferId, "check expected transferId failed"); + FillTransfer memory fillTransfer = fillTransfers[transferId]; + // Make sure this transfer was never filled before + require(fillTransfer.timestamp == 0, "transfer has been filled"); + fillTransfers[transferId] = FillTransfer(uint64(block.timestamp), _params.provider); + + if (_params.targetToken == address(0)) { + require(msg.value == _params.targetAmount, "invalid amount"); + TokenTransferHelper.safeTransferNative(_params.receiver, _params.targetAmount); + } else { + require(msg.value == 0, "value not need"); + TokenTransferHelper.safeTransferFrom(_params.targetToken, msg.sender, _params.receiver, uint256(_params.targetAmount)); + } + emit TransferFilled(transferId, _params.provider); + } + + // slash a tx when timeout + // 1. update fillTransfers and slashInfos storage to save slash proof + // 2. transfer tokens from slasher to receiver for this tx + // 3. send a cross-chain message to source chain to withdraw the amount, fee and penalty from lnProvider + function requestSlashAndRemoteRelease( + RelayParams calldata _params, + bytes32 _expectedTransferId, + uint256 _feePrepaid, + bytes memory _extParams + ) external payable { + bytes32 transferId = keccak256(abi.encodePacked( + _params.remoteChainId, + block.chainid, + _params.provider, + _params.sourceToken, + _params.targetToken, + _params.receiver, + _params.sourceAmount, + _params.targetAmount, + _params.timestamp + )); + require(_expectedTransferId == transferId, "check expected transferId failed"); + + FillTransfer memory fillTransfer = fillTransfers[transferId]; + require(fillTransfer.timestamp == 0, "transfer has been filled"); + + // suppose source chain and target chain has the same block timestamp + // event the timestamp is not sync exactly, this TIMEOUT is also verified on source chain + require(_params.timestamp < block.timestamp - SLASH_EXPIRE_TIME, "time not expired"); + fillTransfers[transferId] = FillTransfer(uint64(block.timestamp), _params.provider); + slashInfos[transferId] = SlashInfo(_params.remoteChainId, msg.sender); + + if (_params.targetToken == address(0)) { + require(msg.value == _params.targetAmount + _feePrepaid, "invalid value"); + TokenTransferHelper.safeTransferNative(_params.receiver, _params.targetAmount); + } else { + require(msg.value == _feePrepaid, "value too large"); + TokenTransferHelper.safeTransferFrom(_params.targetToken, msg.sender, _params.receiver, uint256(_params.targetAmount)); + } + bytes memory message = encodeSlashRequest(transferId, _params.provider, msg.sender); + _sendMessageToSource(_params.remoteChainId, message, _feePrepaid, _extParams); + emit SlashRequest(transferId, _params.remoteChainId, _params.provider, _params.sourceToken, _params.targetToken, msg.sender); + } + + // it's allowed to retry a slash tx because the cross-chain message may fail on source chain + // But it's required that the params must not be modified, it read from the storage saved + function retrySlash(bytes32 transferId, bytes memory _extParams) external payable { + FillTransfer memory fillTransfer = fillTransfers[transferId]; + require(fillTransfer.timestamp > 0, "transfer not filled"); + SlashInfo memory slashInfo = slashInfos[transferId]; + require(slashInfo.slasher == msg.sender, "invalid slasher"); + // send message + bytes memory message = encodeSlashRequest(transferId, fillTransfer.provider, slashInfo.slasher); + _sendMessageToSource(slashInfo.remoteChainId, message, msg.value, _extParams); + } + + // can't withdraw for different providers each time + // the size of the _transferIds should not be too large to be processed outof gas on source chain + function requestWithdrawLiquidity( + uint256 _remoteChainId, + bytes32[] calldata _transferIds, + address _provider, + bytes memory _extParams + ) external payable { + for (uint i = 0; i < _transferIds.length; i++) { + bytes32 transferId = _transferIds[i]; + FillTransfer memory fillTransfer = fillTransfers[transferId]; + // make sure that each transfer has the same provider + require(fillTransfer.provider == _provider, "provider invalid"); + } + bytes memory message = encodeWithdrawLiquidityRequest(_transferIds, _provider); + _sendMessageToSource(_remoteChainId, message, msg.value, _extParams); + emit LiquidityWithdrawRequested(_transferIds, _remoteChainId); + } + + function encodeWithdrawLiquidityRequest( + bytes32[] calldata _transferIds, + address _provider + ) public view returns(bytes memory message) { + message = abi.encodeWithSelector( + ILnBridgeSourceV3.withdrawLiquidity.selector, + _transferIds, + block.chainid, + _provider + ); + } + + function encodeSlashRequest( + bytes32 _transferId, + address _provider, + address _slasher + ) public view returns(bytes memory message) { + message = abi.encodeWithSelector( + ILnBridgeSourceV3.slash.selector, + block.chainid, + _transferId, + _provider, + _slasher + ); + } +} + diff --git a/helix-contract/contracts/ln/interface/ILnBridgeSourceV3.sol b/helix-contract/contracts/ln/interface/ILnBridgeSourceV3.sol new file mode 100644 index 00000000..0e2ca4aa --- /dev/null +++ b/helix-contract/contracts/ln/interface/ILnBridgeSourceV3.sol @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.17; + +interface ILnBridgeSourceV3 { + function slash( + uint256 _remoteChainId, + bytes32 _transferId, + address _lnProvider, + address _slasher + ) external; + function withdrawLiquidity( + bytes32[] calldata _transferIds, + uint256 _remoteChainId, + address _provider + ) external; +} diff --git a/helix-contract/contracts/mapping-token/test/MockArbitrumInbox.sol b/helix-contract/contracts/mapping-token/test/MockArbitrumInbox.sol index 2540b93f..bef5d746 100644 --- a/helix-contract/contracts/mapping-token/test/MockArbitrumInbox.sol +++ b/helix-contract/contracts/mapping-token/test/MockArbitrumInbox.sol @@ -19,6 +19,7 @@ contract MockArbitrumInbox { ) external payable returns (uint256) { // we use this gas price to mock failed remote call console.log("mock arbitrum inbox call", to); + require(msg.value >= 0.01 ether, "fee is required"); if (maxFeePerGas > 100) { (bool result, ) = to.call(data); require(result == true, "arbitrum mock call failed"); diff --git a/helix-contract/contracts/messagers/MsglineMessager.sol b/helix-contract/contracts/messagers/MsglineMessager.sol index 08d10ec5..ab56d186 100644 --- a/helix-contract/contracts/messagers/MsglineMessager.sol +++ b/helix-contract/contracts/messagers/MsglineMessager.sol @@ -5,7 +5,7 @@ import "../utils/AccessController.sol"; import "../interfaces/IMessageLine.sol"; contract MsglineMessager is Application, AccessController { - IMessageLine public immutable msgline; + IMessageLine public msgline; struct RemoteMessager { uint256 msglineRemoteChainId; @@ -39,6 +39,10 @@ contract MsglineMessager is Application, AccessController { msgline = IMessageLine(_msgline); } + function setMsgline(address _msgline) onlyDao external { + msgline = IMessageLine(_msgline); + } + function setRemoteMessager(uint256 _appRemoteChainId, uint256 _msglineRemoteChainId, address _remoteMessager) onlyDao external { remoteMessagers[_appRemoteChainId] = RemoteMessager(_msglineRemoteChainId, _remoteMessager); } diff --git a/helix-contract/deploy/create2.js b/helix-contract/deploy/create2.js index 98d8262e..442775d6 100644 --- a/helix-contract/deploy/create2.js +++ b/helix-contract/deploy/create2.js @@ -3,13 +3,14 @@ var Create2 = { getDeployedBytecode: function(factory, constructorTypes, constructorArgs) { const abiCoder = ethers.utils.defaultAbiCoder; const encodedParams = abiCoder.encode(constructorTypes, constructorArgs); + console.log(`constructor bytes: ${encodedParams.slice(2)}`); const bytecode = `${factory.bytecode}${encodedParams.slice(2)}`; return bytecode; }, - deploy: async function(deployAddress, wallet, bytecode, salt) { + deploy: async function(deployAddress, wallet, bytecode, salt, gasLimit) { const hexSalt = ethers.utils.id(salt.toString()); const deployer = await ethers.getContractAt("Create2Deployer", deployAddress, wallet); - const result = await (await deployer.deploy(bytecode, hexSalt)).wait(); + const result = await (await deployer.deploy(bytecode, hexSalt, {gasLimit: gasLimit})).wait(); const targetEvent = result.events.find((e) => e.event == 'Deployed'); const abiCoder = ethers.utils.defaultAbiCoder; const eventParams = abiCoder.decode(["address", "uint256"], targetEvent.data); diff --git a/helix-contract/deploy/deploy_bytescode.js b/helix-contract/deploy/deploy_bytescode.js index 86598ef5..a6819fe0 100644 --- a/helix-contract/deploy/deploy_bytescode.js +++ b/helix-contract/deploy/deploy_bytescode.js @@ -71,6 +71,13 @@ async function getxTokenIssuingProxyBridgeBytecode(networkUrl, version, logicAdd return; } +async function getLnv3ProxyBridgeBytecode(networkUrl, version, logicAddress, proxyAdminAddress) { + const w = wallet(networkUrl); + const lnv3Factory = await ethers.getContractFactory("HelixLnBridgeV3", w); + await getLnProxyBridgeBytecode(w, version, lnv3Factory, logicAddress, proxyAdminAddress, [w.address]); + return; +} + // 2. deploy mapping token factory async function main() { //await getHelixProxyAdminBytecode('https://rpc.ankr.com/eth_goerli', 'v1.0.0'); @@ -78,7 +85,8 @@ async function main() { //await getDefaultBridgeBytecode('https://rpc.ankr.com/eth_goerli', 'v1.0.0'); //await getLnDefaultProxyBridgeBytecode('https://rpc.ankr.com/eth_goerli', 'v1.0.0', '0x8af688056c6614acb5A78c62e1f9f49022C0452f', '0x601dE3B81c7cE04BecE3b29e5cEe4F3251d250dB'); //await getLnOppositeProxyBridgeBytecode('https://rpc.ankr.com/eth_goerli', 'v1.0.0', '0x90873fa1bbd028F22277567530A22E05f7721D37', '0x601dE3B81c7cE04BecE3b29e5cEe4F3251d250dB'); - await getxTokenIssuingProxyBridgeBytecode('https://rpc.ankr.com/eth_goerli', 'v1.0.0', "0x2279B98741D66ccbB1a9e8c80A571378a29afCf0", "0xa3D85134B8f8dB225D54AA4C5E4A25Bda3bD50eA"); + //await getxTokenIssuingProxyBridgeBytecode('https://rpc.ankr.com/eth_goerli', 'v1.0.0', "0x2279B98741D66ccbB1a9e8c80A571378a29afCf0", "0xa3D85134B8f8dB225D54AA4C5E4A25Bda3bD50eA"); + await getLnv3ProxyBridgeBytecode('https://rpc.ankr.com/eth_goerli', 'v1.0.0', "0xC4Cecb7d4c0eA6c7AA88CbdE56612Cdc2DE2E756", "0xE3979fFa68BBa1F53c6F502c8F5788B370d28730"); } main() diff --git a/helix-contract/deploy/deploy_ln_configure.js b/helix-contract/deploy/deploy_ln_configure.js deleted file mode 100644 index 822957d5..00000000 --- a/helix-contract/deploy/deploy_ln_configure.js +++ /dev/null @@ -1,580 +0,0 @@ -const ethUtil = require('ethereumjs-util'); -const abi = require('ethereumjs-abi'); -const secp256k1 = require('secp256k1'); -const fs = require("fs"); - -var ProxyDeployer = require("./proxy.js"); - -const privateKey = process.env.PRIKEY - -const kNativeTokenAddress = "0x0000000000000000000000000000000000000000"; -const relayer = "0xB2a0654C6b2D0975846968D5a3e729F5006c2894"; - -const lineaGoerliNetwork = { - name: "linea-goerli", - url: "https://rpc.goerli.linea.build", - chainId: 59140, - eth: "0x0000000000000000000000000000000000000000", -} - -const arbitrumGoerliNetwork = { - name: "arbitrum-goerli", - url: "https://goerli-rollup.arbitrum.io/rpc", - chainId: 421613, - eth: "0x0000000000000000000000000000000000000000", -}; - -const goerliNetwork = { - name: "goerli", - url: "https://rpc.ankr.com/eth_goerli", - chainId: 5, - eth: "0x0000000000000000000000000000000000000000", - mnt: "0xc1dC2d65A2243c22344E725677A3E3BEBD26E604", -}; - -const mantleGoerliNetwork = { - name: "mantle-goerli", - url: "https://rpc.testnet.mantle.xyz", - chainId: 5001, - mnt: "0x0000000000000000000000000000000000000000", -} - -const zkSyncGoerliNetwork = { - name: "zksync-goerli", - url: "https://zksync2-testnet.zksync.dev", - chainId: 280, - eth: "0x0000000000000000000000000000000000000000", -}; - -const crabNetwork = { - name: "crab", - url: "https://crab-rpc.darwinia.network", - chainId: 44, - crab: "0x0000000000000000000000000000000000000000", -}; - -const arbitrumSepoliaNetwork = { - name: "arbitrum-sepolia", - url: "https://sepolia-rollup.arbitrum.io/rpc", - chainId: 421614, - eth: "0x0000000000000000000000000000000000000000", -}; - -function wait(ms) { - return new Promise(resolve => setTimeout(() => resolve(), ms)); -}; - -function wallet(url) { - const provider = new ethers.providers.JsonRpcProvider(url); - const wallet = new ethers.Wallet(privateKey, provider); - return wallet; -} - -async function connectArbAndEth(configure, arbWallet, goerliWallet) { - const eth2arbReceiveService = configure.messagers[arbitrumGoerliNetwork.name].Eth2ArbReceiveService; - const eth2arbSendService = configure.messagers[goerliNetwork.name].Eth2ArbSendService; - const arbOppositeBridgeProxy = configure.LnOppositeBridgeProxy; - const goerliOppositeBridgeProxy = configure.LnOppositeBridgeProxy; - const arbDefaultBridgeProxy = configure.LnDefaultBridgeProxy.others; - const goerliDefaultBridgeProxy = configure.LnDefaultBridgeProxy.others; - - const arbitrumReceiveService = await ethers.getContractAt("Eth2ArbReceiveService", eth2arbReceiveService, arbWallet); - const ethereumSendService = await ethers.getContractAt("Eth2ArbSendService", eth2arbSendService, goerliWallet); - // arb<>eth - // arb->eth opposite bridge using l1->l2 messager - console.log("start to connect arb->eth using l1->l2 messager"); - const arb2ethSource = await ethers.getContractAt("LnOppositeBridge", arbOppositeBridgeProxy, arbWallet); - const arb2ethTarget = await ethers.getContractAt("LnOppositeBridge", goerliOppositeBridgeProxy, goerliWallet); - await arbitrumReceiveService.authoriseAppCaller(arb2ethSource.address, true); - await ethereumSendService.authoriseAppCaller(arb2ethTarget.address, true); - await arb2ethSource.setReceiveService(goerliNetwork.chainId, arb2ethTarget.address, eth2arbReceiveService); - await arb2ethTarget.setSendService(arbitrumGoerliNetwork.chainId, arb2ethSource.address, eth2arbSendService); - // eth->arb default bridge using l1->l2 messager - console.log("start to connect eth->arb using l1->l2 messager"); - const eth2arbSource = await ethers.getContractAt("LnDefaultBridge", arbDefaultBridgeProxy, goerliWallet); - const eth2arbTarget = await ethers.getContractAt("LnDefaultBridge", goerliDefaultBridgeProxy, arbWallet); - await ethereumSendService.authoriseAppCaller(eth2arbSource.address, true); - await arbitrumReceiveService.authoriseAppCaller(eth2arbTarget.address, true); - await eth2arbSource.setSendService(arbitrumGoerliNetwork.chainId, eth2arbTarget.address, eth2arbSendService); - await eth2arbTarget.setReceiveService(goerliNetwork.chainId, eth2arbSource.address, eth2arbReceiveService); - console.log("finish connect arb<>eth token bridge"); -} - -async function connectLineaAndEth(configure, lineaWallet, goerliWallet) { - const eth2lineaReceiveService = configure.messagers[lineaGoerliNetwork.name].Eth2LineaReceiveService; - const eth2lineaSendService = configure.messagers[goerliNetwork.name].Eth2LineaSendService; - const lineaOppositeBridgeProxy = configure.LnOppositeBridgeProxy; - const goerliOppositeBridgeProxy = configure.LnOppositeBridgeProxy; - const lineaDefaultBridgeProxy = configure.LnDefaultBridgeProxy.others; - const goerliDefaultBridgeProxy = configure.LnDefaultBridgeProxy.others; - - const lineaReceiveService = await ethers.getContractAt("Eth2LineaReceiveService", eth2lineaReceiveService, lineaWallet); - const ethereumSendService = await ethers.getContractAt("Eth2LineaSendService", eth2lineaSendService, goerliWallet); - // linea<>eth - // linea->eth opposite bridge using l1->l2 messager - console.log("start to connect linea->eth using l1->l2 messager"); - const linea2ethSource = await ethers.getContractAt("LnOppositeBridge", lineaOppositeBridgeProxy, lineaWallet); - const linea2ethTarget = await ethers.getContractAt("LnOppositeBridge", goerliOppositeBridgeProxy, goerliWallet); - await lineaReceiveService.authoriseAppCaller(linea2ethSource.address, true); - await ethereumSendService.authoriseAppCaller(linea2ethTarget.address, true); - await linea2ethSource.setReceiveService(goerliNetwork.chainId, linea2ethTarget.address, eth2lineaReceiveService); - await linea2ethTarget.setSendService(lineaGoerliNetwork.chainId, linea2ethSource.address, eth2lineaSendService); - // eth->linea default bridge using l1->l2 messager - console.log("start to connect eth->linea using l1->l2 messager"); - const eth2lineaSource = await ethers.getContractAt("LnDefaultBridge", goerliDefaultBridgeProxy, goerliWallet); - const eth2lineaTarget = await ethers.getContractAt("LnDefaultBridge", lineaDefaultBridgeProxy, lineaWallet); - await lineaReceiveService.authoriseAppCaller(eth2lineaTarget.address, true); - await ethereumSendService.authoriseAppCaller(eth2lineaSource.address, true); - await eth2lineaSource.setSendService(lineaGoerliNetwork.chainId, eth2lineaTarget.address, eth2lineaSendService); - await eth2lineaTarget.setReceiveService(goerliNetwork.chainId, eth2lineaSource.address, eth2lineaReceiveService); - console.log("finish connect linea<>eth token bridge"); -} - -async function connectUsingLayerzero(configure, leftWallet, rightWallet, leftNetwork, rightNetwork) { - const leftMessagerAddess = configure.messagers[leftNetwork.name].layerzeroMessager; - const rightMessagerAddress = configure.messagers[rightNetwork.name].layerzeroMessager; - const leftBridgeProxy = leftNetwork.chainId === 280 ? configure.LnDefaultBridgeProxy.zkSync : configure.LnDefaultBridgeProxy.others; - const rightBridgeProxy = rightNetwork.chainId === 280 ? configure.LnDefaultBridgeProxy.zkSync : configure.LnDefaultBridgeProxy.others; - const leftMessager = await ethers.getContractAt("LayerZeroMessager", leftMessagerAddess, leftWallet); - const rightMessager = await ethers.getContractAt("LayerZeroMessager", rightMessagerAddress, rightWallet); - console.log("start to connect network by using layerzero"); - const left = await ethers.getContractAt("LnDefaultBridge", leftBridgeProxy, leftWallet); - const right = await ethers.getContractAt("LnDefaultBridge", rightBridgeProxy, rightWallet); - await leftMessager.authoriseAppCaller(left.address, true); - await rightMessager.authoriseAppCaller(right.address, true); - await left.setSendService(rightNetwork.chainId, right.address, leftMessagerAddess); - await right.setReceiveService(leftNetwork.chainId, left.address, rightMessagerAddress); - await left.setReceiveService(rightNetwork.chainId, right.address, leftMessagerAddess); - await right.setSendService(leftNetwork.chainId, left.address, rightMessagerAddress); -} - -async function connectUsingAxelar(configure, leftWallet, rightWallet, leftNetwork, rightNetwork) { - const leftMessagerAddress = configure.messagers[leftNetwork.name].axelarMessager; - const rightMessagerAddress = configure.messagers[rightNetwork.name].axelarMessager; - const leftBridgeProxy = leftNetwork.chainId === 280 ? configure.LnDefaultBridgeProxy.zkSync : configure.LnDefaultBridgeProxy.others; - const rightBridgeProxy = rightNetwork.chainId === 280 ? configure.LnDefaultBridgeProxy.zkSync : configure.LnDefaultBridgeProxy.others; - - const leftMessager = await ethers.getContractAt("AxelarMessager", leftMessagerAddress, leftWallet); - const rightMessager = await ethers.getContractAt("AxelarMessager", rightMessagerAddress, rightWallet); - console.log("start to connect network by using axelar"); - const left = await ethers.getContractAt("LnDefaultBridge", leftBridgeProxy, leftWallet); - const right = await ethers.getContractAt("LnDefaultBridge", rightBridgeProxy, rightWallet); - await leftMessager.authoriseAppCaller(left.address, true); - await rightMessager.authoriseAppCaller(right.address, true); - await left.setSendService(rightNetwork.chainId, right.address, leftMessagerAddress); - await right.setReceiveService(leftNetwork.chainId, left.address, rightMessagerAddress); - await left.setReceiveService(rightNetwork.chainId, right.address, leftMessagerAddress); - await right.setSendService(leftNetwork.chainId, left.address, rightMessagerAddress); -} - -async function connectUsingDarwiniaMsgport(configure, leftWallet, rightWallet, leftNetwork, rightNetwork) { - const leftMessagerAddress = configure.messagers[leftNetwork.name].darwiniaMsglineMessager; - const rightMessagerAddress = configure.messagers[rightNetwork.name].darwiniaMsglineMessager; - const leftBridgeProxy = leftNetwork.chainId === 280 ? configure.LnDefaultBridgeProxy.zkSync : configure.LnDefaultBridgeProxy.others; - const rightBridgeProxy = rightNetwork.chainId === 280 ? configure.LnDefaultBridgeProxy.zkSync : configure.LnDefaultBridgeProxy.others; - - const leftMessager = await ethers.getContractAt("DarwiniaMsglineMessager", leftMessagerAddress, leftWallet); - const rightMessager = await ethers.getContractAt("DarwiniaMsglineMessager", rightMessagerAddress, rightWallet); - console.log("start to connect network by using darwinia message port"); - const left = await ethers.getContractAt("LnDefaultBridge", leftBridgeProxy, leftWallet); - const right = await ethers.getContractAt("LnDefaultBridge", rightBridgeProxy, rightWallet); - await leftMessager.authoriseAppCaller(left.address, true); - await rightMessager.authoriseAppCaller(right.address, true); - await left.setSendService(rightNetwork.chainId, right.address, leftMessagerAddress); - await right.setReceiveService(leftNetwork.chainId, left.address, rightMessagerAddress); - await left.setReceiveService(rightNetwork.chainId, right.address, leftMessagerAddress); - await right.setSendService(leftNetwork.chainId, left.address, rightMessagerAddress); -} - -async function connectAll(configure, arbWallet, lineaWallet, goerliWallet, mantleWallet, zkSyncWallet, crabWallet, arbSepoliaWallet) { - // arbitrum L2 message - await connectArbAndEth(configure, arbWallet, goerliWallet); - // linea L2 message - await connectLineaAndEth(configure, lineaWallet, goerliWallet); - await connectUsingLayerzero(configure, arbWallet, lineaWallet, arbitrumGoerliNetwork, lineaGoerliNetwork); - await connectUsingLayerzero(configure, arbWallet, mantleWallet, arbitrumGoerliNetwork, mantleGoerliNetwork); - await connectUsingLayerzero(configure, arbWallet, zkSyncWallet, arbitrumGoerliNetwork, zkSyncGoerliNetwork); - await connectUsingLayerzero(configure, lineaWallet, mantleWallet, lineaGoerliNetwork, mantleGoerliNetwork); - await connectUsingLayerzero(configure, lineaWallet, zkSyncWallet, lineaGoerliNetwork, zkSyncGoerliNetwork); - await connectUsingLayerzero(configure, zkSyncWallet, mantleWallet, zkSyncGoerliNetwork, mantleGoerliNetwork); - await connectUsingLayerzero(configure, zkSyncWallet, goerliWallet, zkSyncGoerliNetwork, goerliNetwork); - await connectUsingAxelar(configure, mantleWallet, goerliWallet, mantleGoerliNetwork, goerliNetwork); - await connectUsingDarwiniaMsgport(configure, crabWallet, arbSepoliaWallet, crabNetwork, arbitrumSepoliaNetwork); -} - -async function registerToken(configure, contractName, srcWallet, dstWallet, srcNetwork, dstNetwork, srcToken, dstToken) { - - let srcDecimals = 18; - let dstDecimals = 18; - let srcTokenAddress = srcNetwork[srcToken]; - let dstTokenAddress = dstNetwork[dstToken]; - if (srcToken !== 'eth' && srcToken !== 'mnt') { - srcTokenAddress = configure[srcToken][srcNetwork.name]; - } - if (dstToken !== 'eth' && dstToken !== 'mnt') { - dstTokenAddress = configure[dstToken][dstNetwork.name]; - } - if (srcTokenAddress != kNativeTokenAddress) { - const sourceToken = await ethers.getContractAt("Erc20", srcTokenAddress, srcWallet); - srcDecimals = await sourceToken.decimals(); - } - if (dstTokenAddress != kNativeTokenAddress) { - const targetToken = await ethers.getContractAt("Erc20", dstTokenAddress, dstWallet); - dstDecimals = await targetToken.decimals(); - } - let fee = ethers.utils.parseUnits("100", srcDecimals); - const penaltyDecimals = contractName == "LnOppositeBridge" ? srcDecimals : dstDecimals; - let penalty = ethers.utils.parseUnits("1000", penaltyDecimals); - if (srcTokenAddress == kNativeTokenAddress || dstTokenAddress == kNativeTokenAddress) { - fee = ethers.utils.parseUnits("0.001", srcDecimals); - penalty = ethers.utils.parseUnits("0.01", penaltyDecimals); - } - - const defaultAddress = srcNetwork.chainId === 280 ? configure.LnDefaultBridgeProxy.zkSync : configure.LnDefaultBridgeProxy.others; - const proxyAddress = contractName == "LnOppositeBridge" ? configure.LnOppositeBridgeProxy : defaultAddress; - - const source = await ethers.getContractAt(contractName, proxyAddress, srcWallet); - await source.setTokenInfo( - dstNetwork.chainId, - srcTokenAddress, - dstTokenAddress, - fee, - penalty, - srcDecimals, - dstDecimals); - console.log(`finished register token bridge: ${contractName}, ${srcNetwork.chainId}->${dstNetwork.chainId}, ${srcToken}->${dstToken}`); -} - -async function registerAllToken(configure, arbWallet, lineaWallet, goerliWallet, mantleWallet, zkSyncWallet, crabWallet, arbSepoliaWallet) { - //arb<>eth - await registerToken(configure, "LnOppositeBridge", arbWallet, goerliWallet, arbitrumGoerliNetwork, goerliNetwork, "usdc", "usdc"); - await registerToken(configure, "LnDefaultBridge", goerliWallet, arbWallet, goerliNetwork, arbitrumGoerliNetwork, "usdc", "usdc"); - await registerToken(configure, "LnOppositeBridge", arbWallet, goerliWallet, arbitrumGoerliNetwork, goerliNetwork, "usdt", "usdt"); - await registerToken(configure, "LnDefaultBridge", goerliWallet, arbWallet, goerliNetwork, arbitrumGoerliNetwork, "usdt", "usdt"); - await registerToken(configure, "LnOppositeBridge", arbWallet, goerliWallet, arbitrumGoerliNetwork, goerliNetwork, "eth", "eth"); - await registerToken(configure, "LnDefaultBridge", goerliWallet, arbWallet, goerliNetwork, arbitrumGoerliNetwork, "eth", "eth"); - - // linea<>eth - await registerToken(configure, "LnOppositeBridge", lineaWallet, goerliWallet, lineaGoerliNetwork, goerliNetwork, "usdc", "usdc"); - await registerToken(configure, "LnDefaultBridge", goerliWallet, lineaWallet, goerliNetwork, lineaGoerliNetwork, "usdc", "usdc"); - await registerToken(configure, "LnOppositeBridge", lineaWallet, goerliWallet, lineaGoerliNetwork, goerliNetwork, "usdt", "usdt"); - await registerToken(configure, "LnDefaultBridge", goerliWallet, lineaWallet, goerliNetwork, lineaGoerliNetwork, "usdt", "usdt"); - await registerToken(configure, "LnOppositeBridge", lineaWallet, goerliWallet, lineaGoerliNetwork, goerliNetwork, "eth", "eth"); - await registerToken(configure, "LnDefaultBridge", goerliWallet, lineaWallet, goerliNetwork, lineaGoerliNetwork, "eth", "eth"); - - //arb<>linea - await registerToken(configure, "LnDefaultBridge", arbWallet, lineaWallet, arbitrumGoerliNetwork, lineaGoerliNetwork, "usdc", "usdc"); - await registerToken(configure, "LnDefaultBridge", lineaWallet, arbWallet, lineaGoerliNetwork, arbitrumGoerliNetwork, "usdc", "usdc"); - await registerToken(configure, "LnDefaultBridge", arbWallet, lineaWallet, arbitrumGoerliNetwork, lineaGoerliNetwork, "usdt", "usdt"); - await registerToken(configure, "LnDefaultBridge", lineaWallet, arbWallet, lineaGoerliNetwork, arbitrumGoerliNetwork, "usdt", "usdt"); - await registerToken(configure, "LnDefaultBridge", arbWallet, lineaWallet, arbitrumGoerliNetwork, lineaGoerliNetwork, "eth", "eth"); - await registerToken(configure, "LnDefaultBridge", lineaWallet, arbWallet, lineaGoerliNetwork, arbitrumGoerliNetwork, "eth", "eth"); - - //arb<>mantle - await registerToken(configure, "LnDefaultBridge", arbWallet, mantleWallet, arbitrumGoerliNetwork, mantleGoerliNetwork, "usdc", "usdc"); - await registerToken(configure, "LnDefaultBridge", mantleWallet, arbWallet, mantleGoerliNetwork, arbitrumGoerliNetwork, "usdc", "usdc"); - await registerToken(configure, "LnDefaultBridge", arbWallet, mantleWallet, arbitrumGoerliNetwork, mantleGoerliNetwork, "usdt", "usdt"); - await registerToken(configure, "LnDefaultBridge", mantleWallet, arbWallet, mantleGoerliNetwork, arbitrumGoerliNetwork, "usdt", "usdt"); - - // mantle<>linea - await registerToken(configure, "LnDefaultBridge", mantleWallet, lineaWallet, mantleGoerliNetwork, lineaGoerliNetwork, "usdc", "usdc"); - await registerToken(configure, "LnDefaultBridge", lineaWallet, mantleWallet, lineaGoerliNetwork, mantleGoerliNetwork, "usdc", "usdc"); - await registerToken(configure, "LnDefaultBridge", mantleWallet, lineaWallet, mantleGoerliNetwork, lineaGoerliNetwork, "usdt", "usdt"); - await registerToken(configure, "LnDefaultBridge", lineaWallet, mantleWallet, lineaGoerliNetwork, mantleGoerliNetwork, "usdt", "usdt"); - - // mantle<>eth - await registerToken(configure, "LnDefaultBridge", goerliWallet, mantleWallet, goerliNetwork, mantleGoerliNetwork, "usdc", "usdc"); - await registerToken(configure, "LnDefaultBridge", mantleWallet, goerliWallet, mantleGoerliNetwork, goerliNetwork, "usdc", "usdc"); - await registerToken(configure, "LnDefaultBridge", goerliWallet, mantleWallet, goerliNetwork, mantleGoerliNetwork, "usdt", "usdt"); - await registerToken(configure, "LnDefaultBridge", mantleWallet, goerliWallet, mantleGoerliNetwork, goerliNetwork, "usdt", "usdt"); - await registerToken(configure, "LnDefaultBridge", goerliWallet, mantleWallet, goerliNetwork, mantleGoerliNetwork, "mnt", "mnt"); - await registerToken(configure, "LnDefaultBridge", mantleWallet, goerliWallet, mantleGoerliNetwork, goerliNetwork, "mnt", "mnt"); - - // zkSync<>eth - await registerToken(configure, "LnDefaultBridge", zkSyncWallet, goerliWallet, zkSyncGoerliNetwork, goerliNetwork, "usdc", "usdc"); - await registerToken(configure, "LnDefaultBridge", goerliWallet, zkSyncWallet, goerliNetwork, zkSyncGoerliNetwork, "usdc", "usdc"); - await registerToken(configure, "LnDefaultBridge", zkSyncWallet, goerliWallet, zkSyncGoerliNetwork, goerliNetwork, "usdt", "usdt"); - await registerToken(configure, "LnDefaultBridge", goerliWallet, zkSyncWallet, goerliNetwork, zkSyncGoerliNetwork, "usdt", "usdt"); - await registerToken(configure, "LnDefaultBridge", zkSyncWallet, goerliWallet, zkSyncGoerliNetwork, goerliNetwork, "eth", "eth"); - await registerToken(configure, "LnDefaultBridge", goerliWallet, zkSyncWallet, goerliNetwork, zkSyncGoerliNetwork, "eth", "eth"); - - // zkSync<>arb - await registerToken(configure, "LnDefaultBridge", zkSyncWallet, arbWallet, zkSyncGoerliNetwork, arbitrumGoerliNetwork, "usdc", "usdc"); - await registerToken(configure, "LnDefaultBridge", arbWallet, zkSyncWallet, arbitrumGoerliNetwork, zkSyncGoerliNetwork, "usdc", "usdc"); - await registerToken(configure, "LnDefaultBridge", zkSyncWallet, arbWallet, zkSyncGoerliNetwork, arbitrumGoerliNetwork, "usdt", "usdt"); - await registerToken(configure, "LnDefaultBridge", arbWallet, zkSyncWallet, arbitrumGoerliNetwork, zkSyncGoerliNetwork, "usdt", "usdt"); - await registerToken(configure, "LnDefaultBridge", zkSyncWallet, arbWallet, zkSyncGoerliNetwork, arbitrumGoerliNetwork, "eth", "eth"); - await registerToken(configure, "LnDefaultBridge", arbWallet, zkSyncWallet, arbitrumGoerliNetwork, zkSyncGoerliNetwork, "eth", "eth"); - - // zkSync<>linea - await registerToken(configure, "LnDefaultBridge", zkSyncWallet, lineaWallet, zkSyncGoerliNetwork, lineaGoerliNetwork, "usdc", "usdc"); - await registerToken(configure, "LnDefaultBridge", lineaWallet, zkSyncWallet, lineaGoerliNetwork, zkSyncGoerliNetwork, "usdc", "usdc"); - await registerToken(configure, "LnDefaultBridge", zkSyncWallet, lineaWallet, zkSyncGoerliNetwork, lineaGoerliNetwork, "usdt", "usdt"); - await registerToken(configure, "LnDefaultBridge", lineaWallet, zkSyncWallet, lineaGoerliNetwork, zkSyncGoerliNetwork, "usdt", "usdt"); - await registerToken(configure, "LnDefaultBridge", zkSyncWallet, lineaWallet, zkSyncGoerliNetwork, lineaGoerliNetwork, "eth", "eth"); - await registerToken(configure, "LnDefaultBridge", lineaWallet, zkSyncWallet, lineaGoerliNetwork, zkSyncGoerliNetwork, "eth", "eth"); - - // zkSync<>mantle - await registerToken(configure, "LnDefaultBridge", zkSyncWallet, mantleWallet, zkSyncGoerliNetwork, mantleGoerliNetwork, "usdc", "usdc"); - await registerToken(configure, "LnDefaultBridge", mantleWallet, zkSyncWallet, mantleGoerliNetwork, zkSyncGoerliNetwork, "usdc", "usdc"); - await registerToken(configure, "LnDefaultBridge", zkSyncWallet, mantleWallet, zkSyncGoerliNetwork, mantleGoerliNetwork, "usdt", "usdt"); - await registerToken(configure, "LnDefaultBridge", mantleWallet, zkSyncWallet, mantleGoerliNetwork, zkSyncGoerliNetwork, "usdt", "usdt"); - - // crab<>arbitrum sepoliea - await registerToken(configure, "LnDefaultBridge", crabWallet, arbSepoliaWallet, crabNetwork, arbitrumSepoliaNetwork, "usdc", "usdc"); - await registerToken(configure, "LnDefaultBridge", arbSepoliaWallet, crabWallet, arbitrumSepoliaNetwork, crabNetwork, "usdc", "usdc"); -} - -async function registerRelayer(configure, contractName, srcWallet, dstWallet, srcNetwork, dstNetwork, srcToken, dstToken, increaseMargin) { - let srcTokenAddress = srcNetwork[srcToken]; - let dstTokenAddress = dstNetwork[dstToken]; - let srcDecimals = 18; - let dstDecimals = 18; - if (srcToken !== 'eth' && srcToken !== 'mnt') { - srcTokenAddress = configure[srcToken][srcNetwork.name]; - } - if (dstToken !== 'eth' && dstToken !== 'mnt') { - dstTokenAddress = configure[dstToken][dstNetwork.name]; - } - - let baseFeeAmount = "0.001"; - if (srcTokenAddress != kNativeTokenAddress) { - const sourceToken = await ethers.getContractAt("Erc20", srcTokenAddress, srcWallet); - srcDecimals = await sourceToken.decimals(); - baseFeeAmount = "20"; - } - if (dstTokenAddress != kNativeTokenAddress) { - const targetToken = await ethers.getContractAt("Erc20", dstTokenAddress, dstWallet); - dstDecimals = await targetToken.decimals(); - baseFeeAmount = "20"; - } - let baseFee = ethers.utils.parseUnits(baseFeeAmount, srcDecimals); - const liquidityFeeRate = 30; - - // default bridge - if (contractName == "LnDefaultBridge") { - const defaultAddress = srcNetwork.chainId === 280 ? configure.LnDefaultBridgeProxy.zkSync : configure.LnDefaultBridgeProxy.others; - // set source network - let margin = ethers.utils.parseUnits("1000000", dstDecimals); - let value = 0; - if (dstTokenAddress == kNativeTokenAddress) { - margin = ethers.utils.parseUnits("0.1", dstDecimals); - value = margin; - } - if (!increaseMargin) { - margin = 0; - value = 0; - } - const source = await ethers.getContractAt(contractName, defaultAddress, srcWallet); - await source.setProviderFee( - dstNetwork.chainId, - srcTokenAddress, - dstTokenAddress, - baseFee, - liquidityFeeRate - ); - // set target network - const target = await ethers.getContractAt(contractName, defaultAddress, dstWallet); - await target.depositProviderMargin( - srcNetwork.chainId, - srcTokenAddress, - dstTokenAddress, - margin, - {value: value}, - ); - } else { - let margin = ethers.utils.parseUnits("1000000", srcDecimals); - let value = 0; - if (srcTokenAddress == kNativeTokenAddress) { - margin = ethers.utils.parseUnits("0.1", dstDecimals); - value = margin; - } - if (!increaseMargin) { - margin = 0; - value = 0; - } - const source = await ethers.getContractAt(contractName, configure.LnOppositeBridgeProxy, srcWallet); - await source.updateProviderFeeAndMargin( - dstNetwork.chainId, - srcTokenAddress, - dstTokenAddress, - margin, - baseFee, - liquidityFeeRate, - {value: value} - ); - } - console.log(`finished register relayer: ${contractName}, ${srcNetwork.chainId}->${dstNetwork.chainId}, ${srcToken}->${dstToken}`); -} - -async function registerAllRelayer(configure, arbWallet, lineaWallet, goerliWallet, mantleWallet, zkSyncWallet, crabWallet, arbSepoliaWallet) { - const increaseMargin = true; - //arb<>eth - console.log("start to register arb<>eth relayer"); - await registerRelayer(configure, "LnOppositeBridge", arbWallet, goerliWallet, arbitrumGoerliNetwork, goerliNetwork, "usdc", "usdc", increaseMargin); - await registerRelayer(configure, "LnDefaultBridge", goerliWallet, arbWallet, goerliNetwork, arbitrumGoerliNetwork, "usdc", "usdc", increaseMargin); - await registerRelayer(configure, "LnOppositeBridge", arbWallet, goerliWallet, arbitrumGoerliNetwork, goerliNetwork, "usdt", "usdt", increaseMargin); - await registerRelayer(configure, "LnDefaultBridge", goerliWallet, arbWallet, goerliNetwork, arbitrumGoerliNetwork, "usdt", "usdt", increaseMargin); - await registerRelayer(configure, "LnOppositeBridge", arbWallet, goerliWallet, arbitrumGoerliNetwork, goerliNetwork, "eth", "eth", increaseMargin); - await registerRelayer(configure, "LnDefaultBridge", goerliWallet, arbWallet, goerliNetwork, arbitrumGoerliNetwork, "eth", "eth", increaseMargin); - - // linea<>eth - console.log("start to register linea<>eth relayer"); - await registerRelayer(configure, "LnOppositeBridge", lineaWallet, goerliWallet, lineaGoerliNetwork, goerliNetwork, "usdc", "usdc", increaseMargin); - await registerRelayer(configure, "LnDefaultBridge", goerliWallet, lineaWallet, goerliNetwork, lineaGoerliNetwork, "usdc", "usdc", increaseMargin); - await registerRelayer(configure, "LnOppositeBridge", lineaWallet, goerliWallet, lineaGoerliNetwork, goerliNetwork, "usdt", "usdt", increaseMargin); - await registerRelayer(configure, "LnDefaultBridge", goerliWallet, lineaWallet, goerliNetwork, lineaGoerliNetwork, "usdt", "usdt", increaseMargin); - await registerRelayer(configure, "LnOppositeBridge", lineaWallet, goerliWallet, lineaGoerliNetwork, goerliNetwork, "eth", "eth", increaseMargin); - await registerRelayer(configure, "LnDefaultBridge", goerliWallet, lineaWallet, goerliNetwork, lineaGoerliNetwork, "eth", "eth", increaseMargin); - - //arb<>linea - console.log("start to register linea<>arb relayer"); - await registerRelayer(configure, "LnDefaultBridge", arbWallet, lineaWallet, arbitrumGoerliNetwork, lineaGoerliNetwork, "usdc", "usdc", increaseMargin); - await registerRelayer(configure, "LnDefaultBridge", lineaWallet, arbWallet, lineaGoerliNetwork, arbitrumGoerliNetwork, "usdc", "usdc", increaseMargin); - await registerRelayer(configure, "LnDefaultBridge", arbWallet, lineaWallet, arbitrumGoerliNetwork, lineaGoerliNetwork, "usdt", "usdt", increaseMargin); - await registerRelayer(configure, "LnDefaultBridge", lineaWallet, arbWallet, lineaGoerliNetwork, arbitrumGoerliNetwork, "usdt", "usdt", increaseMargin); - await registerRelayer(configure, "LnDefaultBridge", arbWallet, lineaWallet, arbitrumGoerliNetwork, lineaGoerliNetwork, "eth", "eth", increaseMargin); - await registerRelayer(configure, "LnDefaultBridge", lineaWallet, arbWallet, lineaGoerliNetwork, arbitrumGoerliNetwork, "eth", "eth", increaseMargin); - - //arb<>mantle - console.log("start to register mantle<>arb relayer"); - await registerRelayer(configure, "LnDefaultBridge", arbWallet, mantleWallet, arbitrumGoerliNetwork, mantleGoerliNetwork, "usdc", "usdc", increaseMargin); - await registerRelayer(configure, "LnDefaultBridge", mantleWallet, arbWallet, mantleGoerliNetwork, arbitrumGoerliNetwork, "usdc", "usdc", increaseMargin); - await registerRelayer(configure, "LnDefaultBridge", arbWallet, mantleWallet, arbitrumGoerliNetwork, mantleGoerliNetwork, "usdt", "usdt", increaseMargin); - await registerRelayer(configure, "LnDefaultBridge", mantleWallet, arbWallet, mantleGoerliNetwork, arbitrumGoerliNetwork, "usdt", "usdt", increaseMargin); - - // mantle<>linea - console.log("start to register mantle<>linea relayer"); - await registerRelayer(configure, "LnDefaultBridge", mantleWallet, lineaWallet, mantleGoerliNetwork, lineaGoerliNetwork, "usdc", "usdc", increaseMargin); - await registerRelayer(configure, "LnDefaultBridge", lineaWallet, mantleWallet, lineaGoerliNetwork, mantleGoerliNetwork, "usdc", "usdc", increaseMargin); - await registerRelayer(configure, "LnDefaultBridge", mantleWallet, lineaWallet, mantleGoerliNetwork, lineaGoerliNetwork, "usdt", "usdt", increaseMargin); - await registerRelayer(configure, "LnDefaultBridge", lineaWallet, mantleWallet, lineaGoerliNetwork, mantleGoerliNetwork, "usdt", "usdt", increaseMargin); - - // mantle<>eth - console.log("start to register mantle<>eth relayer"); - await registerRelayer(configure, "LnDefaultBridge", goerliWallet, mantleWallet, goerliNetwork, mantleGoerliNetwork, "usdc", "usdc", increaseMargin); - await registerRelayer(configure, "LnDefaultBridge", mantleWallet, goerliWallet, mantleGoerliNetwork, goerliNetwork, "usdc", "usdc", increaseMargin); - await registerRelayer(configure, "LnDefaultBridge", goerliWallet, mantleWallet, goerliNetwork, mantleGoerliNetwork, "usdt", "usdt", increaseMargin); - await registerRelayer(configure, "LnDefaultBridge", mantleWallet, goerliWallet, mantleGoerliNetwork, goerliNetwork, "usdt", "usdt", increaseMargin); - await registerRelayer(configure, "LnDefaultBridge", goerliWallet, mantleWallet, goerliNetwork, mantleGoerliNetwork, "mnt", "mnt", increaseMargin); - await registerRelayer(configure, "LnDefaultBridge", mantleWallet, goerliWallet, mantleGoerliNetwork, goerliNetwork, "mnt", "mnt", increaseMargin); - - // arb<>zkSync - await registerRelayer(configure, "LnDefaultBridge", arbWallet, zkSyncWallet, arbitrumGoerliNetwork, zkSyncGoerliNetwork, "usdc", "usdc", increaseMargin); - await registerRelayer(configure, "LnDefaultBridge", zkSyncWallet, arbWallet, zkSyncGoerliNetwork, arbitrumGoerliNetwork, "usdc", "usdc", increaseMargin); - await registerRelayer(configure, "LnDefaultBridge", arbWallet, zkSyncWallet, arbitrumGoerliNetwork, zkSyncGoerliNetwork, "usdt", "usdt", increaseMargin); - await registerRelayer(configure, "LnDefaultBridge", zkSyncWallet, arbWallet, zkSyncGoerliNetwork, arbitrumGoerliNetwork, "usdt", "usdt", increaseMargin); - await registerRelayer(configure, "LnDefaultBridge", arbWallet, zkSyncWallet, arbitrumGoerliNetwork, zkSyncGoerliNetwork, "eth", "eth", increaseMargin); - await registerRelayer(configure, "LnDefaultBridge", zkSyncWallet, arbWallet, zkSyncGoerliNetwork, arbitrumGoerliNetwork, "eth", "eth", increaseMargin); - // eth<>zkSync - await registerRelayer(configure, "LnDefaultBridge", goerliWallet, zkSyncWallet, goerliNetwork, zkSyncGoerliNetwork, "usdc", "usdc", increaseMargin); - await registerRelayer(configure, "LnDefaultBridge", zkSyncWallet, goerliWallet, zkSyncGoerliNetwork, goerliNetwork, "usdc", "usdc", increaseMargin); - await registerRelayer(configure, "LnDefaultBridge", goerliWallet, zkSyncWallet, goerliNetwork, zkSyncGoerliNetwork, "usdt", "usdt", increaseMargin); - await registerRelayer(configure, "LnDefaultBridge", zkSyncWallet, goerliWallet, zkSyncGoerliNetwork, goerliNetwork, "usdt", "usdt", increaseMargin); - await registerRelayer(configure, "LnDefaultBridge", goerliWallet, zkSyncWallet, goerliNetwork, zkSyncGoerliNetwork, "eth", "eth", increaseMargin); - await registerRelayer(configure, "LnDefaultBridge", zkSyncWallet, goerliWallet, zkSyncGoerliNetwork, goerliNetwork, "eth", "eth", increaseMargin); - // mantle<>zkSync - await registerRelayer(configure, "LnDefaultBridge", mantleWallet, zkSyncWallet, mantleGoerliNetwork, zkSyncGoerliNetwork, "usdc", "usdc", increaseMargin); - await registerRelayer(configure, "LnDefaultBridge", zkSyncWallet, mantleWallet, zkSyncGoerliNetwork, mantleGoerliNetwork, "usdc", "usdc", increaseMargin); - await registerRelayer(configure, "LnDefaultBridge", mantleWallet, zkSyncWallet, mantleGoerliNetwork, zkSyncGoerliNetwork, "usdt", "usdt", increaseMargin); - await registerRelayer(configure, "LnDefaultBridge", zkSyncWallet, mantleWallet, zkSyncGoerliNetwork, mantleGoerliNetwork, "usdt", "usdt", increaseMargin); - // linea<>zkSync - await registerRelayer(configure, "LnDefaultBridge", lineaWallet, zkSyncWallet, lineaGoerliNetwork, zkSyncGoerliNetwork, "usdc", "usdc", increaseMargin); - await registerRelayer(configure, "LnDefaultBridge", zkSyncWallet, lineaWallet, zkSyncGoerliNetwork, lineaGoerliNetwork, "usdc", "usdc", increaseMargin); - await registerRelayer(configure, "LnDefaultBridge", lineaWallet, zkSyncWallet, lineaGoerliNetwork, zkSyncGoerliNetwork, "usdt", "usdt", increaseMargin); - await registerRelayer(configure, "LnDefaultBridge", zkSyncWallet, lineaWallet, zkSyncGoerliNetwork, lineaGoerliNetwork, "usdt", "usdt", increaseMargin); - await registerRelayer(configure, "LnDefaultBridge", lineaWallet, zkSyncWallet, lineaGoerliNetwork, zkSyncGoerliNetwork, "eth", "eth", increaseMargin); - await registerRelayer(configure, "LnDefaultBridge", zkSyncWallet, lineaWallet, zkSyncGoerliNetwork, lineaGoerliNetwork, "eth", "eth", increaseMargin); - - // crab<>arbitrum sepolia - await registerRelayer(configure, "LnDefaultBridge", crabWallet, arbSepoliaWallet, crabNetwork, arbitrumSepoliaNetwork, "usdc", "usdc", increaseMargin); - await registerRelayer(configure, "LnDefaultBridge", arbSepoliaWallet, crabWallet, arbitrumSepoliaNetwork, crabNetwork, "usdc", "usdc", increaseMargin); -} - -async function mintToken(configure, tokenSymbol, network, wallet, to) { - const tokenAddress = configure[tokenSymbol][network.name]; - const token = await ethers.getContractAt("Erc20", tokenAddress, wallet); - const decimals = await token.decimals(); - const amount = ethers.utils.parseUnits("9000000", decimals); - console.log("start to mint token", tokenSymbol, amount); - await token.mint(to, amount); -} - -async function approveToken(configure, tokenSymbol, network, wallet) { - const tokenAddress = configure[tokenSymbol][network.name]; - const token = await ethers.getContractAt("Erc20", tokenAddress, wallet); - const decimals = await token.decimals(); - console.log("start to approve", tokenSymbol); - - const defaultAddress = network.chainId === 280 ? configure.LnDefaultBridgeProxy.zkSync : configure.LnDefaultBridgeProxy.others; - - await token.approve(defaultAddress, ethers.utils.parseUnits("10000000000000", decimals)); - await wait(5000); - if (network.chainId !== 280) { - await token.approve(configure.LnOppositeBridgeProxy, ethers.utils.parseUnits("10000000000000", decimals)); - await wait(5000); - } - console.log("finished to approve", tokenSymbol); -} - -async function mintAll(configure, relayer, arbWallet, lineaWallet, goerliWallet, mantleWallet, zkSyncWallet, crabWallet, arbSepoliaWallet) { - await mintToken(configure, "usdc", goerliNetwork, goerliWallet, relayer); - await mintToken(configure, "usdt", goerliNetwork, goerliWallet, relayer); - await mintToken(configure, "usdc", lineaGoerliNetwork, lineaWallet, relayer); - await mintToken(configure, "usdt", lineaGoerliNetwork, lineaWallet, relayer); - await mintToken(configure, "usdc", arbitrumGoerliNetwork, arbWallet, relayer); - await mintToken(configure, "usdt", arbitrumGoerliNetwork, arbWallet, relayer); - await mintToken(configure, "usdc", mantleGoerliNetwork, mantleWallet, relayer); - await mintToken(configure, "usdt", mantleGoerliNetwork, mantleWallet, relayer); - await mintToken(configure, "usdt", zkSyncGoerliNetwork, zkSyncWallet, relayer); - await mintToken(configure, "usdc", zkSyncGoerliNetwork, zkSyncWallet, relayer); - await mintToken(configure, "usdc", crabNetwork, crabWallet, relayer); - await mintToken(configure, "usdc", arbitrumSepoliaNetwork, arbSepoliaWallet, relayer); -} - -async function approveAll(configure, arbWallet, lineaWallet, goerliWallet, mantleWallet, zkSyncWallet, crabWallet, arbSepoliaWallet) { - await approveToken(configure, "usdc", goerliNetwork, goerliWallet); - await approveToken(configure, "usdt", goerliNetwork, goerliWallet); - await approveToken(configure, "mnt", goerliNetwork, goerliWallet); - await approveToken(configure, "usdc", lineaGoerliNetwork, lineaWallet); - await approveToken(configure, "usdt", lineaGoerliNetwork, lineaWallet); - await approveToken(configure, "usdc", arbitrumGoerliNetwork, arbWallet); - await approveToken(configure, "usdt", arbitrumGoerliNetwork, arbWallet); - await approveToken(configure, "usdc", mantleGoerliNetwork, mantleWallet); - await approveToken(configure, "usdt", mantleGoerliNetwork, mantleWallet); - await approveToken(configure, "usdt", zkSyncGoerliNetwork, zkSyncWallet); - await approveToken(configure, "usdc", zkSyncGoerliNetwork, zkSyncWallet); - await approveToken(configure, "usdc", crabNetwork, crabWallet); - await approveToken(configure, "usdc", arbitrumSepoliaNetwork, arbSepoliaWallet); -} - -// 2. deploy mapping token factory -async function main() { - const pathConfig = "./address/ln-dev.json"; - const configure = JSON.parse( - fs.readFileSync(pathConfig, "utf8") - ); - - const arbWallet = wallet(arbitrumGoerliNetwork.url); - const lineaWallet = wallet(lineaGoerliNetwork.url); - const goerliWallet = wallet(goerliNetwork.url); - const mantleWallet = wallet(mantleGoerliNetwork.url); - const zkSyncWallet = wallet(zkSyncGoerliNetwork.url); - const crabWallet = wallet(crabNetwork.url); - const arbSepoliaWallet = wallet(arbitrumSepoliaNetwork.url); - - // set messager service - //await connectAll(configure, arbWallet, lineaWallet, goerliWallet, mantleWallet, zkSyncWallet, crabWallet, arbSepoliaWallet); - //await registerAllToken(configure, arbWallet, lineaWallet, goerliWallet, mantleWallet, zkSyncWallet, crabWallet, arbSepoliaWallet); - //await mintAll(configure, relayer, arbWallet, lineaWallet, goerliWallet, mantleWallet, zkSyncWallet, crabWallet, arbSepoliaWallet); - //await approveAll(configure, arbWallet, lineaWallet, goerliWallet, mantleWallet, zkSyncWallet, crabWallet, arbSepoliaWallet); - await registerAllRelayer(configure, arbWallet, lineaWallet, goerliWallet, mantleWallet, zkSyncWallet, crabWallet, arbSepoliaWallet); - console.log("finished!"); -} - -main() - .then(() => process.exit(0)) - .catch((error) => { - console.error(error); - process.exit(1); - }); diff --git a/helix-contract/deploy/deploy_ln_create2.js b/helix-contract/deploy/deploy_ln_create2.js index bc7bbf10..f7dd052d 100644 --- a/helix-contract/deploy/deploy_ln_create2.js +++ b/helix-contract/deploy/deploy_ln_create2.js @@ -1,6 +1,7 @@ const ethUtil = require('ethereumjs-util'); const abi = require('ethereumjs-abi'); const secp256k1 = require('secp256k1'); +const fs = require("fs"); var Create2 = require("./create2.js"); @@ -21,8 +22,9 @@ async function deployCreate2Deployer(networkUrl, version) { from: w.address, to: "0x914d7Fec6aaC8cd542e72Bca78B30650d45643d7", data: `${salt}${bytecode.slice(2)}`, - gasPrice: 2100000000, - nonce: 0, + gasLimit: 2000000, + //gasPrice: 2100000000, + //nonce: 0, }; const tx = await w.sendTransaction(unsignedTransaction); console.log(`deploy create2 tx: ${tx.hash}, salt: ${salt}`); @@ -31,17 +33,13 @@ async function deployCreate2Deployer(networkUrl, version) { // 2. deploy mapping token factory async function main() { - //await deployCreate2Deployer('https://rpc.ankr.com/eth_goerli', 'v1.0.0'); - //await deployCreate2Deployer('https://goerli-rollup.arbitrum.io/rpc', 'v1.0.0'); - //await deployCreate2Deployer('https://rpc.testnet.mantle.xyz', 'v1.0.0'); - //await deployCreate2Deployer('https://rpc.goerli.linea.build', 'v1.0.0'); - //await deployCreate2Deployer('https://arb1.arbitrum.io/rpc', 'v1.0.0'); - //await deployCreate2Deployer('https://rpc.mantle.xyz', 'v1.0.0'); - //await deployCreate2Deployer('https://crab-rpc.darwinia.network', 'v1.0.0'); - //await deployCreate2Deployer('https://binance.llamarpc.com', 'v1.0.0'); - //await deployCreate2Deployer('https://mainnet.base.org', 'v1.0.0'); - //await deployCreate2Deployer('https://optimism.llamarpc.com', 'v1.0.0'); - await deployCreate2Deployer('https://rpc.linea.build', 'v1.0.0'); + const pathConfig = "./address/ln-dev.json"; + const configure = JSON.parse( + fs.readFileSync(pathConfig, "utf8") + ); + + const network = configure.chains['arbitrum-sepolia']; + await deployCreate2Deployer(network.url, 'v1.0.0'); } main() diff --git a/helix-contract/deploy/deploy_ln_logic.js b/helix-contract/deploy/deploy_ln_logic.js deleted file mode 100644 index 7dac1c1f..00000000 --- a/helix-contract/deploy/deploy_ln_logic.js +++ /dev/null @@ -1,109 +0,0 @@ -const ethUtil = require('ethereumjs-util'); -const abi = require('ethereumjs-abi'); -const secp256k1 = require('secp256k1'); - -var Create2 = require("./create2.js"); - -const privateKey = process.env.PRIKEY - -const arbitrumNetwork = { - url: "https://goerli-rollup.arbitrum.io/rpc", - deployer: "0xbe6b2860d3c17a719be0A4911EA0EE689e8357f3", -}; - -const goerliNetwork = { - url: "https://rpc.ankr.com/eth_goerli", - deployer: "0xbe6b2860d3c17a719be0A4911EA0EE689e8357f3", -}; - -const mantleNetwork = { - url: "https://rpc.testnet.mantle.xyz", - deployer: "0xbe6b2860d3c17a719be0A4911EA0EE689e8357f3", -}; - -const lineaNetwork = { - url: "https://rpc.goerli.linea.build", - deployer: "0xbe6b2860d3c17a719be0A4911EA0EE689e8357f3", -}; - -const crabNetwork = { - url: "https://crab-rpc.darwinia.network", - deployer: "0xbe6b2860d3c17a719be0A4911EA0EE689e8357f3", -}; - -const arbitrumSepolia = { - url: "https://sepolia-rollup.arbitrum.io/rpc", - deployer: "0xbe6b2860d3c17a719be0A4911EA0EE689e8357f3", -}; - -const sepoliaNetwork = { - url: "https://rpc-sepolia.rockx.com", - deployer: "0xbe6b2860d3c17a719be0A4911EA0EE689e8357f3", -} - -const scrollSepoliaNetwork = { - url: "https://sepolia-rpc.scroll.io/", - deployer: "0xbe6b2860d3c17a719be0A4911EA0EE689e8357f3", -} - -function wallet(url) { - const provider = new ethers.providers.JsonRpcProvider(url); - const wallet = new ethers.Wallet(privateKey, provider); - return wallet; -} - -async function deployLnDefaultBridge(wallet, deployerAddress, salt) { - const bridgeContract = await ethers.getContractFactory("LnDefaultBridge", wallet); - const bytecode = Create2.getDeployedBytecode(bridgeContract, [], []); - const address = await Create2.deploy(deployerAddress, wallet, bytecode, salt); - console.log("finish to deploy ln default bridge logic, address: ", address); - return address; -} - -async function deployLnOppositeBridge(wallet, deployerAddress, salt) { - const bridgeContract = await ethers.getContractFactory("LnOppositeBridge", wallet); - const bytecode = Create2.getDeployedBytecode(bridgeContract, [], []); - const address = await Create2.deploy(deployerAddress, wallet, bytecode, salt); - console.log("finish to deploy ln opposite bridge logic, address: ", address); - return address; -} - -// 2. deploy mapping token factory -async function main() { - const networks = [goerliNetwork, mantleNetwork, arbitrumNetwork, lineaNetwork, sepoliaNetwork, scrollSepoliaNetwork]; - for (const network of networks) { - const w = wallet(network.url); - const logicAddress = await deployLnDefaultBridge(w, network.deployer, "ln-default-logic-v1.0.0"); - //const logicAddress = await deployLnOppositeBridge(w, network.deployer, "ln-opposite-logic-v1.0.0"); - console.log("finish to deploy logic contract, network is: ", network.url); - } - return; - //const network = goerliNetwork; - //const network = mantleNetwork; - //const network = arbitrumNetwork; - //const network = lineaNetwork; - //const w = wallet(network.url); - //await deployLnDefaultBridge(w, network.deployer, "ln-default-logic-v1.0.3"); - //await deployLnOppositeBridge(w, network.deployer, "ln-opposite-logic-v1.0.2"); - for (const network of networks) { - // deploy logic bridge - const w = wallet(network.url); - const proxyAdmin = await ethers.getContractAt("ProxyAdmin", "0xE3979fFa68BBa1F53c6F502c8F5788B370d28730", w); - - // upgrade default bridge - const logicAddress = await deployLnDefaultBridge(w, network.deployer, "ln-default-logic-v1.0.7"); - await proxyAdmin.upgrade("0x54cc9716905ba8ebdD01E6364125cA338Cd0054E", logicAddress); - // upgrade opposite bridge - //const logicAddress = await deployLnOppositeBridge(w, network.deployer, "ln-opposite-logic-v1.0.6"); - //await proxyAdmin.upgrade("0x79e6f452f1e491a7aF0382FA0a6EF9368691960D", logicAddress); - console.log("finished"); - } -} - -main() - .then(() => process.exit(0)) - .catch((error) => { - console.error(error); - process.exit(1); - }); - diff --git a/helix-contract/deploy/deploy_ln_messager.js b/helix-contract/deploy/deploy_ln_messager.js index 711edf41..92ab4d14 100644 --- a/helix-contract/deploy/deploy_ln_messager.js +++ b/helix-contract/deploy/deploy_ln_messager.js @@ -1,6 +1,7 @@ const ethUtil = require('ethereumjs-util'); const abi = require('ethereumjs-abi'); const secp256k1 = require('secp256k1'); +const fs = require("fs"); var ProxyDeployer = require("./proxy.js"); @@ -78,10 +79,11 @@ const arbitrumSepoliaNetwork = { chainId: 421614, msglineChainId: 421614, msglineAddress: "0x000C61ca18583C9504691f43Ea43C2c638772487", + lzChainId: 10231, + endpoint: "0x6098e96a28E02f27B1e6BD381f870F1C8Bd169d3", + layerzeroMessager: "0x87A649246974732f7AbBe01F2DD81E3D829EF0B7", }; - - const scrollNetwork = { url: "https://sepolia-rpc.scroll.io/", dao: "0x88a39B052d477CfdE47600a7C9950a441Ce61cb4", @@ -94,6 +96,18 @@ const sepoliaNetwork = { dao: "0x88a39B052d477CfdE47600a7C9950a441Ce61cb4", chainId: 11155111, scrollMessager: "0x50c7d3e7f7c656493D1D76aaa1a836CedfCBB16A", + lzChainId: 10161, + endpoint: "0xae92d5aD7583AD66E49A0c67BAd18F6ba52dDDc1", + layerzeroMessager: "0x33C9916a43507aa0a89a3e889522f840aa1245fE", +} + +const zkSyncSepoliaNetwork = { + url: "https://sepolia.era.zksync.dev", + dao: "0x88a39B052d477CfdE47600a7C9950a441Ce61cb4", + chainId: 300, + lzChainId: 10165, + endpoint: "0x093D2CF57f764f09C3c2Ac58a42A2601B8C79281", + layerzeroMessager: "0xf29244511DA9242D8A452f7EB1264B52A19f5058", } function wait(ms) { @@ -123,11 +137,12 @@ async function main() { const zkSyncWallet = wallet(zkSyncNetwork.url); const crabWallet = wallet(crabNetwork.url); const arbSepoliaWallet = wallet(arbitrumSepoliaNetwork.url); + const zkSyncSepoliaWallet = wallet(zkSyncSepoliaNetwork.url); const scrollWallet = wallet(scrollNetwork.url); const sepoliaWallet = wallet(sepoliaNetwork.url); - /* // deploy arb<>eth + /* console.log("deploy arb <> eth messager"); const Eth2ArbReceiveService = await deployContract(arbWallet, "Eth2ArbReceiveService", arbitrumNetwork.dao, goerliNetwork.chainId); const Eth2ArbSendService = await deployContract(goerliWallet, "Eth2ArbSendService", goerliNetwork.dao, goerliNetwork.inbox, arbitrumNetwork.chainId); @@ -143,15 +158,31 @@ async function main() { await Eth2LineaReceiveService.setRemoteMessager(Eth2LineaSendService.address); await Eth2LineaSendService.setRemoteMessager(Eth2LineaReceiveService.address); await wait(10000); + */ // deploy layerZero - console.log("deploy layerzero messager"); - const lzGoerli = await deployContract(goerliWallet, "LayerZeroMessager", goerliNetwork.dao, goerliNetwork.endpoint); - const lzArbitrum = await deployContract(arbWallet, "LayerZeroMessager", arbitrumNetwork.dao, arbitrumNetwork.endpoint); - const lzLinea = await deployContract(lineaWallet, "LayerZeroMessager", lineaNetwork.dao, lineaNetwork.endpoint); - const lzMantle = await deployContract(mantleWallet, "LayerZeroMessager", mantleNetwork.dao, mantleNetwork.endpoint); - // zkSync has been deployed - const lzZkSync = await ethers.getContractAt("LayerZeroMessager", zkSyncNetwork.layerzeroMessager, zkSyncWallet); + //console.log("deploy layerzero messager"); + //const lzGoerli = await deployContract(goerliWallet, "LayerZeroMessager", goerliNetwork.dao, goerliNetwork.endpoint); + //const lzArbitrum = await deployContract(arbWallet, "LayerZeroMessager", arbitrumNetwork.dao, arbitrumNetwork.endpoint); + //const lzLinea = await deployContract(lineaWallet, "LayerZeroMessager", lineaNetwork.dao, lineaNetwork.endpoint); + //const lzMantle = await deployContract(mantleWallet, "LayerZeroMessager", mantleNetwork.dao, mantleNetwork.endpoint); + //// zkSync has been deployed + //const lzZkSync = await ethers.getContractAt("LayerZeroMessager", zkSyncNetwork.layerzeroMessager, zkSyncWallet); + + //const lzSepolia = await deployContract(sepoliaWallet, "LayerZeroMessager", sepoliaNetwork.dao, sepoliaNetwork.endpoint); + //const lzArbitrumSepolia = await deployContract(arbSepoliaWallet, "LayerZeroMessager", arbitrumSepoliaNetwork.dao, arbitrumSepoliaNetwork.endpoint); + //await lzSepolia.setRemoteMessager(arbitrumSepoliaNetwork.chainId, arbitrumSepoliaNetwork.lzChainId, lzArbitrumSepolia.address); + //await lzArbitrumSepolia.setRemoteMessager(sepoliaNetwork.chainId, sepoliaNetwork.lzChainId, lzSepolia.address); + const lzzkSyncSepolia = await ethers.getContractAt("LayerZeroMessager", zkSyncSepoliaNetwork.layerzeroMessager, zkSyncSepoliaWallet); + const lzArbitrumSepolia = await ethers.getContractAt("LayerZeroMessager", arbitrumSepoliaNetwork.layerzeroMessager, arbSepoliaWallet); + const lzSepolia = await ethers.getContractAt("LayerZeroMessager", sepoliaNetwork.layerzeroMessager, sepoliaWallet); + + await lzSepolia.setRemoteMessager(zkSyncSepoliaNetwork.chainId, zkSyncSepoliaNetwork.lzChainId, lzzkSyncSepolia.address); + await lzArbitrumSepolia.setRemoteMessager(zkSyncSepoliaNetwork.chainId, zkSyncSepoliaNetwork.lzChainId, lzzkSyncSepolia.address); + await lzzkSyncSepolia.setRemoteMessager(arbitrumSepoliaNetwork.chainId, arbitrumSepoliaNetwork.lzChainId, lzArbitrumSepolia.address); + await lzzkSyncSepolia.setRemoteMessager(sepoliaNetwork.chainId, sepoliaNetwork.lzChainId, lzSepolia.address); + console.log("confgure layerzero messager"); + /* await lzGoerli.setRemoteMessager(arbitrumNetwork.chainId, arbitrumNetwork.lzChainId, lzArbitrum.address); await lzLinea.setRemoteMessager(arbitrumNetwork.chainId, arbitrumNetwork.lzChainId, lzArbitrum.address); await lzMantle.setRemoteMessager(arbitrumNetwork.chainId, arbitrumNetwork.lzChainId, lzArbitrum.address); @@ -176,7 +207,9 @@ async function main() { await lzLinea.setRemoteMessager(goerliNetwork.chainId, goerliNetwork.lzChainId, lzGoerli.address); await lzMantle.setRemoteMessager(goerliNetwork.chainId, goerliNetwork.lzChainId, lzGoerli.address); await lzZkSync.setRemoteMessager(goerliNetwork.chainId, goerliNetwork.lzChainId, lzGoerli.address); + */ // deploy axelar + /* console.log("deploy axelar messager"); const axGoerli = await deployContract(goerliWallet, "AxelarMessager", goerliNetwork.dao, goerliNetwork.axGateway, goerliNetwork.axGasService); const axArbitrum = await deployContract(arbWallet, "AxelarMessager", arbitrumNetwork.dao, arbitrumNetwork.axGateway, arbitrumNetwork.axGasService); @@ -200,6 +233,7 @@ async function main() { */ // deploy crab<>arbitrum sepolia + /* const msglineCrab = await deployContract(crabWallet, "DarwiniaMsglineMessager", crabNetwork.dao, arbitrumSepoliaNetwork.msglineAddress); const msglineArbSepolia = await deployContract(arbSepoliaWallet, "DarwiniaMsglineMessager", arbitrumSepoliaNetwork.dao, crabNetwork.msglineAddress); await msglineCrab.setRemoteMessager(arbitrumSepoliaNetwork.chainId, arbitrumSepoliaNetwork.msglineChainId, msglineArbSepolia.address); @@ -213,6 +247,7 @@ async function main() { await Eth2ScrollReceiveService.setRemoteMessager(Eth2ScrollSendService.address); await Eth2ScrollSendService.setRemoteMessager(Eth2ScrollReceiveService.address); await wait(10000); + */ /* // deploy debug messager await deployContract(goerliWallet, "DebugMessager"); diff --git a/helix-contract/deploy/deploy_ln_proxy.js b/helix-contract/deploy/deploy_ln_proxy.js deleted file mode 100644 index 60b4e522..00000000 --- a/helix-contract/deploy/deploy_ln_proxy.js +++ /dev/null @@ -1,136 +0,0 @@ -const ethUtil = require('ethereumjs-util'); -const abi = require('ethereumjs-abi'); -const secp256k1 = require('secp256k1'); -const fs = require("fs"); - -var ProxyDeployer = require("./proxy.js"); - -const privateKey = process.env.PRIKEY - -const lineaGoerliNetwork = { - name: "linea-goerli", - url: "https://rpc.goerli.linea.build", - dao: "0x88a39B052d477CfdE47600a7C9950a441Ce61cb4", -}; - -const arbitrumGoerliNetwork = { - name: "arbitrum-goerli", - url: "https://goerli-rollup.arbitrum.io/rpc", - dao: "0x88a39B052d477CfdE47600a7C9950a441Ce61cb4", -}; - -const goerliNetwork = { - name: "goerli", - url: "https://rpc.ankr.com/eth_goerli", - dao: "0x88a39B052d477CfdE47600a7C9950a441Ce61cb4", -}; - -const mantleGoerliNetwork = { - name: "mantle-goerli", - url: "https://rpc.testnet.mantle.xyz", - dao: "0x88a39B052d477CfdE47600a7C9950a441Ce61cb4", -}; - -const crabNetwork = { - name: "crab", - url: "https://crab-rpc.darwinia.network", - dao: "0x88a39B052d477CfdE47600a7C9950a441Ce61cb4", -}; - -const arbitrumSepoliaNetwork = { - name: "arbitrum-sepolia", - url: "https://sepolia-rollup.arbitrum.io/rpc", -} - -const sepoliaNetwork = { - name: "sepolia", - url: "https://rpc-sepolia.rockx.com", - dao: "0x88a39B052d477CfdE47600a7C9950a441Ce61cb4", -}; - -const scrollSepoliaNetwork = { - name: "scroll-sepolia", - url: "https://sepolia-rpc.scroll.io/", - dao: "0x88a39B052d477CfdE47600a7C9950a441Ce61cb4", -}; - -function wallet(url) { - const provider = new ethers.providers.JsonRpcProvider(url); - const wallet = new ethers.Wallet(privateKey, provider); - return wallet; -} - -async function deployLnDefaultBridgeProxy(wallet, salt, dao, proxyAdminAddress, logicAddress, deployer) { - const bridgeContract = await ethers.getContractFactory("LnDefaultBridge", wallet); - const lnBridgeProxy = await ProxyDeployer.deployProxyContract2( - deployer, - salt, - proxyAdminAddress, - bridgeContract, - logicAddress, - [dao], - wallet); - console.log("finish to deploy ln default bridge proxy, address:", lnBridgeProxy); - return lnBridgeProxy; -} - -async function deployLnOppositeBridgeProxy(wallet, salt, dao, proxyAdminAddress, logicAddress, deployer) { - const bridgeContract = await ethers.getContractFactory("LnOppositeBridge", wallet); - const lnBridgeProxy = await ProxyDeployer.deployProxyContract2( - deployer, - salt, - proxyAdminAddress, - bridgeContract, - logicAddress, - [dao], - wallet); - console.log("finish to deploy ln opposite bridge proxy, address:", lnBridgeProxy); - return lnBridgeProxy; -} - -async function deploy() { - // address path - const pathConfig = "./address/ln-dev.json"; - const configure = JSON.parse( - fs.readFileSync(pathConfig, "utf8") - ); - - const chains = [goerliNetwork, lineaGoerliNetwork, arbitrumGoerliNetwork, mantleGoerliNetwork, sepoliaNetwork, scrollSepoliaNetwork]; - for (const chain of chains) { - const w = wallet(chain.url); - const proxyAdmin = configure.ProxyAdmin.others; - const defaultLogicAddress = configure.LnDefaultBridgeLogic.others; - const oppositeLogicAddress = configure.LnOppositeBridgeLogic; - const deployer = configure.deployer; - let proxyAddress = await deployLnDefaultBridgeProxy( - w, - "ln-default-v1.1.2", - chain.dao, - proxyAdmin, - defaultLogicAddress, - deployer, - ); - console.log("deploy proxy success", proxyAddress); - proxyAddress = await deployLnOppositeBridgeProxy( - w, - "ln-opposite-v1.1.2", - chain.dao, - proxyAdmin, - oppositeLogicAddress, - deployer, - ); - console.log("deploy proxy success", proxyAddress); - } -} - -async function main() { - await deploy(); -} - -main() - .then(() => process.exit(0)) - .catch((error) => { - console.error(error); - process.exit(1); - }); - diff --git a/helix-contract/deploy/deploy_ln_test_token.js b/helix-contract/deploy/deploy_ln_test_token.js index 927fb63a..5aa20d32 100644 --- a/helix-contract/deploy/deploy_ln_test_token.js +++ b/helix-contract/deploy/deploy_ln_test_token.js @@ -86,6 +86,11 @@ const arbitrumSepoliaNetwork = { name: "Helix Test Token USDC", symbol: "USDC", decimals: 18 + }, + { + name: "Helix Test Token USDT", + symbol: "USDT", + decimals: 18 } ] }; @@ -130,6 +135,14 @@ function wallet(url) { // 2. deploy mapping token factory async function main() { + const w = wallet(arbitrumSepoliaNetwork.url); + const tokenInfo = arbitrumSepoliaNetwork.tokens[1]; + const tokenContract = await ethers.getContractFactory("HelixTestErc20", w); + const token = await tokenContract.deploy(tokenInfo.name, tokenInfo.symbol, tokenInfo.decimals); + await token.deployed(); + console.log(`finish to deploy test token contract, network is: ${network.url}, address is: ${token.address}`); + return; + const networks = [goerliNetwork, mantleNetwork, arbitrumNetwork, lineaNetwork, sepoliaNetwork, scrollSepoliaNetwork]; for (const network of networks) { const w = wallet(network.url); diff --git a/helix-contract/deploy/deploy_lnv2_configure.js b/helix-contract/deploy/deploy_lnv2_configure.js new file mode 100644 index 00000000..e2b70dd6 --- /dev/null +++ b/helix-contract/deploy/deploy_lnv2_configure.js @@ -0,0 +1,374 @@ +const ethUtil = require('ethereumjs-util'); +const abi = require('ethereumjs-abi'); +const secp256k1 = require('secp256k1'); +const fs = require("fs"); + +var ProxyDeployer = require("./proxy.js"); + +const privateKey = process.env.PRIKEY + +const kNativeTokenAddress = "0x0000000000000000000000000000000000000000"; +const relayer = "0xB2a0654C6b2D0975846968D5a3e729F5006c2894"; + +function wait(ms) { + return new Promise(resolve => setTimeout(() => resolve(), ms)); +}; + +function wallet(url) { + const provider = new ethers.providers.JsonRpcProvider(url); + const wallet = new ethers.Wallet(privateKey, provider); + return wallet; +} + +async function connectArbAndEth(configure, arbWallet, goerliWallet) { + const eth2arbReceiveService = configure.messagers[arbitrumGoerliNetwork.name].Eth2ArbReceiveService; + const eth2arbSendService = configure.messagers[goerliNetwork.name].Eth2ArbSendService; + const arbOppositeBridgeProxy = configure.LnOppositeBridgeProxy; + const goerliOppositeBridgeProxy = configure.LnOppositeBridgeProxy; + const arbDefaultBridgeProxy = configure.LnDefaultBridgeProxy.others; + const goerliDefaultBridgeProxy = configure.LnDefaultBridgeProxy.others; + + const arbitrumReceiveService = await ethers.getContractAt("Eth2ArbReceiveService", eth2arbReceiveService, arbWallet); + const ethereumSendService = await ethers.getContractAt("Eth2ArbSendService", eth2arbSendService, goerliWallet); + // arb<>eth + // arb->eth opposite bridge using l1->l2 messager + console.log("start to connect arb->eth using l1->l2 messager"); + const arb2ethSource = await ethers.getContractAt("LnOppositeBridge", arbOppositeBridgeProxy, arbWallet); + const arb2ethTarget = await ethers.getContractAt("LnOppositeBridge", goerliOppositeBridgeProxy, goerliWallet); + await arbitrumReceiveService.authoriseAppCaller(arb2ethSource.address, true); + await ethereumSendService.authoriseAppCaller(arb2ethTarget.address, true); + await arb2ethSource.setReceiveService(goerliNetwork.chainId, arb2ethTarget.address, eth2arbReceiveService); + await arb2ethTarget.setSendService(arbitrumGoerliNetwork.chainId, arb2ethSource.address, eth2arbSendService); + // eth->arb default bridge using l1->l2 messager + console.log("start to connect eth->arb using l1->l2 messager"); + const eth2arbSource = await ethers.getContractAt("LnDefaultBridge", arbDefaultBridgeProxy, goerliWallet); + const eth2arbTarget = await ethers.getContractAt("LnDefaultBridge", goerliDefaultBridgeProxy, arbWallet); + await ethereumSendService.authoriseAppCaller(eth2arbSource.address, true); + await arbitrumReceiveService.authoriseAppCaller(eth2arbTarget.address, true); + await eth2arbSource.setSendService(arbitrumGoerliNetwork.chainId, eth2arbTarget.address, eth2arbSendService); + await eth2arbTarget.setReceiveService(goerliNetwork.chainId, eth2arbSource.address, eth2arbReceiveService); + console.log("finish connect arb<>eth token bridge"); +} + +async function connectLineaAndEth(configure, lineaWallet, goerliWallet) { + const eth2lineaReceiveService = configure.messagers[lineaGoerliNetwork.name].Eth2LineaReceiveService; + const eth2lineaSendService = configure.messagers[goerliNetwork.name].Eth2LineaSendService; + const lineaOppositeBridgeProxy = configure.LnOppositeBridgeProxy; + const goerliOppositeBridgeProxy = configure.LnOppositeBridgeProxy; + const lineaDefaultBridgeProxy = configure.LnDefaultBridgeProxy.others; + const goerliDefaultBridgeProxy = configure.LnDefaultBridgeProxy.others; + + const lineaReceiveService = await ethers.getContractAt("Eth2LineaReceiveService", eth2lineaReceiveService, lineaWallet); + const ethereumSendService = await ethers.getContractAt("Eth2LineaSendService", eth2lineaSendService, goerliWallet); + // linea<>eth + // linea->eth opposite bridge using l1->l2 messager + console.log("start to connect linea->eth using l1->l2 messager"); + const linea2ethSource = await ethers.getContractAt("LnOppositeBridge", lineaOppositeBridgeProxy, lineaWallet); + const linea2ethTarget = await ethers.getContractAt("LnOppositeBridge", goerliOppositeBridgeProxy, goerliWallet); + await lineaReceiveService.authoriseAppCaller(linea2ethSource.address, true); + await ethereumSendService.authoriseAppCaller(linea2ethTarget.address, true); + await linea2ethSource.setReceiveService(goerliNetwork.chainId, linea2ethTarget.address, eth2lineaReceiveService); + await linea2ethTarget.setSendService(lineaGoerliNetwork.chainId, linea2ethSource.address, eth2lineaSendService); + // eth->linea default bridge using l1->l2 messager + console.log("start to connect eth->linea using l1->l2 messager"); + const eth2lineaSource = await ethers.getContractAt("LnDefaultBridge", goerliDefaultBridgeProxy, goerliWallet); + const eth2lineaTarget = await ethers.getContractAt("LnDefaultBridge", lineaDefaultBridgeProxy, lineaWallet); + await lineaReceiveService.authoriseAppCaller(eth2lineaTarget.address, true); + await ethereumSendService.authoriseAppCaller(eth2lineaSource.address, true); + await eth2lineaSource.setSendService(lineaGoerliNetwork.chainId, eth2lineaTarget.address, eth2lineaSendService); + await eth2lineaTarget.setReceiveService(goerliNetwork.chainId, eth2lineaSource.address, eth2lineaReceiveService); + console.log("finish connect linea<>eth token bridge"); +} + +async function connectUsingLayerzero(configure, pair) { + const leftNetwork = pair.networks[0]; + const rightNetwork = pair.networks[1]; + const leftWallet = pair.wallets[0]; + const rightWallet = pair.wallets[1]; + + const leftGasLimit = leftNetwork.name == 'sepolia' ? 2000000 : null; + const rightGasLimit = rightNetwork.name == 'sepolia' ? 2000000 : null; + + const leftMessagerAddess = configure.messagers[leftNetwork.name].layerzeroMessager; + const rightMessagerAddress = configure.messagers[rightNetwork.name].layerzeroMessager; + const leftBridgeProxy = leftNetwork.chainId === 300 ? configure.LnDefaultBridgeProxy.zksync : configure.LnDefaultBridgeProxy.others; + const rightBridgeProxy = rightNetwork.chainId === 300 ? configure.LnDefaultBridgeProxy.zksync : configure.LnDefaultBridgeProxy.others; + const leftMessager = await ethers.getContractAt("LayerZeroMessager", leftMessagerAddess, leftWallet); + const rightMessager = await ethers.getContractAt("LayerZeroMessager", rightMessagerAddress, rightWallet); + console.log("start to connect network by using layerzero"); + const left = await ethers.getContractAt("LnDefaultBridge", leftBridgeProxy, leftWallet); + const right = await ethers.getContractAt("LnDefaultBridge", rightBridgeProxy, rightWallet); + + await leftMessager.authoriseAppCaller(left.address, true, {gasLimit: leftGasLimit}); + await rightMessager.authoriseAppCaller(right.address, true, {gasLimit: rightGasLimit}); + await left.setSendService(rightNetwork.chainId, right.address, leftMessagerAddess, {gasLimit: leftGasLimit}); + await right.setReceiveService(leftNetwork.chainId, left.address, rightMessagerAddress, {gasLimit: rightGasLimit}); + await left.setReceiveService(rightNetwork.chainId, right.address, leftMessagerAddess, {gasLimit: leftGasLimit}); + await right.setSendService(leftNetwork.chainId, left.address, rightMessagerAddress, {gasLimit: rightGasLimit}); +} + +async function connectUsingAxelar(configure, leftWallet, rightWallet, leftNetwork, rightNetwork) { + const leftMessagerAddress = configure.messagers[leftNetwork.name].axelarMessager; + const rightMessagerAddress = configure.messagers[rightNetwork.name].axelarMessager; + const leftBridgeProxy = leftNetwork.chainId === 300 ? configure.LnDefaultBridgeProxy.zksync : configure.LnDefaultBridgeProxy.others; + const rightBridgeProxy = rightNetwork.chainId === 300 ? configure.LnDefaultBridgeProxy.zksync : configure.LnDefaultBridgeProxy.others; + + const leftMessager = await ethers.getContractAt("AxelarMessager", leftMessagerAddress, leftWallet); + const rightMessager = await ethers.getContractAt("AxelarMessager", rightMessagerAddress, rightWallet); + console.log("start to connect network by using axelar"); + const left = await ethers.getContractAt("LnDefaultBridge", leftBridgeProxy, leftWallet); + const right = await ethers.getContractAt("LnDefaultBridge", rightBridgeProxy, rightWallet); + await leftMessager.authoriseAppCaller(left.address, true); + await rightMessager.authoriseAppCaller(right.address, true); + await left.setSendService(rightNetwork.chainId, right.address, leftMessagerAddress); + await right.setReceiveService(leftNetwork.chainId, left.address, rightMessagerAddress); + await left.setReceiveService(rightNetwork.chainId, right.address, leftMessagerAddress); + await right.setSendService(leftNetwork.chainId, left.address, rightMessagerAddress); +} + +async function connectUsingDarwiniaMsgport(configure, leftWallet, rightWallet, leftNetwork, rightNetwork) { + const leftMessagerAddress = configure.messagers[leftNetwork.name].darwiniaMsglineMessager; + const rightMessagerAddress = configure.messagers[rightNetwork.name].darwiniaMsglineMessager; + const leftBridgeProxy = leftNetwork.chainId === 300 ? configure.LnDefaultBridgeProxy.zksync : configure.LnDefaultBridgeProxy.others; + const rightBridgeProxy = rightNetwork.chainId === 300 ? configure.LnDefaultBridgeProxy.zksync : configure.LnDefaultBridgeProxy.others; + + const leftMessager = await ethers.getContractAt("DarwiniaMsglineMessager", leftMessagerAddress, leftWallet); + const rightMessager = await ethers.getContractAt("DarwiniaMsglineMessager", rightMessagerAddress, rightWallet); + console.log("start to connect network by using darwinia message port"); + const left = await ethers.getContractAt("LnDefaultBridge", leftBridgeProxy, leftWallet); + const right = await ethers.getContractAt("LnDefaultBridge", rightBridgeProxy, rightWallet); + await leftMessager.authoriseAppCaller(left.address, true); + await rightMessager.authoriseAppCaller(right.address, true); + await left.setSendService(rightNetwork.chainId, right.address, leftMessagerAddress); + await right.setReceiveService(leftNetwork.chainId, left.address, rightMessagerAddress); + await left.setReceiveService(rightNetwork.chainId, right.address, leftMessagerAddress); + await right.setSendService(leftNetwork.chainId, left.address, rightMessagerAddress); +} + +async function registerToken(configure, contractName, srcWallet, dstWallet, srcNetwork, dstNetwork, srcToken, dstToken) { + let srcDecimals = 18; + let dstDecimals = 18; + let srcTokenAddress = kNativeTokenAddress; + let dstTokenAddress = kNativeTokenAddress; + if (srcToken !== 'eth') { + srcTokenAddress = configure[srcToken][srcNetwork.name]; + } + if (dstToken !== 'eth') { + dstTokenAddress = configure[dstToken][dstNetwork.name]; + } + if (srcTokenAddress != kNativeTokenAddress) { + const sourceToken = await ethers.getContractAt("Erc20", srcTokenAddress, srcWallet); + srcDecimals = await sourceToken.decimals(); + } + if (dstTokenAddress != kNativeTokenAddress) { + const targetToken = await ethers.getContractAt("Erc20", dstTokenAddress, dstWallet); + dstDecimals = await targetToken.decimals(); + } + let fee = ethers.utils.parseUnits("100", srcDecimals); + const penaltyDecimals = contractName == "LnOppositeBridge" ? srcDecimals : dstDecimals; + let penalty = ethers.utils.parseUnits("1000", penaltyDecimals); + if (srcTokenAddress == kNativeTokenAddress || dstTokenAddress == kNativeTokenAddress) { + fee = ethers.utils.parseUnits("0.001", srcDecimals); + penalty = ethers.utils.parseUnits("0.01", penaltyDecimals); + } + + const defaultAddress = srcNetwork.chainId === 300 ? configure.LnDefaultBridgeProxy.zksync : configure.LnDefaultBridgeProxy.others; + const proxyAddress = contractName == "LnOppositeBridge" ? configure.LnOppositeBridgeProxy : defaultAddress; + + const source = await ethers.getContractAt(contractName, proxyAddress, srcWallet); + await source.setTokenInfo( + dstNetwork.chainId, + srcTokenAddress, + dstTokenAddress, + fee, + penalty, + srcDecimals, + dstDecimals, + { gasLimit: 2000000 } + ); + console.log(`finished register token bridge: ${contractName}, ${srcNetwork.chainId}->${dstNetwork.chainId}, ${srcToken}->${dstToken}`); +} + +async function registerAllToken(configure, pair, bridgeType) { + const leftNetwork = pair.networks[0]; + const rightNetwork = pair.networks[1]; + const leftWallet = pair.wallets[0]; + const rightWallet = pair.wallets[1]; + //arb<>eth + await registerToken(configure, bridgeType, leftWallet, rightWallet, leftNetwork, rightNetwork, "usdc", "usdc"); + await registerToken(configure, bridgeType, leftWallet, rightWallet, leftNetwork, rightNetwork, "usdt", "usdt"); + await registerToken(configure, bridgeType, leftWallet, rightWallet, leftNetwork, rightNetwork, "eth", "eth"); + await registerToken(configure, bridgeType, rightWallet, leftWallet, rightNetwork, leftNetwork, "usdc", "usdc"); + await registerToken(configure, bridgeType, rightWallet, leftWallet, rightNetwork, leftNetwork, "usdt", "usdt"); + await registerToken(configure, bridgeType, rightWallet, leftWallet, rightNetwork, leftNetwork, "eth", "eth"); +} + +async function registerRelayer(configure, contractName, srcWallet, dstWallet, srcNetwork, dstNetwork, srcToken, dstToken, increaseMargin) { + let srcTokenAddress = kNativeTokenAddress; + let dstTokenAddress = kNativeTokenAddress; + let srcDecimals = 18; + let dstDecimals = 18; + if (srcToken !== 'eth') { + srcTokenAddress = configure[srcToken][srcNetwork.name]; + } + if (dstToken !== 'eth') { + dstTokenAddress = configure[dstToken][dstNetwork.name]; + } + + const srcGasLimit = srcNetwork.name == 'sepolia' ? 2000000 : null; + const dstGasLimit = dstNetwork.name == 'sepolia' ? 2000000 : null; + + let baseFeeAmount = "0.001"; + if (srcTokenAddress != kNativeTokenAddress) { + const sourceToken = await ethers.getContractAt("Erc20", srcTokenAddress, srcWallet); + srcDecimals = await sourceToken.decimals(); + baseFeeAmount = "20"; + } + if (dstTokenAddress != kNativeTokenAddress) { + const targetToken = await ethers.getContractAt("Erc20", dstTokenAddress, dstWallet); + dstDecimals = await targetToken.decimals(); + baseFeeAmount = "20"; + } + let baseFee = ethers.utils.parseUnits(baseFeeAmount, srcDecimals); + const liquidityFeeRate = 30; + + // default bridge + if (contractName == "LnDefaultBridge") { + const sourceAddress = srcNetwork.chainId === 300 ? configure.LnDefaultBridgeProxy.zksync : configure.LnDefaultBridgeProxy.others; + const targetAddress = dstNetwork.chainId === 300 ? configure.LnDefaultBridgeProxy.zksync : configure.LnDefaultBridgeProxy.others; + // set source network + let margin = ethers.utils.parseUnits("1000000", dstDecimals); + let value = 0; + if (dstTokenAddress == kNativeTokenAddress) { + margin = ethers.utils.parseUnits("0.01", dstDecimals); + value = margin; + } + if (!increaseMargin) { + margin = 0; + value = 0; + } + const source = await ethers.getContractAt(contractName, sourceAddress, srcWallet); + await source.setProviderFee( + dstNetwork.chainId, + srcTokenAddress, + dstTokenAddress, + baseFee, + liquidityFeeRate, + { gasLimit: srcGasLimit } + ); + // set target network + const target = await ethers.getContractAt(contractName, targetAddress, dstWallet); + await target.depositProviderMargin( + srcNetwork.chainId, + srcTokenAddress, + dstTokenAddress, + margin, + { + value: value, + gasLimit: dstGasLimit + }, + ); + } else { + let margin = ethers.utils.parseUnits("1000000", srcDecimals); + let value = 0; + if (srcTokenAddress == kNativeTokenAddress) { + margin = ethers.utils.parseUnits("0.01", dstDecimals); + value = margin; + } + if (!increaseMargin) { + margin = 0; + value = 0; + } + const source = await ethers.getContractAt(contractName, configure.LnOppositeBridgeProxy, srcWallet); + await source.updateProviderFeeAndMargin( + dstNetwork.chainId, + srcTokenAddress, + dstTokenAddress, + margin, + baseFee, + liquidityFeeRate, + { + value: value, + gasLimit: srcGasLimit + } + ); + } + console.log(`finished register relayer: ${contractName}, ${srcNetwork.chainId}->${dstNetwork.chainId}, ${srcToken}->${dstToken}`); +} + +async function registerAllRelayer(configure, pair, bridgeType) { + const leftNetwork = pair.networks[0]; + const rightNetwork = pair.networks[1]; + const leftWallet = pair.wallets[0]; + const rightWallet = pair.wallets[1]; + const increaseMargin = true; + + await registerRelayer(configure, bridgeType, leftWallet, rightWallet, leftNetwork, rightNetwork, "usdc", "usdc", increaseMargin); + await registerRelayer(configure, bridgeType, rightWallet, leftWallet, rightNetwork, leftNetwork, "usdc", "usdc", increaseMargin); + await registerRelayer(configure, bridgeType, leftWallet, rightWallet, leftNetwork, rightNetwork, "usdt", "usdt", increaseMargin); + await registerRelayer(configure, bridgeType, rightWallet, leftWallet, rightNetwork, leftNetwork, "usdt", "usdt", increaseMargin); + await registerRelayer(configure, bridgeType, leftWallet, rightWallet, leftNetwork, rightNetwork, "eth", "eth", increaseMargin); + await registerRelayer(configure, bridgeType, rightWallet, leftWallet, rightNetwork, leftNetwork, "eth", "eth", increaseMargin); +} + +async function approveToken(configure, tokenSymbol, network, wallet) { + const tokenAddress = configure[tokenSymbol][network.name]; + const token = await ethers.getContractAt("Erc20", tokenAddress, wallet); + const decimals = await token.decimals(); + console.log("start to approve", tokenSymbol); + + const defaultAddress = network.chainId === 300 ? configure.LnDefaultBridgeProxy.zksync : configure.LnDefaultBridgeProxy.others; + + await token.approve(defaultAddress, ethers.utils.parseUnits("10000000000000", decimals)); + await wait(5000); + if (network.chainId !== 300) { + await token.approve(configure.LnOppositeBridgeProxy, ethers.utils.parseUnits("10000000000000", decimals)); + await wait(5000); + } + console.log("finished to approve", tokenSymbol); +} + +async function approveAll(configure, network, wallet) { + await approveToken(configure, "usdc", network, wallet); + await approveToken(configure, "usdt", network, wallet); +} + +// 2. deploy mapping token factory +async function main() { + const pathConfig = "./address/ln-dev.json"; + const configure = JSON.parse( + fs.readFileSync(pathConfig, "utf8") + ); + + const network01 = configure.chains['arbitrum-sepolia']; + const network02 = configure.chains['zksync']; + + const wallet01 = wallet(network01.url); + const wallet02 = wallet(network02.url); + + const pair = { + networks: [network01, network02], + wallets: [wallet01, wallet02] + }; + + // connect + //await connectUsingLayerzero(configure, pair); + // register tokens + //await registerAllToken(configure, pair, "LnDefaultBridge"); + //await registerAllToken(configure, pair, "LnOppositeBridge"); + + // approve + //await approveAll(configure, network01, wallet01); + //await approveAll(configure, network02, wallet02); + + //await registerAllRelayer(configure, pair, "LnDefaultBridge"); + //await registerAllRelayer(configure, pair, "LnOppositeBridge"); + console.log("finished!"); +} + +main() + .then(() => process.exit(0)) + .catch((error) => { + console.error(error); + process.exit(1); + }); diff --git a/helix-contract/deploy/deploy_lnv2_logic.js b/helix-contract/deploy/deploy_lnv2_logic.js new file mode 100644 index 00000000..56f539a8 --- /dev/null +++ b/helix-contract/deploy/deploy_lnv2_logic.js @@ -0,0 +1,59 @@ +const ethUtil = require('ethereumjs-util'); +const abi = require('ethereumjs-abi'); +const secp256k1 = require('secp256k1'); +const fs = require("fs"); + +var Create2 = require("./create2.js"); + +const privateKey = process.env.PRIKEY + +function wallet(configure, network) { + const provider = new ethers.providers.JsonRpcProvider(network.url); + const wallet = new ethers.Wallet(privateKey, provider); + return wallet; +} + +async function deployLnDefaultBridge(wallet, deployerAddress, salt) { + const bridgeContract = await ethers.getContractFactory("LnDefaultBridge", wallet); + const bytecode = Create2.getDeployedBytecode(bridgeContract, [], []); + const address = await Create2.deploy(deployerAddress, wallet, bytecode, salt); + console.log("finish to deploy ln default bridge logic, address: ", address); + return address; +} + +async function deployLnOppositeBridge(wallet, deployerAddress, salt) { + const bridgeContract = await ethers.getContractFactory("LnOppositeBridge", wallet); + const bytecode = Create2.getDeployedBytecode(bridgeContract, [], []); + const address = await Create2.deploy(deployerAddress, wallet, bytecode, salt); + console.log("finish to deploy ln opposite bridge logic, address: ", address); + return address; +} + +// 2. deploy mapping token factory +async function main() { + const pathConfig = "./address/ln-dev.json"; + const configure = JSON.parse( + fs.readFileSync(pathConfig, "utf8") + ); + + // deploy + const network = configure.chains['arbitrum-sepolia']; + const w = wallet(configure, network); + //const logicAddress = await deployLnDefaultBridge(w, network.deployer, "lnv2-default-logic-v1.0.0"); + //const logicAddress = await deployLnOppositeBridge(w, network.deployer, "lnv2-opposite-logic-v1.0.0"); + + console.log("finish to deploy logic contract, address is: ", logicAddress); + + // upgrade + //const proxyAdmin = await ethers.getContractAt("ProxyAdmin", "0xE3979fFa68BBa1F53c6F502c8F5788B370d28730", w); + //await proxyAdmin.upgrade("0x54cc9716905ba8ebdD01E6364125cA338Cd0054E", logicAddress); + //console.log("finished"); +} + +main() + .then(() => process.exit(0)) + .catch((error) => { + console.error(error); + process.exit(1); + }); + diff --git a/helix-contract/deploy/deploy_lnv2_proxy.js b/helix-contract/deploy/deploy_lnv2_proxy.js new file mode 100644 index 00000000..e9bf83ac --- /dev/null +++ b/helix-contract/deploy/deploy_lnv2_proxy.js @@ -0,0 +1,73 @@ +const ethUtil = require('ethereumjs-util'); +const abi = require('ethereumjs-abi'); +const secp256k1 = require('secp256k1'); +const fs = require("fs"); + +var ProxyDeployer = require("./proxy.js"); + +const privateKey = process.env.PRIKEY + +function wallet(configure, network) { + const provider = new ethers.providers.JsonRpcProvider(network.url); + const wallet = new ethers.Wallet(privateKey, provider); + return wallet; +} + +async function deployLnDefaultBridgeProxy(wallet, salt, dao, proxyAdminAddress, logicAddress, deployer) { + const bridgeContract = await ethers.getContractFactory("LnDefaultBridge", wallet); + const lnBridgeProxy = await ProxyDeployer.deployProxyContract2( + deployer, + salt, + proxyAdminAddress, + bridgeContract, + logicAddress, + [dao], + wallet); + console.log("finish to deploy ln default bridge proxy, address:", lnBridgeProxy); + return lnBridgeProxy; +} + +async function deployLnOppositeBridgeProxy(wallet, salt, dao, proxyAdminAddress, logicAddress, deployer) { + const bridgeContract = await ethers.getContractFactory("LnOppositeBridge", wallet); + const lnBridgeProxy = await ProxyDeployer.deployProxyContract2( + deployer, + salt, + proxyAdminAddress, + bridgeContract, + logicAddress, + [dao], + wallet); + console.log("finish to deploy ln opposite bridge proxy, address:", lnBridgeProxy); + return lnBridgeProxy; +} + +async function deploy() { + // address path + const pathConfig = "./address/ln-dev.json"; + const configure = JSON.parse( + fs.readFileSync(pathConfig, "utf8") + ); + + const network = configure.chains['arbitrum-sepolia']; + const w = wallet(configure, network); + + const proxyAdmin = configure.ProxyAdmin.others; + const defaultLogicAddress = configure.LnDefaultBridgeLogic.others; + const oppositeLogicAddress = configure.LnOppositeBridgeLogic; + const deployer = configure.deployer; + //let proxyAddress = await deployLnDefaultBridgeProxy(w, "lnv2-default-v1.0.0", network.dao, proxyAdmin, defaultLogicAddress, deployer); + let proxyAddress = await deployLnOppositeBridgeProxy(w, "lnv2-opposite-v1.0.0", network.dao, proxyAdmin, oppositeLogicAddress, deployer); + console.log("deploy proxy success", proxyAddress); +} + +async function main() { + await deploy(); +} + +main() + .then(() => process.exit(0)) + .catch((error) => { + console.error(error); + process.exit(1); + }); + diff --git a/helix-contract/deploy/deploy_ln_test.js b/helix-contract/deploy/deploy_lnv2_test.js similarity index 91% rename from helix-contract/deploy/deploy_ln_test.js rename to helix-contract/deploy/deploy_lnv2_test.js index 190e20e8..b837521d 100644 --- a/helix-contract/deploy/deploy_ln_test.js +++ b/helix-contract/deploy/deploy_lnv2_test.js @@ -1,10 +1,12 @@ const ethUtil = require('ethereumjs-util'); const abi = require('ethereumjs-abi'); const secp256k1 = require('secp256k1'); +const fs = require("fs"); const privateKey = process.env.PRIKEY const initTransferId = "0x0000000000000000000000000000000000000000000000000000000000000000"; +const relayer = '0xB2a0654C6b2D0975846968D5a3e729F5006c2894'; const networks = { "goerli": { @@ -83,19 +85,19 @@ async function defaultTransferAndLockMargin( const bridge = await ethers.getContractAt("LnDefaultBridge", bridgeAddress, wallet); const expectedFee = await bridge.totalFee( remoteChainId, - wallet.address, + relayer, sourceToken, targetToken, amount); console.log("expect fee is", expectedFee); - const providerInfo = await bridge.srcProviders(getProviderKey(remoteChainId, wallet.address, sourceToken, targetToken)); + const providerInfo = await bridge.srcProviders(getProviderKey(remoteChainId, relayer, sourceToken, targetToken)); const expectedWithdrawNonce = providerInfo.config.withdrawNonce; console.log("expect withdraw nonce is", expectedWithdrawNonce); //const tx = await bridge.callStatic.transferAndLockMargin( const tx = await bridge.transferAndLockMargin( [ remoteChainId, - wallet.address, + relayer, sourceToken, targetToken, providerInfo.lastTransferId, @@ -118,19 +120,19 @@ async function oppositeTransferAndLockMargin( const bridge = await ethers.getContractAt("LnOppositeBridge", bridgeAddress, wallet); const expectedFee = await bridge.totalFee( remoteChainId, - wallet.address, + relayer, sourceToken, targetToken, amount); console.log("expect fee is", expectedFee); - const providerInfo = await bridge.srcProviders(getProviderKey(remoteChainId, wallet.address, sourceToken, targetToken)); + const providerInfo = await bridge.srcProviders(getProviderKey(remoteChainId, relayer, sourceToken, targetToken)); const expectedMargin = providerInfo.config.margin; console.log("expect margin is", expectedMargin); //const tx = await bridge.callStatic.transferAndLockMargin( const tx = await bridge.transferAndLockMargin( [ remoteChainId, - wallet.address, + relayer, sourceToken, targetToken, providerInfo.lastTransferId, @@ -299,17 +301,23 @@ async function withdraw(bridgeType, from, to, sourceToken, targetToken, amount, } } -async function transfer(bridgeType, from, to, sourceToken, targetToken, amount) { +async function transfer(configure, bridgeType, from, to, token, amount) { + const sourceToken = configure[token][from.chain]; + const targetToken = configure[token][to.chain]; + const toChainId = configure.chains[to.chain].chainId; + const sourceTokenContract = await ethers.getContractAt("Erc20", sourceToken, from.wallet); const decimals = await sourceTokenContract.decimals(); const formatedAmount = ethers.utils.parseUnits(amount, decimals); if (bridgeType == "default") { - const bridge = await ethers.getContractAt("LnDefaultBridge", from.defaultBridge, from.wallet); - const previousInfo = await bridge.srcProviders(getProviderKey(to.chainId, from.wallet.address, sourceToken, targetToken)); + const key = from.chain == 'zksync' ? 'zksync' : 'others'; + const fromBridge = configure.LnDefaultBridgeProxy[key]; + const bridge = await ethers.getContractAt("LnDefaultBridge", fromBridge, from.wallet); + const previousInfo = await bridge.srcProviders(getProviderKey(toChainId, relayer, sourceToken, targetToken)); await defaultTransferAndLockMargin( from.wallet, - from.defaultBridge, - to.chainId, + fromBridge, + toChainId, sourceToken, targetToken, formatedAmount @@ -335,12 +343,13 @@ async function transfer(bridgeType, from, to, sourceToken, targetToken, amount) console.log("[default] relay and release margin successed"); */ } else { - const bridge = await ethers.getContractAt("LnOppositeBridge", from.oppositeBridge, from.wallet); - const previousInfo = await bridge.srcProviders(getProviderKey(to.chainId, from.wallet.address, sourceToken, targetToken)); + const fromBridge = configure.LnOppositeBridgeProxy; + const bridge = await ethers.getContractAt("LnOppositeBridge", fromBridge, from.wallet); + const previousInfo = await bridge.srcProviders(getProviderKey(toChainId, from.wallet.address, sourceToken, targetToken)); await oppositeTransferAndLockMargin( from.wallet, - from.oppositeBridge, - to.chainId, + fromBridge, + toChainId, sourceToken, targetToken, formatedAmount @@ -405,17 +414,26 @@ async function eth2arbFee(arb, eth, sourceToken, targetToken) { // 2. deploy mapping token factory async function main() { - for (let network in networks) { - networks[network]['wallet'] = wallet(networks[network]); - } + const pathConfig = "./address/ln-dev.json"; + const configure = JSON.parse( + fs.readFileSync(pathConfig, "utf8") + ); + + const network01 = configure.chains['sepolia']; + const network02 = configure.chains['zksync']; - //await transfer("default", networks.goerli, networks.linea, networks.goerli.usdt, networks.linea.usdt, "320"); - //await transfer("opposite", networks.linea, networks.goerli, networks.linea.usdt, networks.goerli.usdt, "500"); - await transfer("default", networks.goerli, networks.mantle, networks.goerli.usdc, networks.mantle.usdc, "500"); + const from = { + chain: network01.name, + wallet: wallet(network01), + }; + const to = { + chain: network02.name, + wallet: wallet(network02), + }; + + //await transfer(configure, "opposite", from, to, 'usdc', "500"); + await transfer(configure, "default", from, to, 'usdc', "101"); return; - //await transfer("default",networks.mantle, networks.goerli, networks.mantle.usdc, networks.goerli.usdc, "132"); - //console.log("transfer and relay successed"); - //return; /* const fee = await lzFee(networks.arbitrum, networks.linea); diff --git a/helix-contract/deploy/deploy_lnv3_configure.js b/helix-contract/deploy/deploy_lnv3_configure.js new file mode 100644 index 00000000..14aaa5fc --- /dev/null +++ b/helix-contract/deploy/deploy_lnv3_configure.js @@ -0,0 +1,250 @@ +const ethUtil = require('ethereumjs-util'); +const abi = require('ethereumjs-abi'); +const secp256k1 = require('secp256k1'); +const fs = require("fs"); + +var ProxyDeployer = require("./proxy.js"); + +const privateKey = process.env.PRIKEY + +const kNativeTokenAddress = "0x0000000000000000000000000000000000000000"; +const relayer = "0xB2a0654C6b2D0975846968D5a3e729F5006c2894"; + +function wait(ms) { + return new Promise(resolve => setTimeout(() => resolve(), ms)); +}; + +function wallet(url) { + const provider = new ethers.providers.JsonRpcProvider(url); + const wallet = new ethers.Wallet(privateKey, provider); + return wallet; +} + +async function connectUsingLayerzero(configure, pair) { + const leftNetwork = pair.networks[0]; + const rightNetwork = pair.networks[1]; + const leftWallet = pair.wallets[0]; + const rightWallet = pair.wallets[1]; + const leftMessagerAddess = configure.messagers[leftNetwork.name].layerzeroMessager; + const rightMessagerAddress = configure.messagers[rightNetwork.name].layerzeroMessager; + const leftBridgeProxy = leftNetwork.chainId === 300 ? configure.LnV3BridgeProxy.zksync : configure.LnV3BridgeProxy.others; + const rightBridgeProxy = rightNetwork.chainId === 300 ? configure.LnV3BridgeProxy.zksync : configure.LnV3BridgeProxy.others; + const leftMessager = await ethers.getContractAt("LayerZeroMessager", leftMessagerAddess, leftWallet); + const rightMessager = await ethers.getContractAt("LayerZeroMessager", rightMessagerAddress, rightWallet); + console.log("start to connect network by using layerzero"); + const left = await ethers.getContractAt("HelixLnBridgeV3", leftBridgeProxy, leftWallet); + const right = await ethers.getContractAt("HelixLnBridgeV3", rightBridgeProxy, rightWallet); + + await leftMessager.authoriseAppCaller(left.address, true); + await rightMessager.authoriseAppCaller(right.address, true); + await left.setSendService(rightNetwork.chainId, right.address, leftMessagerAddess); + await right.setReceiveService(leftNetwork.chainId, left.address, rightMessagerAddress); + await left.setReceiveService(rightNetwork.chainId, right.address, leftMessagerAddess); + await right.setSendService(leftNetwork.chainId, left.address, rightMessagerAddress); +} + +async function registerToken(configure, srcWallet, dstWallet, srcNetwork, dstNetwork, srcToken, dstToken, tokenIndex) { + let srcDecimals = 18; + let dstDecimals = 18; + let srcTokenAddress = kNativeTokenAddress; + let dstTokenAddress = kNativeTokenAddress; + if (srcToken !== 'eth') { + srcTokenAddress = configure[srcToken][srcNetwork.name]; + } + if (dstToken !== 'eth') { + dstTokenAddress = configure[dstToken][dstNetwork.name]; + } + if (srcTokenAddress != kNativeTokenAddress) { + const sourceToken = await ethers.getContractAt("Erc20", srcTokenAddress, srcWallet); + srcDecimals = await sourceToken.decimals(); + } + if (dstTokenAddress != kNativeTokenAddress) { + const targetToken = await ethers.getContractAt("Erc20", dstTokenAddress, dstWallet); + dstDecimals = await targetToken.decimals(); + } + let fee = ethers.utils.parseUnits("0.01", srcDecimals); + const penaltyDecimals = srcDecimals; + let penalty = ethers.utils.parseUnits("1000", penaltyDecimals); + if (srcTokenAddress == kNativeTokenAddress || dstTokenAddress == kNativeTokenAddress) { + fee = ethers.utils.parseUnits("0.001", srcDecimals); + penalty = ethers.utils.parseUnits("0.01", penaltyDecimals); + } + + const proxyAddress = srcNetwork.chainId === 300 ? configure.LnV3BridgeProxy.zksync : configure.LnV3BridgeProxy.others; + + const source = await ethers.getContractAt("HelixLnBridgeV3", proxyAddress, srcWallet); + + if (tokenIndex > 0) { + await source.registerTokenInfo( + dstNetwork.chainId, + srcTokenAddress, + dstTokenAddress, + fee, + penalty, + srcDecimals, + dstDecimals, + tokenIndex); + } else { + await source.updateTokenInfo( + dstNetwork.chainId, + srcTokenAddress, + dstTokenAddress, + fee, + penalty, + srcDecimals, + dstDecimals); + } + console.log(`finished register token bridge: ${srcNetwork.chainId}->${dstNetwork.chainId}, ${srcToken}->${dstToken}`); +} + +async function registerAllToken(configure, pair) { + const leftNetwork = pair.networks[0]; + const rightNetwork = pair.networks[1]; + const leftWallet = pair.wallets[0]; + const rightWallet = pair.wallets[1]; + // zkSync<>eth + let leftTokenIndex = 0; + let rightTokenIndex = 0; + //await registerToken(configure, leftWallet, rightWallet, leftNetwork, rightNetwork, "usdc", "usdc", leftTokenIndex++); + //await registerToken(configure, rightWallet, leftWallet, rightNetwork, leftNetwork, "usdc", "usdc", rightTokenIndex++); + await registerToken(configure, leftWallet, rightWallet, leftNetwork, rightNetwork, "usdt", "usdt", leftTokenIndex); + await registerToken(configure, rightWallet, leftWallet, rightNetwork, leftNetwork, "usdt", "usdt", rightTokenIndex); + await registerToken(configure, leftWallet, rightWallet, leftNetwork, rightNetwork, "eth", "eth", leftTokenIndex); + await registerToken(configure, rightWallet, leftWallet, rightNetwork, leftNetwork, "eth", "eth", rightTokenIndex); +} + +async function registerRelayer(configure, srcWallet, dstWallet, srcNetwork, dstNetwork, srcToken, dstToken) { + let srcTokenAddress = kNativeTokenAddress; + let dstTokenAddress = kNativeTokenAddress; + let srcDecimals = 18; + let dstDecimals = 18; + if (srcToken !== 'eth') { + srcTokenAddress = configure[srcToken][srcNetwork.name]; + } + if (dstToken !== 'eth') { + dstTokenAddress = configure[dstToken][dstNetwork.name]; + } + + let baseFeeAmount = "0.001"; + if (srcTokenAddress != kNativeTokenAddress) { + const sourceToken = await ethers.getContractAt("Erc20", srcTokenAddress, srcWallet); + srcDecimals = await sourceToken.decimals(); + baseFeeAmount = "20"; + } + if (dstTokenAddress != kNativeTokenAddress) { + const targetToken = await ethers.getContractAt("Erc20", dstTokenAddress, dstWallet); + dstDecimals = await targetToken.decimals(); + baseFeeAmount = "20"; + } + let baseFee = ethers.utils.parseUnits(baseFeeAmount, srcDecimals); + const liquidityFeeRate = 30; + + const proxyAddress = srcNetwork.chainId === 300 ? configure.LnV3BridgeProxy.zksync : configure.LnV3BridgeProxy.others; + // set source network + let penalty = ethers.utils.parseUnits("100000", srcDecimals); + let value = 0; + if (dstTokenAddress == kNativeTokenAddress) { + penalty = ethers.utils.parseUnits("0.01", dstDecimals); + value = penalty; + } + const source = await ethers.getContractAt("HelixLnBridgeV3", proxyAddress, srcWallet); + + await source.registerLnProvider( + dstNetwork.chainId, + srcTokenAddress, + dstTokenAddress, + baseFee, + liquidityFeeRate, + ethers.utils.parseUnits("1000000", srcDecimals), + { gasLimit: 2000000 } + ); + + await source.depositPenaltyReserve( + srcTokenAddress, + penalty, + { + value: value, + gasLimit: 2000000 + } + ); + console.log(`finished register relayer: ${srcNetwork.chainId}->${dstNetwork.chainId}, ${srcToken}->${dstToken}`); +} + +async function registerAllRelayer(configure, pair) { + const leftNetwork = pair.networks[0]; + const rightNetwork = pair.networks[1]; + const leftWallet = pair.wallets[0]; + const rightWallet = pair.wallets[1]; + // eth<>zkSync + await registerRelayer(configure, leftWallet, rightWallet, leftNetwork, rightNetwork, "usdc", "usdc"); + //await registerRelayer(configure, rightWallet, leftWallet, rightNetwork, leftNetwork, "usdc", "usdc"); + await registerRelayer(configure, leftWallet, rightWallet, leftNetwork, rightNetwork, "usdt", "usdt"); + //await registerRelayer(configure, rightWallet, leftWallet, rightNetwork, leftNetwork, "usdt", "usdt"); + await registerRelayer(configure, leftWallet, rightWallet, leftNetwork, rightNetwork, "eth", "eth"); + //await registerRelayer(configure, rightWallet, leftWallet, rightNetwork, leftNetwork, "eth", "eth"); +} + +async function mintToken(configure, tokenSymbol, network, wallet, to) { + const tokenAddress = configure[tokenSymbol][network.name]; + const token = await ethers.getContractAt("Erc20", tokenAddress, wallet); + const decimals = await token.decimals(); + const amount = ethers.utils.parseUnits("9000000", decimals); + console.log("start to mint token", tokenSymbol, amount); + await token.mint(to, amount); +} + +async function approveToken(configure, tokenSymbol, network, wallet) { + const tokenAddress = configure[tokenSymbol][network.name]; + const token = await ethers.getContractAt("Erc20", tokenAddress, wallet); + const decimals = await token.decimals(); + console.log("start to approve", tokenSymbol); + + const proxyAddress = network.chainId === 300 ? configure.LnV3BridgeProxy.zksync : configure.LnV3BridgeProxy.others; + + await token.approve(proxyAddress, ethers.utils.parseUnits("10000000000000", decimals), {gasLimit: 1000000}); + await wait(5000); + console.log("finished to approve", tokenSymbol); +} + +async function approveAll(configure, network, wallet) { + await approveToken(configure, "usdc", network, wallet); + await approveToken(configure, "usdt", network, wallet); +} + +// 2. deploy mapping token factory +async function main() { + const pathConfig = "./address/ln-dev.json"; + const configure = JSON.parse( + fs.readFileSync(pathConfig, "utf8") + ); + + const network01 = configure.chains['zksync']; + const network02 = configure.chains['sepolia']; + + const wallet01 = wallet(network01.url); + const wallet02 = wallet(network02.url); + + const pair = { + networks: [network01, network02], + wallets: [wallet01, wallet02] + }; + + // connect + //await connectUsingLayerzero(configure, pair); + // register tokens + await registerAllToken(configure, pair); + // approve + //await approveAll(configure, network01, wallet01); + //await approveAll(configure, network02, wallet02); + + //await mintToken(configure, 'usdc', network01, wallet01, wallet01.address); + //await registerAllRelayer(configure, pair); + console.log("finished!"); +} + +main() + .then(() => process.exit(0)) + .catch((error) => { + console.error(error); + process.exit(1); + }); diff --git a/helix-contract/deploy/deploy_lnv3_logic.js b/helix-contract/deploy/deploy_lnv3_logic.js new file mode 100644 index 00000000..4bdd1782 --- /dev/null +++ b/helix-contract/deploy/deploy_lnv3_logic.js @@ -0,0 +1,46 @@ +const ethUtil = require('ethereumjs-util'); +const abi = require('ethereumjs-abi'); +const secp256k1 = require('secp256k1'); +const fs = require("fs"); + +var Create2 = require("./create2.js"); + +const privateKey = process.env.PRIKEY + +function wallet(configure, network) { + const provider = new ethers.providers.JsonRpcProvider(network.url); + const wallet = new ethers.Wallet(privateKey, provider); + return wallet; +} + +function chainInfo(configure, network) { + return configure.chains[network]; +} + +async function deployLnBridgeV3(wallet, deployerAddress, salt) { + const bridgeContract = await ethers.getContractFactory("HelixLnBridgeV3", wallet); + const bytecode = Create2.getDeployedBytecode(bridgeContract, [], []); + const address = await Create2.deploy(deployerAddress, wallet, bytecode, salt, 8000000); + console.log("finish to deploy lnv3 bridge logic, address: ", address); + return address; +} + +// 2. deploy mapping token factory +async function main() { + const pathConfig = "./address/ln-dev.json"; + const configure = JSON.parse( + fs.readFileSync(pathConfig, "utf8") + ); + + const network = chainInfo(configure, "arbitrum-sepolia"); + const w = wallet(configure, network); + const logicAddress = await deployLnBridgeV3(w, network.deployer, "lnv3-logic-v1.0.0"); +} + +main() + .then(() => process.exit(0)) + .catch((error) => { + console.error(error); + process.exit(1); + }); + diff --git a/helix-contract/deploy/deploy_lnv3_proxy.js b/helix-contract/deploy/deploy_lnv3_proxy.js new file mode 100644 index 00000000..5cf86a33 --- /dev/null +++ b/helix-contract/deploy/deploy_lnv3_proxy.js @@ -0,0 +1,65 @@ +const ethUtil = require('ethereumjs-util'); +const abi = require('ethereumjs-abi'); +const secp256k1 = require('secp256k1'); +const fs = require("fs"); + +var ProxyDeployer = require("./proxy.js"); + +const privateKey = process.env.PRIKEY + +function wallet(url) { + const provider = new ethers.providers.JsonRpcProvider(url); + const wallet = new ethers.Wallet(privateKey, provider); + return wallet; +} + +async function deployLnBridgeV3Proxy(wallet, salt, dao, proxyAdminAddress, logicAddress, deployer) { + const bridgeContract = await ethers.getContractFactory("HelixLnBridgeV3", wallet); + const lnBridgeProxy = await ProxyDeployer.deployProxyContract2( + deployer, + salt, + proxyAdminAddress, + bridgeContract, + logicAddress, + [dao], + wallet, + { gasLimit: 5000000 } + ); + console.log("finish to deploy lnv3 bridge proxy, address:", lnBridgeProxy); + return lnBridgeProxy; +} + +async function deploy() { + // address path + const pathConfig = "./address/ln-dev.json"; + const configure = JSON.parse( + fs.readFileSync(pathConfig, "utf8") + ); + + const network = configure.chains['arbitrum-sepolia']; + const w = wallet(network.url); + const proxyAdmin = configure.ProxyAdmin.others; + const logicAddress = configure.LnV3BridgeLogic.others; + const deployer = configure.deployer; + let proxyAddress = await deployLnBridgeV3Proxy( + w, + "lnv3-v1.0.0", + network.dao, + proxyAdmin, + logicAddress, + deployer, + ); + console.log("deploy proxy success", proxyAddress); +} + +async function main() { + await deploy(); +} + +main() + .then(() => process.exit(0)) + .catch((error) => { + console.error(error); + process.exit(1); + }); + diff --git a/helix-contract/deploy/deploy_lnv3_test.js b/helix-contract/deploy/deploy_lnv3_test.js new file mode 100644 index 00000000..fabb59e7 --- /dev/null +++ b/helix-contract/deploy/deploy_lnv3_test.js @@ -0,0 +1,247 @@ +const ethUtil = require('ethereumjs-util'); +const abi = require('ethereumjs-abi'); +const secp256k1 = require('secp256k1'); +const fs = require("fs"); + +const privateKey = process.env.PRIKEY + +const initTransferId = "0x0000000000000000000000000000000000000000000000000000000000000000"; + +const networks = { + "goerli": { + url: "https://rpc.ankr.com/eth_goerli", + bridgeProxy: "0xd3cbC2D8469837134F4b2E8089c8e975399aff24", + chainId: 5, + usdc: "0xe9784E0d9A939dbe966b021DE3cd877284DB1B99", + usdt: "0xa39cffE89567eBfb5c306a07dfb6e5B3ba41F358", + }, + "zksync-goerli": { + url: "https://zksync2-testnet.zksync.dev", + bridgeProxy: "0x1162E5266121e0495674b9919b016AD9336eF3F5", + chainId: 280, + usdc: "0xAe60e005C560E869a2bad271e38e3C9D78381aFF", + usdt: "0xb5372ed3bb2CbA63e7908066ac10ee94d30eA839", + }, +}; + +function wait(ms) { + return new Promise(resolve => setTimeout(() => resolve(), ms)); +}; + +async function lockAndRemoteRelease( + wallet, + provider, + bridgeAddress, + remoteChainId, + sourceToken, + targetToken, + amount, + timestamp) { + const bridge = await ethers.getContractAt("LnBridgeSourceV3", bridgeAddress, wallet); + const expectedFee = await bridge.totalFee( + remoteChainId, + provider, + sourceToken, + targetToken, + amount); + console.log("expect fee is", expectedFee); + const value = sourceToken == '0x0000000000000000000000000000000000000000' ? amount.add(expectedFee) : 0; + const params = [ + remoteChainId, + provider, + sourceToken, + targetToken, + expectedFee, + amount, + wallet.address, + timestamp + ]; + //const tx = await bridge.callStatic.lockAndRemoteRelease( + const tx = await bridge.lockAndRemoteRelease( + params, + { value: value } + ); + console.log(tx); + return await bridge.getTransferId(params, amount); +} + +async function relay( + remoteChainId, + toWallet, + toBridgeAddress, + provider, + sourceToken, + targetToken, + sourceAmount, + targetAmount, + receiver, + timestamp, + expectedTransferId, +) { + const toBridge = await ethers.getContractAt("HelixLnBridgeV3", toBridgeAddress, toWallet); + //const tx = await toBridge.callStatic.relay( + await toBridge.relay( + [ + remoteChainId, + provider, + sourceToken, + targetToken, + sourceAmount, + targetAmount, + receiver, + timestamp, + ], + expectedTransferId, + true + ); + //console.log(tx); +} + +async function slash( + wallet, + bridgeAddress, + remoteChainId, + provider, + sourceToken, + targetToken, + sourceAmount, + targetAmount, + receiver, + timestamp, + expectedTransferId, +) { + const bridge = await ethers.getContractAt("LnBridgeTargetV3", bridgeAddress, wallet); + const cost = ethers.utils.parseEther("0.0003"); + + //const tx = await bridge.callStatic.requestSlashAndRemoteRelease( + await bridge.requestSlashAndRemoteRelease( + [ + remoteChainId, + provider, + sourceToken, + targetToken, + sourceAmount, + targetAmount, + receiver, + timestamp + ], + expectedTransferId, + cost, + wallet.address, + {value: cost }, + ); + //console.log(tx); +} + +async function requestWithdrawLiquidity( + wallet, + provider, + remoteChainId, + bridgeAddress, + transferIds, + extParams, +) { + const bridge = await ethers.getContractAt("LnBridgeTargetV3", bridgeAddress, wallet); + const cost = ethers.utils.parseEther("0.0003"); + //const tx = await bridge.callStatic.requestWithdrawLiquidity( + await bridge.requestWithdrawLiquidity( + remoteChainId, + transferIds, + provider, + extParams, + {value: cost }, + ); + //console.log(tx); +} + +function wallet(network) { + const provider = new ethers.providers.JsonRpcProvider(network.url); + const wallet = new ethers.Wallet(privateKey, provider); + return wallet; +} + +// 2. deploy mapping token factory +async function main() { + const provider = '0xB2a0654C6b2D0975846968D5a3e729F5006c2894'; + + const pathConfig = "./address/ln-dev.json"; + const configure = JSON.parse( + fs.readFileSync(pathConfig, "utf8") + ); + + const sourceNetwork = configure.chains['arbitrum-sepolia']; + const targetNetwork = configure.chains['sepolia']; + const sourceWallet = wallet(sourceNetwork); + const targetWallet = wallet(targetNetwork); + + //const sourceToken = '0x0000000000000000000000000000000000000000'; + //const targetToken = '0x0000000000000000000000000000000000000000'; + const sourceToken = configure.usdt['arbitrum-sepolia']; + const targetToken = configure.usdt['sepolia']; + + const timestamp = Date.parse(new Date().toString())/1000; + const amount = ethers.utils.parseEther("111"); + + /* + const transferId = await lockAndRemoteRelease( + sourceWallet, + provider, + configure.LnV3BridgeProxy.others, + targetNetwork.chainId, + sourceToken, + targetToken, + amount, + timestamp + ); + console.log(timestamp, transferId); + return; + + await relay( + sourceNetwork.chainId, + targetWallet, + configure.LnV3BridgeProxy.others, + provider, + sourceToken, + targetToken, + amount, + amount, + "0x88a39B052d477CfdE47600a7C9950a441Ce61cb4", + 1704960830, + "0x110db54735ca7a73984ec654686c7ea9d6fa572fcee138ca109dda58c75d2142" //expectedTransferId, + ); + */ + + await requestWithdrawLiquidity( + targetWallet, + provider, + sourceNetwork.chainId, + configure.LnV3BridgeProxy.others, + ["0x326597a3bcd3017f8d5c4e7eddfcec7d64667f999f3060ac4d9940ee10e13b20"], + "0x88a39B052d477CfdE47600a7C9950a441Ce61cb4", + ); + + /* + await slash( + targetWallet, + configure.LnV3BridgeProxy.others, + sourceNetwork.chainId, + provider, + sourceToken, + targetToken, + amount, + amount, + "0x88a39B052d477CfdE47600a7C9950a441Ce61cb4", + "0x659fa7da", // timestamp + "0x01e40aad095d9a381f3870f288e5977d8ccc5c0bc3ece780fde5cada26fcb8ca", + ); + */ + + return; +} + +main() + .then(() => process.exit(0)) + .catch((error) => { + console.error(error); + process.exit(1); + }); diff --git a/helix-contract/deploy/flatten-lnv3.sh b/helix-contract/deploy/flatten-lnv3.sh new file mode 100644 index 00000000..9ed1ce68 --- /dev/null +++ b/helix-contract/deploy/flatten-lnv3.sh @@ -0,0 +1,3 @@ +path=flatten/lnv3 +mkdir -p $path +yarn flat contracts/ln/HelixLnBridgeV3.sol --output $path/HelixLnBridgeV3.sol diff --git a/helix-contract/deploy/proxy.js b/helix-contract/deploy/proxy.js index e3ba413f..8c7b2105 100644 --- a/helix-contract/deploy/proxy.js +++ b/helix-contract/deploy/proxy.js @@ -27,13 +27,14 @@ var ProxyDeployer = { await proxy.deployed(); return proxy; }, - deployProxyContract2: async function(deployerAddress, salt, proxyAdminAdder, logicFactory, logicAddress, args, wallet) { + deployProxyContract2: async function(deployerAddress, salt, proxyAdminAdder, logicFactory, logicAddress, args, wallet, gasLimit) { const calldata = ProxyDeployer.getInitializerData(logicFactory.interface, args, "initialize"); const proxyContract = await ethers.getContractFactory("TransparentUpgradeableProxy", wallet); const deployedBytecode = Create2.getDeployedBytecode( proxyContract, ["address", "address", "bytes"], - [logicAddress, proxyAdminAdder, calldata] + [logicAddress, proxyAdminAdder, calldata], + { gasLimit: gasLimit } ); return await Create2.deploy(deployerAddress, wallet, deployedBytecode, salt); } diff --git a/helix-contract/flatten/lnv3/HelixLnBridgeV3.sol b/helix-contract/flatten/lnv3/HelixLnBridgeV3.sol new file mode 100644 index 00000000..d8c1dced --- /dev/null +++ b/helix-contract/flatten/lnv3/HelixLnBridgeV3.sol @@ -0,0 +1,1422 @@ +// SPDX-License-Identifier: MIT + +/** + * .----------------. .----------------. .----------------. .----------------. .----------------. + * | .--------------. || .--------------. || .--------------. || .--------------. || .--------------. | + * | | ____ ____ | || | _________ | || | _____ | || | _____ | || | ____ ____ | | + * | | |_ || _| | || | |_ ___ | | || | |_ _| | || | |_ _| | || | |_ _||_ _| | | + * | | | |__| | | || | | |_ \_| | || | | | | || | | | | || | \ \ / / | | + * | | | __ | | || | | _| _ | || | | | _ | || | | | | || | > `' < | | + * | | _| | | |_ | || | _| |___/ | | || | _| |__/ | | || | _| |_ | || | _/ /'`\ \_ | | + * | | |____||____| | || | |_________| | || | |________| | || | |_____| | || | |____||____| | | + * | | | || | | || | | || | | || | | | + * | '--------------' || '--------------' || '--------------' || '--------------' || '--------------' | + * '----------------' '----------------' '----------------' '----------------' '----------------' ' + * + * + * 1/28/2024 + **/ + +pragma solidity ^0.8.17; + +// File contracts/interfaces/IMessager.sol +// License-Identifier: MIT + +interface ILowLevelMessageSender { + function registerRemoteReceiver(uint256 remoteChainId, address remoteBridge) external; + function sendMessage(uint256 remoteChainId, bytes memory message, bytes memory params) external payable; +} + +interface ILowLevelMessageReceiver { + function registerRemoteSender(uint256 remoteChainId, address remoteBridge) external; + function recvMessage(address remoteSender, address localReceiver, bytes memory payload) external; +} + +// File @zeppelin-solidity/contracts/token/ERC20/IERC20.sol@v4.7.3 +// License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol) + + +/** + * @dev Interface of the ERC20 standard as defined in the EIP. + */ +interface IERC20 { + /** + * @dev Emitted when `value` tokens are moved from one account (`from`) to + * another (`to`). + * + * Note that `value` may be zero. + */ + event Transfer(address indexed from, address indexed to, uint256 value); + + /** + * @dev Emitted when the allowance of a `spender` for an `owner` is set by + * a call to {approve}. `value` is the new allowance. + */ + event Approval(address indexed owner, address indexed spender, uint256 value); + + /** + * @dev Returns the amount of tokens in existence. + */ + function totalSupply() external view returns (uint256); + + /** + * @dev Returns the amount of tokens owned by `account`. + */ + function balanceOf(address account) external view returns (uint256); + + /** + * @dev Moves `amount` tokens from the caller's account to `to`. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * Emits a {Transfer} event. + */ + function transfer(address to, uint256 amount) external returns (bool); + + /** + * @dev Returns the remaining number of tokens that `spender` will be + * allowed to spend on behalf of `owner` through {transferFrom}. This is + * zero by default. + * + * This value changes when {approve} or {transferFrom} are called. + */ + function allowance(address owner, address spender) external view returns (uint256); + + /** + * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * IMPORTANT: Beware that changing an allowance with this method brings the risk + * that someone may use both the old and the new allowance by unfortunate + * transaction ordering. One possible solution to mitigate this race + * condition is to first reduce the spender's allowance to 0 and set the + * desired value afterwards: + * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 + * + * Emits an {Approval} event. + */ + function approve(address spender, uint256 amount) external returns (bool); + + /** + * @dev Moves `amount` tokens from `from` to `to` using the + * allowance mechanism. `amount` is then deducted from the caller's + * allowance. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * Emits a {Transfer} event. + */ + function transferFrom( + address from, + address to, + uint256 amount + ) external returns (bool); +} + +// File contracts/utils/TokenTransferHelper.sol +// License-Identifier: MIT + +library TokenTransferHelper { + function safeTransfer( + address token, + address receiver, + uint256 amount + ) internal { + (bool success, bytes memory data) = token.call(abi.encodeWithSelector( + IERC20.transfer.selector, + receiver, + amount + )); + require(success && (data.length == 0 || abi.decode(data, (bool))), "helix:transfer token failed"); + } + + function safeTransferFrom( + address token, + address sender, + address receiver, + uint256 amount + ) internal { + (bool success, bytes memory data) = token.call(abi.encodeWithSelector( + IERC20.transferFrom.selector, + sender, + receiver, + amount + )); + require(success && (data.length == 0 || abi.decode(data, (bool))), "helix:transferFrom token failed"); + } + + function safeTransferNative( + address receiver, + uint256 amount + ) internal { + (bool success,) = payable(receiver).call{value: amount}(""); + require(success, "helix:transfer native token failed"); + } +} + +// File contracts/ln/interface/ILnBridgeSourceV3.sol +// License-Identifier: MIT + +interface ILnBridgeSourceV3 { + function slash( + uint256 _remoteChainId, + bytes32 _transferId, + address _lnProvider, + address _slasher + ) external; + function withdrawLiquidity( + bytes32[] calldata _transferIds, + uint256 _remoteChainId, + address _provider + ) external; +} + +// File contracts/ln/base/LnBridgeTargetV3.sol +// License-Identifier: MIT + + +contract LnBridgeTargetV3 { + uint256 constant public SLASH_EXPIRE_TIME = 60 * 60; + // timestamp: the time when transfer filled, this is also the flag that the transfer is filled(relayed or slashed) + // provider: the transfer lnProvider + struct FillTransfer { + uint64 timestamp; + address provider; + } + + // lockTimestamp: the time when the transfer start from source chain + // the lockTimestamp is verified on source chain + // 1. lockTimestamp verified successed: slasher get the transfer amount, fee and penalty on source chain + // 2. lockTimestamp verified failed: slasher get the transfer amount, but the fee and penalty back to the provider + // sourceAmount: the send amount on source chain + struct SlashInfo { + uint256 remoteChainId; + address slasher; + } + + struct RelayParams { + uint256 remoteChainId; + address provider; + address sourceToken; + address targetToken; + uint112 sourceAmount; + uint112 targetAmount; + address receiver; + uint256 timestamp; + } + + // transferId => FillTransfer + mapping(bytes32 => FillTransfer) public fillTransfers; + // transferId => SlashInfo + mapping(bytes32 => SlashInfo) public slashInfos; + + event TransferFilled(bytes32 transferId, address provider); + event SlashRequest(bytes32 transferId, uint256 remoteChainId, address provider, address sourceToken, address targetToken, address slasher); + event LiquidityWithdrawRequested(bytes32[] transferIds, uint256 remoteChainId); + + function _sendMessageToSource(uint256 _remoteChainId, bytes memory _payload, uint256 feePrepaid, bytes memory _extParams) internal virtual {} + + // relay a tx, usually called by lnProvider + // 1. update the fillTransfers storage to save the relay proof + // 2. transfer token from lnProvider to the receiver + function relay( + RelayParams calldata _params, + bytes32 _expectedTransferId, + bool _relayBySelf + ) external payable { + // _relayBySelf = true to protect that the msg.sender don't relay for others + // _relayBySelf = false to allow that lnProvider can use different account between source chain and target chain + require(!_relayBySelf || _params.provider == msg.sender, "invalid provider"); + bytes32 transferId = keccak256(abi.encodePacked( + _params.remoteChainId, + block.chainid, + _params.provider, + _params.sourceToken, + _params.targetToken, + _params.receiver, + _params.sourceAmount, + _params.targetAmount, + _params.timestamp + )); + require(_expectedTransferId == transferId, "check expected transferId failed"); + FillTransfer memory fillTransfer = fillTransfers[transferId]; + // Make sure this transfer was never filled before + require(fillTransfer.timestamp == 0, "transfer has been filled"); + fillTransfers[transferId] = FillTransfer(uint64(block.timestamp), _params.provider); + + if (_params.targetToken == address(0)) { + require(msg.value == _params.targetAmount, "invalid amount"); + TokenTransferHelper.safeTransferNative(_params.receiver, _params.targetAmount); + } else { + require(msg.value == 0, "value not need"); + TokenTransferHelper.safeTransferFrom(_params.targetToken, msg.sender, _params.receiver, uint256(_params.targetAmount)); + } + emit TransferFilled(transferId, _params.provider); + } + + // slash a tx when timeout + // 1. update fillTransfers and slashInfos storage to save slash proof + // 2. transfer tokens from slasher to receiver for this tx + // 3. send a cross-chain message to source chain to withdraw the amount, fee and penalty from lnProvider + function requestSlashAndRemoteRelease( + RelayParams calldata _params, + bytes32 _expectedTransferId, + uint256 _feePrepaid, + bytes memory _extParams + ) external payable { + bytes32 transferId = keccak256(abi.encodePacked( + _params.remoteChainId, + block.chainid, + _params.provider, + _params.sourceToken, + _params.targetToken, + _params.receiver, + _params.sourceAmount, + _params.targetAmount, + _params.timestamp + )); + require(_expectedTransferId == transferId, "check expected transferId failed"); + + FillTransfer memory fillTransfer = fillTransfers[transferId]; + require(fillTransfer.timestamp == 0, "transfer has been filled"); + + // suppose source chain and target chain has the same block timestamp + // event the timestamp is not sync exactly, this TIMEOUT is also verified on source chain + require(_params.timestamp < block.timestamp - SLASH_EXPIRE_TIME, "time not expired"); + fillTransfers[transferId] = FillTransfer(uint64(block.timestamp), _params.provider); + slashInfos[transferId] = SlashInfo(_params.remoteChainId, msg.sender); + + if (_params.targetToken == address(0)) { + require(msg.value == _params.targetAmount + _feePrepaid, "invalid value"); + TokenTransferHelper.safeTransferNative(_params.receiver, _params.targetAmount); + } else { + require(msg.value == _feePrepaid, "value too large"); + TokenTransferHelper.safeTransferFrom(_params.targetToken, msg.sender, _params.receiver, uint256(_params.targetAmount)); + } + bytes memory message = encodeSlashRequest(transferId, _params.provider, msg.sender); + _sendMessageToSource(_params.remoteChainId, message, _feePrepaid, _extParams); + emit SlashRequest(transferId, _params.remoteChainId, _params.provider, _params.sourceToken, _params.targetToken, msg.sender); + } + + // it's allowed to retry a slash tx because the cross-chain message may fail on source chain + // But it's required that the params must not be modified, it read from the storage saved + function retrySlash(bytes32 transferId, bytes memory _extParams) external payable { + FillTransfer memory fillTransfer = fillTransfers[transferId]; + require(fillTransfer.timestamp > 0, "transfer not filled"); + SlashInfo memory slashInfo = slashInfos[transferId]; + require(slashInfo.slasher == msg.sender, "invalid slasher"); + // send message + bytes memory message = encodeSlashRequest(transferId, fillTransfer.provider, slashInfo.slasher); + _sendMessageToSource(slashInfo.remoteChainId, message, msg.value, _extParams); + } + + // can't withdraw for different providers each time + // the size of the _transferIds should not be too large to be processed outof gas on source chain + function requestWithdrawLiquidity( + uint256 _remoteChainId, + bytes32[] calldata _transferIds, + address _provider, + bytes memory _extParams + ) external payable { + for (uint i = 0; i < _transferIds.length; i++) { + bytes32 transferId = _transferIds[i]; + FillTransfer memory fillTransfer = fillTransfers[transferId]; + // make sure that each transfer has the same provider + require(fillTransfer.provider == _provider, "provider invalid"); + } + bytes memory message = encodeWithdrawLiquidityRequest(_transferIds, _provider); + _sendMessageToSource(_remoteChainId, message, msg.value, _extParams); + emit LiquidityWithdrawRequested(_transferIds, _remoteChainId); + } + + function encodeWithdrawLiquidityRequest( + bytes32[] calldata _transferIds, + address _provider + ) public view returns(bytes memory message) { + message = abi.encodeWithSelector( + ILnBridgeSourceV3.withdrawLiquidity.selector, + _transferIds, + block.chainid, + _provider + ); + } + + function encodeSlashRequest( + bytes32 _transferId, + address _provider, + address _slasher + ) public view returns(bytes memory message) { + message = abi.encodeWithSelector( + ILnBridgeSourceV3.slash.selector, + block.chainid, + _transferId, + _provider, + _slasher + ); + } +} + +// File contracts/utils/AccessController.sol +// License-Identifier: MIT + +/// @title AccessController +/// @notice AccessController is a contract to control the access permission +/// @dev See https://github.com/helix-bridge/contracts/tree/master/helix-contract +contract AccessController { + address public dao; + address public operator; + address public pendingDao; + + modifier onlyDao() { + require(msg.sender == dao, "!dao"); + _; + } + + modifier onlyOperator() { + require(msg.sender == operator, "!operator"); + _; + } + + function _initialize(address _dao) internal { + dao = _dao; + operator = _dao; + } + + function setOperator(address _operator) onlyDao external { + operator = _operator; + } + + function transferOwnership(address _dao) onlyDao external { + pendingDao = _dao; + } + + function acceptOwnership() external { + address newDao = msg.sender; + require(pendingDao == newDao, "!pendingDao"); + delete pendingDao; + dao = newDao; + } +} + +// File @zeppelin-solidity/contracts/utils/Context.sol@v4.7.3 +// License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (utils/Context.sol) + + +/** + * @dev Provides information about the current execution context, including the + * sender of the transaction and its data. While these are generally available + * via msg.sender and msg.data, they should not be accessed in such a direct + * manner, since when dealing with meta-transactions the account sending and + * paying for execution may not be the actual sender (as far as an application + * is concerned). + * + * This contract is only required for intermediate, library-like contracts. + */ +abstract contract Context { + function _msgSender() internal view virtual returns (address) { + return msg.sender; + } + + function _msgData() internal view virtual returns (bytes calldata) { + return msg.data; + } +} + +// File @zeppelin-solidity/contracts/security/Pausable.sol@v4.7.3 +// License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.7.0) (security/Pausable.sol) + + +/** + * @dev Contract module which allows children to implement an emergency stop + * mechanism that can be triggered by an authorized account. + * + * This module is used through inheritance. It will make available the + * modifiers `whenNotPaused` and `whenPaused`, which can be applied to + * the functions of your contract. Note that they will not be pausable by + * simply including this module, only once the modifiers are put in place. + */ +abstract contract Pausable is Context { + /** + * @dev Emitted when the pause is triggered by `account`. + */ + event Paused(address account); + + /** + * @dev Emitted when the pause is lifted by `account`. + */ + event Unpaused(address account); + + bool private _paused; + + /** + * @dev Initializes the contract in unpaused state. + */ + constructor() { + _paused = false; + } + + /** + * @dev Modifier to make a function callable only when the contract is not paused. + * + * Requirements: + * + * - The contract must not be paused. + */ + modifier whenNotPaused() { + _requireNotPaused(); + _; + } + + /** + * @dev Modifier to make a function callable only when the contract is paused. + * + * Requirements: + * + * - The contract must be paused. + */ + modifier whenPaused() { + _requirePaused(); + _; + } + + /** + * @dev Returns true if the contract is paused, and false otherwise. + */ + function paused() public view virtual returns (bool) { + return _paused; + } + + /** + * @dev Throws if the contract is paused. + */ + function _requireNotPaused() internal view virtual { + require(!paused(), "Pausable: paused"); + } + + /** + * @dev Throws if the contract is not paused. + */ + function _requirePaused() internal view virtual { + require(paused(), "Pausable: not paused"); + } + + /** + * @dev Triggers stopped state. + * + * Requirements: + * + * - The contract must not be paused. + */ + function _pause() internal virtual whenNotPaused { + _paused = true; + emit Paused(_msgSender()); + } + + /** + * @dev Returns to normal state. + * + * Requirements: + * + * - The contract must be paused. + */ + function _unpause() internal virtual whenPaused { + _paused = false; + emit Unpaused(_msgSender()); + } +} + +// File contracts/ln/base/LnBridgeSourceV3.sol +// License-Identifier: MIT + + + +/// @title LnBridgeSourceV3 +/// @notice LnBridgeSourceV3 is a contract to help user lock token and then trigger remote chain relay +/// @dev See https://github.com/helix-bridge/contracts/tree/master/helix-contract +contract LnBridgeSourceV3 is Pausable, AccessController { + uint256 constant public LOCK_TIME_DISTANCE = 15 minutes; + uint256 constant public MAX_TRANSFER_AMOUNT = type(uint112).max; + // liquidity fee base rate + // liquidityFee = liquidityFeeRate / LIQUIDITY_FEE_RATE_BASE * sendAmount + // totalProviderFee = baseFee + liquidityFee + uint256 constant public LIQUIDITY_FEE_RATE_BASE = 100000; + uint8 constant public LOCK_STATUS_LOCKED = 1; + uint8 constant public LOCK_STATUS_WITHDRAWN = 2; + uint8 constant public LOCK_STATUS_SLASHED = 3; + // the configure information can be updated + struct TokenConfigure { + // pay to system for each tx + uint112 protocolFee; + // Used to penalise relayer for each slashed transaction + uint112 penalty; + uint8 sourceDecimals; + uint8 targetDecimals; + } + // registered token info + struct TokenInfo { + TokenConfigure config; + // zero index is invalid + // use this index to indict the token info to save gas + uint32 index; + address sourceToken; + address targetToken; + // accumulated system revenues + uint256 protocolFeeIncome; + } + struct TransferParams { + uint256 remoteChainId; + address provider; + address sourceToken; + address targetToken; + uint112 totalFee; + uint112 amount; + address receiver; + // use this timestamp as the lock time + // can't be too far from the block that the transaction confirmed + // This timestamp can also be adjusted to produce different transferId + uint256 timestamp; + } + // hash(remoteChainId, sourceToken, targetToken) => TokenInfo + mapping(bytes32=>TokenInfo) public tokenInfos; + // the token index is used to be stored in lockInfo to save gas + mapping(uint32=>bytes32) public tokenIndexer; + // amountWithFeeAndPenalty = transferAmount + providerFee + penalty < type(uint112).max + // the status only has the following 4 values + // status == 0: lockInfo not exist -> can update to status 1 + // status == 1: lockInfo confirmed on source chain(has not been withdrawn or slashed) -> can update to status 2 or 3 + // status == 2: lockInfo has been withdrawn -> can't update anymore + // status == 3: lockInfo has been slashed -> can't update anymore + // we don't clean lockInfo after withdraw or slash to avoid the hash collision(generate the same transferId) + // when we wan't to get tokenInfo from lockInfo, we should get the key(bytes32) from tokenIndex, then get tokenInfo from key + struct LockInfo { + uint112 amountWithFeeAndPenalty; + uint32 tokenIndex; + uint8 status; + } + // transferId => LockInfo + mapping(bytes32 => LockInfo) public lockInfos; + + struct SourceProviderInfo { + uint112 baseFee; + uint16 liquidityFeeRate; + uint112 transferLimit; + bool pause; + } + + // hash(remoteChainId, provider, sourceToken, targetToken) => SourceProviderInfo + mapping(bytes32=>SourceProviderInfo) public srcProviders; + // for a special source token, all the path start from this chain use the same panaltyReserve + // 1. when a lock tx sent, the penaltyReserves decrease and the penalty move to lockInfo.amountWithFeeAndPenalty + // 2. when withdraw liquidity, it tries to move this penalty lockInfo.amountWithFeeAndPenalty back to penaltyReserves + // 3. when the penaltyReserves is not enough to support one lock tx, the provider is paused to work + // hash(sourceToken, provider) => penalty reserve + mapping(bytes32=>uint256) public penaltyReserves; + + event TokenRegistered( + bytes32 key, + uint256 remoteChainId, + address sourceToken, + address targetToken, + uint112 protocolFee, + uint112 penalty, + uint32 index + ); + event TokenInfoUpdated(bytes32 tokenInfoKey, uint112 protocolFee, uint112 penalty, uint112 sourceDecimals, uint112 targetDecimals); + event FeeIncomeClaimed(bytes32 tokenInfoKey, uint256 amount, address receiver); + event TokenLocked( + TransferParams params, + bytes32 transferId, + uint112 targetAmount, + uint112 fee + ); + event LnProviderUpdated( + uint256 remoteChainId, + address provider, + address sourceToken, + address targetToken, + uint112 baseFee, + uint16 liquidityfeeRate, + uint112 transferLimit + ); + event PenaltyReserveUpdated(address provider, address sourceToken, uint256 updatedPanaltyReserve); + event LiquidityWithdrawn(bytes32[] transferIds, address provider, uint256 amount); + event TransferSlashed(bytes32 transferId, address provider, address slasher, uint112 slashAmount); + event LnProviderPaused(address provider, uint256 remoteChainId, address sourceToken, address targetToken, bool paused); + + modifier allowRemoteCall(uint256 _remoteChainId) { + _verifyRemote(_remoteChainId); + _; + } + + function _verifyRemote(uint256 _remoteChainId) internal virtual {} + + function unpause() external onlyOperator { + _unpause(); + } + + function pause() external onlyOperator { + _pause(); + } + + // register a new token pair by Helix Dao + // if the token pair has been registered, it will revert + // select an unused _index to save the tokenInfo, it's not required that the _index is continous or increased + function registerTokenInfo( + uint256 _remoteChainId, + address _sourceToken, + address _targetToken, + uint112 _protocolFee, + uint112 _penalty, + uint8 _sourceDecimals, + uint8 _targetDecimals, + uint32 _index + ) onlyDao external { + require(_index > 0, "invalid index"); + bytes32 key = getTokenKey(_remoteChainId, _sourceToken, _targetToken); + TokenInfo memory oldInfo = tokenInfos[key]; + require(oldInfo.index == 0, "token info exist"); + require(tokenIndexer[_index] == bytes32(0), "the index exist"); + TokenConfigure memory tokenConfig = TokenConfigure( + _protocolFee, + _penalty, + _sourceDecimals, + _targetDecimals + ); + tokenInfos[key] = TokenInfo( + tokenConfig, + _index, + _sourceToken, + _targetToken, + 0 + ); + tokenIndexer[_index] = key; + emit TokenRegistered(key, _remoteChainId, _sourceToken, _targetToken, _protocolFee, _penalty, _index); + } + + // update a registered token pair + // the key or index cannot be updated + // Attention! source decimals and target decimals + function updateTokenInfo( + uint256 _remoteChainId, + address _sourceToken, + address _targetToken, + uint112 _protocolFee, + uint112 _penalty, + uint8 _sourceDecimals, + uint8 _targetDecimals + ) onlyDao external { + bytes32 key = getTokenKey(_remoteChainId, _sourceToken, _targetToken); + TokenInfo memory tokenInfo = tokenInfos[key]; + require(tokenInfo.index > 0, "token not registered"); + tokenInfos[key].config = TokenConfigure( + _protocolFee, + _penalty, + _sourceDecimals, + _targetDecimals + ); + emit TokenInfoUpdated(key, _protocolFee, _penalty, _sourceDecimals, _targetDecimals); + } + + // delete a token pair by Helix Dao + // This interface should be called with exceptional caution, only when correcting registration errors, to conserve index resources. + // Attention! DON'T delete a used token pair + function deleteTokenInfo(bytes32 key) onlyDao external { + TokenInfo memory tokenInfo = tokenInfos[key]; + require(tokenInfo.index > 0, "token not registered"); + require(tokenIndexer[tokenInfo.index] == key, "indexer exception"); + delete tokenInfos[key]; + delete tokenIndexer[tokenInfo.index]; + } + + // claim the protocol fee + function claimProtocolFeeIncome( + bytes32 _tokenInfoKey, + uint256 _amount, + address _receiver + ) onlyDao external { + TokenInfo memory tokenInfo = tokenInfos[_tokenInfoKey]; + require(tokenInfo.protocolFeeIncome > _amount, "not enough income"); + tokenInfos[_tokenInfoKey].protocolFeeIncome = tokenInfo.protocolFeeIncome - _amount; + + if (tokenInfo.sourceToken == address(0)) { + TokenTransferHelper.safeTransferNative(_receiver, _amount); + } else { + TokenTransferHelper.safeTransfer(tokenInfo.sourceToken, _receiver, _amount); + } + emit FeeIncomeClaimed(_tokenInfoKey, _amount, _receiver); + } + + // called by lnProvider + // this func can be called to register a new or update an exist LnProvider info + function registerLnProvider( + uint256 _remoteChainId, + address _sourceToken, + address _targetToken, + uint112 _baseFee, + uint16 _liquidityFeeRate, + uint112 _transferLimit + ) external { + bytes32 key = getTokenKey(_remoteChainId, _sourceToken, _targetToken); + TokenInfo memory tokenInfo = tokenInfos[key]; + require(tokenInfo.index > 0, "token not registered"); + bytes32 providerKey = getProviderKey(_remoteChainId, msg.sender, _sourceToken, _targetToken); + + require(_liquidityFeeRate < LIQUIDITY_FEE_RATE_BASE, "liquidity fee too large"); + + // we only update the field fee of the provider info + // if the provider has not been registered, then this line will register, otherwise update fee + SourceProviderInfo storage providerInfo = srcProviders[providerKey]; + providerInfo.baseFee = _baseFee; + providerInfo.liquidityFeeRate = _liquidityFeeRate; + providerInfo.transferLimit = _transferLimit; + + emit LnProviderUpdated(_remoteChainId, msg.sender, _sourceToken, _targetToken, _baseFee, _liquidityFeeRate, _transferLimit); + } + + function depositPenaltyReserve( + address _sourceToken, + uint256 _amount + ) external payable { + bytes32 key = getProviderStateKey(_sourceToken, msg.sender); + uint256 updatedPanaltyReserve = penaltyReserves[key] + _amount; + penaltyReserves[key] = updatedPanaltyReserve; + + if (_sourceToken == address(0)) { + require(msg.value == _amount, "invalid penaltyReserve value"); + } else { + require(msg.value == 0, "value not need"); + TokenTransferHelper.safeTransferFrom( + _sourceToken, + msg.sender, + address(this), + _amount + ); + } + emit PenaltyReserveUpdated(msg.sender, _sourceToken, updatedPanaltyReserve); + } + + function withdrawPenaltyReserve( + address _sourceToken, + uint256 _amount + ) external { + bytes32 key = getProviderStateKey(_sourceToken, msg.sender); + uint256 updatedPanaltyReserve = penaltyReserves[key] - _amount; + penaltyReserves[key] = updatedPanaltyReserve; + + if (_sourceToken == address(0)) { + TokenTransferHelper.safeTransferNative(msg.sender, _amount); + } else { + TokenTransferHelper.safeTransfer(_sourceToken, msg.sender, _amount); + } + emit PenaltyReserveUpdated(msg.sender, _sourceToken, updatedPanaltyReserve); + } + + function providerPause( + uint256 _remoteChainId, + address _sourceToken, + address _targetToken + ) external { + bytes32 providerKey = getProviderKey(_remoteChainId, msg.sender, _sourceToken, _targetToken); + srcProviders[providerKey].pause = true; + emit LnProviderPaused(msg.sender, _remoteChainId, _sourceToken, _targetToken, true); + } + + function providerUnpause( + uint256 _remoteChainId, + address _sourceToken, + address _targetToken + ) external { + bytes32 providerKey = getProviderKey(_remoteChainId, msg.sender, _sourceToken, _targetToken); + srcProviders[providerKey].pause = false; + emit LnProviderPaused(msg.sender, _remoteChainId, _sourceToken, _targetToken, false); + } + + function totalFee( + uint256 _remoteChainId, + address _provider, + address _sourceToken, + address _targetToken, + uint112 _amount + ) external view returns(uint112) { + TokenInfo memory tokenInfo = getTokenInfo(_remoteChainId, _sourceToken, _targetToken); + SourceProviderInfo memory providerInfo = getProviderInfo(_remoteChainId, _provider, _sourceToken, _targetToken); + uint256 providerFee = uint256(providerInfo.baseFee) + uint256(providerInfo.liquidityFeeRate) * uint256(_amount) / LIQUIDITY_FEE_RATE_BASE; + require(providerFee < type(uint112).max, "overflow fee"); + return uint112(providerFee) + tokenInfo.config.protocolFee; + } + + function lockAndRemoteRelease(TransferParams calldata _params) whenNotPaused external payable { + // timestamp must be close to the block time + require( + _params.timestamp >= block.timestamp - LOCK_TIME_DISTANCE && _params.timestamp <= block.timestamp + LOCK_TIME_DISTANCE, + "timestamp is too far from block time" + ); + + // check transfer info + bytes32 tokenKey = getTokenKey(_params.remoteChainId, _params.sourceToken, _params.targetToken); + TokenInfo memory tokenInfo = tokenInfos[tokenKey]; + SourceProviderInfo memory providerInfo = getProviderInfo(_params.remoteChainId, _params.provider, _params.sourceToken, _params.targetToken); + require(providerInfo.transferLimit >= _params.amount && _params.amount > 0, "invalid transfer amount"); + uint256 providerFee = uint256(providerInfo.baseFee) + uint256(providerInfo.liquidityFeeRate) * uint256(_params.amount) / LIQUIDITY_FEE_RATE_BASE; + require(providerFee < type(uint112).max, "overflow fee"); + uint112 amountWithFeeAndPenalty = _params.amount + uint112(providerFee) + tokenInfo.config.penalty; + require(_params.totalFee >= providerFee + tokenInfo.config.protocolFee, "fee not matched"); + require(!providerInfo.pause, "provider paused"); + + // update provider state + bytes32 stateKey = getProviderStateKey(_params.sourceToken, _params.provider); + uint256 penaltyReserved = penaltyReserves[stateKey]; + require(penaltyReserved >= tokenInfo.config.penalty, "penalty reserve not enough"); + penaltyReserved -= tokenInfo.config.penalty; + penaltyReserves[stateKey] = penaltyReserved; + emit PenaltyReserveUpdated(_params.provider, _params.sourceToken, penaltyReserved); + + // save lock info + uint256 remoteAmount = uint256(_params.amount) * 10**tokenInfo.config.targetDecimals / 10**tokenInfo.config.sourceDecimals; + require(remoteAmount < MAX_TRANSFER_AMOUNT && remoteAmount > 0, "overflow amount"); + bytes32 transferId = getTransferId(_params, uint112(remoteAmount)); + require(lockInfos[transferId].status == 0, "transferId exist"); + lockInfos[transferId] = LockInfo(amountWithFeeAndPenalty, tokenInfo.index, LOCK_STATUS_LOCKED); + emit TokenLocked(_params, transferId, uint112(remoteAmount), uint112(providerFee)); + + // update protocol fee income + // leave the protocol fee into contract, and admin can withdraw this fee anytime + tokenInfos[tokenKey].protocolFeeIncome = tokenInfo.protocolFeeIncome + tokenInfo.config.protocolFee; + + // transfer token + uint112 totalPayAmount = _params.amount + uint112(providerFee) + tokenInfo.config.protocolFee; + if (_params.sourceToken == address(0)) { + require(msg.value >= totalPayAmount, "value not enough"); + if (msg.value > totalPayAmount) { + // refund + TokenTransferHelper.safeTransferNative(msg.sender, msg.value - totalPayAmount); + } + } else { + require(msg.value == 0, "no value need"); + TokenTransferHelper.safeTransferFrom(_params.sourceToken, msg.sender, address(this), totalPayAmount); + } + } + + // we require the same token to withdrawn + function withdrawLiquidity( + bytes32[] calldata _transferIds, + uint256 _remoteChainId, + // provider is verified on the target chain + address _provider + ) external allowRemoteCall(_remoteChainId) { + require(_transferIds.length > 0, "invalid transferIds size"); + uint32 tokenIndex = lockInfos[_transferIds[0]].tokenIndex; + uint256 totalAmount = 0; + for (uint i = 0; i < _transferIds.length; i++) { + bytes32 transferId = _transferIds[i]; + LockInfo memory lockInfo = lockInfos[transferId]; + require(lockInfo.amountWithFeeAndPenalty > 0, "invalid transferId"); + require(lockInfo.tokenIndex == tokenIndex, "token index not matched"); + require(lockInfo.status == LOCK_STATUS_LOCKED, "token has been withdrawn"); + + totalAmount += lockInfo.amountWithFeeAndPenalty; + lockInfos[transferId].status = LOCK_STATUS_WITHDRAWN; + } + emit LiquidityWithdrawn(_transferIds, _provider, totalAmount); + bytes32 key = tokenIndexer[tokenIndex]; + TokenInfo memory tokenInfo = tokenInfos[key]; + require(tokenInfo.index == tokenIndex, "invalid token info"); + + uint256 withdrawAmount = totalAmount; + // if penalty updated, the relayer may not redeposit + if (tokenInfo.config.penalty * _transferIds.length < withdrawAmount) { + // restore the penalty reserve + uint112 redepositPenalty = tokenInfo.config.penalty * uint112(_transferIds.length); + bytes32 stateKey = getProviderStateKey(tokenInfo.sourceToken, _provider); + uint256 penaltyReserved = penaltyReserves[stateKey] + uint256(redepositPenalty); + penaltyReserves[stateKey] = penaltyReserved; + withdrawAmount -= redepositPenalty; + emit PenaltyReserveUpdated(_provider, tokenInfo.sourceToken, penaltyReserved); + } + + if (tokenInfo.sourceToken == address(0)) { + TokenTransferHelper.safeTransferNative(_provider, withdrawAmount); + } else { + TokenTransferHelper.safeTransfer(tokenInfo.sourceToken, _provider, withdrawAmount); + } + } + + function slash( + uint256 _remoteChainId, + bytes32 _transferId, + // slasher, amount and lnProvider is verified on the target chain + address _lnProvider, + address _slasher + ) external allowRemoteCall(_remoteChainId) { + LockInfo memory lockInfo = lockInfos[_transferId]; + require(lockInfo.status == LOCK_STATUS_LOCKED, "invalid lock status"); + bytes32 tokenKey = tokenIndexer[lockInfo.tokenIndex]; + TokenInfo memory tokenInfo = tokenInfos[tokenKey]; + lockInfos[_transferId].status = LOCK_STATUS_SLASHED; + + // pause this provider if slashed + bytes32 providerKey = getProviderKey(_remoteChainId, _lnProvider, tokenInfo.sourceToken, tokenInfo.targetToken); + srcProviders[providerKey].pause = true; + emit LnProviderPaused(_lnProvider, _remoteChainId, tokenInfo.sourceToken, tokenInfo.targetToken, true); + + // transfer token to slasher + if (tokenInfo.sourceToken == address(0)) { + TokenTransferHelper.safeTransferNative(_slasher, lockInfo.amountWithFeeAndPenalty); + } else { + TokenTransferHelper.safeTransfer(tokenInfo.sourceToken, _slasher, lockInfo.amountWithFeeAndPenalty); + } + emit TransferSlashed(_transferId, _lnProvider, _slasher, lockInfo.amountWithFeeAndPenalty); + } + + function getProviderKey(uint256 _remoteChainId, address _provider, address _sourceToken, address _targetToken) pure public returns(bytes32) { + return keccak256(abi.encodePacked(_remoteChainId, _provider, _sourceToken, _targetToken)); + } + + function getTokenKey(uint256 _remoteChainId, address _sourceToken, address _targetToken) pure public returns(bytes32) { + return keccak256(abi.encodePacked(_remoteChainId, _sourceToken, _targetToken)); + } + + function getProviderStateKey(address _sourceToken, address provider) pure public returns(bytes32) { + return keccak256(abi.encodePacked(_sourceToken, provider)); + } + + function getTransferId( + TransferParams memory _params, + uint112 _remoteAmount + ) public view returns(bytes32) { + return keccak256(abi.encodePacked( + block.chainid, + _params.remoteChainId, + _params.provider, + _params.sourceToken, + _params.targetToken, + _params.receiver, + _params.amount, + _remoteAmount, + _params.timestamp + )); + } + + function getTokenInfo(uint256 _remoteChainId, address _sourceToken, address _targetToken) view internal returns(TokenInfo memory) { + bytes32 key = keccak256(abi.encodePacked(_remoteChainId, _sourceToken, _targetToken)); + return tokenInfos[key]; + } + + function getProviderInfo( + uint256 _remoteChainId, + address _provider, + address _sourceToken, + address _targetToken + ) view internal returns(SourceProviderInfo memory) { + bytes32 key = keccak256(abi.encodePacked(_remoteChainId, _provider, _sourceToken, _targetToken)); + return srcProviders[key]; + } +} + +// File @zeppelin-solidity/contracts/utils/Address.sol@v4.7.3 +// License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.7.0) (utils/Address.sol) + + +/** + * @dev Collection of functions related to the address type + */ +library Address { + /** + * @dev Returns true if `account` is a contract. + * + * [IMPORTANT] + * ==== + * It is unsafe to assume that an address for which this function returns + * false is an externally-owned account (EOA) and not a contract. + * + * Among others, `isContract` will return false for the following + * types of addresses: + * + * - an externally-owned account + * - a contract in construction + * - an address where a contract will be created + * - an address where a contract lived, but was destroyed + * ==== + * + * [IMPORTANT] + * ==== + * You shouldn't rely on `isContract` to protect against flash loan attacks! + * + * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets + * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract + * constructor. + * ==== + */ + function isContract(address account) internal view returns (bool) { + // This method relies on extcodesize/address.code.length, which returns 0 + // for contracts in construction, since the code is only stored at the end + // of the constructor execution. + + return account.code.length > 0; + } + + /** + * @dev Replacement for Solidity's `transfer`: sends `amount` wei to + * `recipient`, forwarding all available gas and reverting on errors. + * + * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost + * of certain opcodes, possibly making contracts go over the 2300 gas limit + * imposed by `transfer`, making them unable to receive funds via + * `transfer`. {sendValue} removes this limitation. + * + * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. + * + * IMPORTANT: because control is transferred to `recipient`, care must be + * taken to not create reentrancy vulnerabilities. Consider using + * {ReentrancyGuard} or the + * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. + */ + function sendValue(address payable recipient, uint256 amount) internal { + require(address(this).balance >= amount, "Address: insufficient balance"); + + (bool success, ) = recipient.call{value: amount}(""); + require(success, "Address: unable to send value, recipient may have reverted"); + } + + /** + * @dev Performs a Solidity function call using a low level `call`. A + * plain `call` is an unsafe replacement for a function call: use this + * function instead. + * + * If `target` reverts with a revert reason, it is bubbled up by this + * function (like regular Solidity function calls). + * + * Returns the raw returned data. To convert to the expected return value, + * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. + * + * Requirements: + * + * - `target` must be a contract. + * - calling `target` with `data` must not revert. + * + * _Available since v3.1._ + */ + function functionCall(address target, bytes memory data) internal returns (bytes memory) { + return functionCall(target, data, "Address: low-level call failed"); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with + * `errorMessage` as a fallback revert reason when `target` reverts. + * + * _Available since v3.1._ + */ + function functionCall( + address target, + bytes memory data, + string memory errorMessage + ) internal returns (bytes memory) { + return functionCallWithValue(target, data, 0, errorMessage); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but also transferring `value` wei to `target`. + * + * Requirements: + * + * - the calling contract must have an ETH balance of at least `value`. + * - the called Solidity function must be `payable`. + * + * _Available since v3.1._ + */ + function functionCallWithValue( + address target, + bytes memory data, + uint256 value + ) internal returns (bytes memory) { + return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); + } + + /** + * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but + * with `errorMessage` as a fallback revert reason when `target` reverts. + * + * _Available since v3.1._ + */ + function functionCallWithValue( + address target, + bytes memory data, + uint256 value, + string memory errorMessage + ) internal returns (bytes memory) { + require(address(this).balance >= value, "Address: insufficient balance for call"); + require(isContract(target), "Address: call to non-contract"); + + (bool success, bytes memory returndata) = target.call{value: value}(data); + return verifyCallResult(success, returndata, errorMessage); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but performing a static call. + * + * _Available since v3.3._ + */ + function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { + return functionStaticCall(target, data, "Address: low-level static call failed"); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], + * but performing a static call. + * + * _Available since v3.3._ + */ + function functionStaticCall( + address target, + bytes memory data, + string memory errorMessage + ) internal view returns (bytes memory) { + require(isContract(target), "Address: static call to non-contract"); + + (bool success, bytes memory returndata) = target.staticcall(data); + return verifyCallResult(success, returndata, errorMessage); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but performing a delegate call. + * + * _Available since v3.4._ + */ + function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { + return functionDelegateCall(target, data, "Address: low-level delegate call failed"); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], + * but performing a delegate call. + * + * _Available since v3.4._ + */ + function functionDelegateCall( + address target, + bytes memory data, + string memory errorMessage + ) internal returns (bytes memory) { + require(isContract(target), "Address: delegate call to non-contract"); + + (bool success, bytes memory returndata) = target.delegatecall(data); + return verifyCallResult(success, returndata, errorMessage); + } + + /** + * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the + * revert reason using the provided one. + * + * _Available since v4.3._ + */ + function verifyCallResult( + bool success, + bytes memory returndata, + string memory errorMessage + ) internal pure returns (bytes memory) { + if (success) { + return returndata; + } else { + // Look for revert reason and bubble it up if present + if (returndata.length > 0) { + // The easiest way to bubble the revert reason is using memory via assembly + /// @solidity memory-safe-assembly + assembly { + let returndata_size := mload(returndata) + revert(add(32, returndata), returndata_size) + } + } else { + revert(errorMessage); + } + } + } +} + +// File @zeppelin-solidity/contracts/proxy/utils/Initializable.sol@v4.7.3 +// License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.7.0) (proxy/utils/Initializable.sol) + + +/** + * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed + * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an + * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer + * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect. + * + * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be + * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in + * case an upgrade adds a module that needs to be initialized. + * + * For example: + * + * [.hljs-theme-light.nopadding] + * ``` + * contract MyToken is ERC20Upgradeable { + * function initialize() initializer public { + * __ERC20_init("MyToken", "MTK"); + * } + * } + * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable { + * function initializeV2() reinitializer(2) public { + * __ERC20Permit_init("MyToken"); + * } + * } + * ``` + * + * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as + * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}. + * + * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure + * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity. + * + * [CAUTION] + * ==== + * Avoid leaving a contract uninitialized. + * + * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation + * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke + * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed: + * + * [.hljs-theme-light.nopadding] + * ``` + * /// @custom:oz-upgrades-unsafe-allow constructor + * constructor() { + * _disableInitializers(); + * } + * ``` + * ==== + */ +abstract contract Initializable { + /** + * @dev Indicates that the contract has been initialized. + * @custom:oz-retyped-from bool + */ + uint8 private _initialized; + + /** + * @dev Indicates that the contract is in the process of being initialized. + */ + bool private _initializing; + + /** + * @dev Triggered when the contract has been initialized or reinitialized. + */ + event Initialized(uint8 version); + + /** + * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope, + * `onlyInitializing` functions can be used to initialize parent contracts. Equivalent to `reinitializer(1)`. + */ + modifier initializer() { + bool isTopLevelCall = !_initializing; + require( + (isTopLevelCall && _initialized < 1) || (!Address.isContract(address(this)) && _initialized == 1), + "Initializable: contract is already initialized" + ); + _initialized = 1; + if (isTopLevelCall) { + _initializing = true; + } + _; + if (isTopLevelCall) { + _initializing = false; + emit Initialized(1); + } + } + + /** + * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the + * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be + * used to initialize parent contracts. + * + * `initializer` is equivalent to `reinitializer(1)`, so a reinitializer may be used after the original + * initialization step. This is essential to configure modules that are added through upgrades and that require + * initialization. + * + * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in + * a contract, executing them in the right order is up to the developer or operator. + */ + modifier reinitializer(uint8 version) { + require(!_initializing && _initialized < version, "Initializable: contract is already initialized"); + _initialized = version; + _initializing = true; + _; + _initializing = false; + emit Initialized(version); + } + + /** + * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the + * {initializer} and {reinitializer} modifiers, directly or indirectly. + */ + modifier onlyInitializing() { + require(_initializing, "Initializable: contract is not initializing"); + _; + } + + /** + * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call. + * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized + * to any version. It is recommended to use this to lock implementation contracts that are designed to be called + * through proxies. + */ + function _disableInitializers() internal virtual { + require(!_initializing, "Initializable: contract is initializing"); + if (_initialized < type(uint8).max) { + _initialized = type(uint8).max; + emit Initialized(type(uint8).max); + } + } +} + +// File contracts/ln/HelixLnBridgeV3.sol +// License-Identifier: MIT + + + + +contract HelixLnBridgeV3 is Initializable, LnBridgeSourceV3, LnBridgeTargetV3 { + struct MessagerService { + address sendService; + address receiveService; + } + + // remoteChainId => messager + mapping(uint256=>MessagerService) public messagers; + + receive() external payable {} + + function initialize(address dao) public initializer { + _initialize(dao); + } + + // the remote endpoint is unique, if we want multi-path to remote endpoint, then the messager should support multi-path + function setSendService(uint256 _remoteChainId, address _remoteBridge, address _service) external onlyDao { + messagers[_remoteChainId].sendService = _service; + ILowLevelMessageSender(_service).registerRemoteReceiver(_remoteChainId, _remoteBridge); + } + + function setReceiveService(uint256 _remoteChainId, address _remoteBridge, address _service) external onlyDao { + messagers[_remoteChainId].receiveService = _service; + ILowLevelMessageReceiver(_service).registerRemoteSender(_remoteChainId, _remoteBridge); + } + + function _sendMessageToSource(uint256 _remoteChainId, bytes memory _payload, uint256 feePrepaid, bytes memory _extParams) whenNotPaused internal override { + address sendService = messagers[_remoteChainId].sendService; + require(sendService != address(0), "invalid messager"); + ILowLevelMessageSender(sendService).sendMessage{value: feePrepaid}(_remoteChainId, _payload, _extParams); + } + + function _verifyRemote(uint256 _remoteChainId) whenNotPaused internal view override { + address receiveService = messagers[_remoteChainId].receiveService; + require(receiveService == msg.sender, "invalid messager"); + } +} \ No newline at end of file diff --git a/helix-contract/test/3_test_ln_opposite.js b/helix-contract/test/3_test_ln_opposite.js index 1471d939..921e638d 100644 --- a/helix-contract/test/3_test_ln_opposite.js +++ b/helix-contract/test/3_test_ln_opposite.js @@ -340,6 +340,7 @@ describe("eth->arb lnv2 positive bridge tests", () => { chainInfo.srcChainId, expectedTransferId, chainInfo.extParams, + { value: ethers.utils.parseEther("0.01") } ); const slashInfo = await chainInfo.dstBridge.slashInfos(expectedTransferId); const balanceOfUserAfter = await chainInfo.dstToken.balanceOf(user.address); @@ -372,6 +373,7 @@ describe("eth->arb lnv2 positive bridge tests", () => { chainInfo.dstToken.address, amount, chainInfo.extParams, + { value: ethers.utils.parseEther("0.01") } ); const balanceOfRelayerAfter = await chainInfo.srcToken.balanceOf(relayer.address); const marginAfter = (await chainInfo.srcBridge.srcProviders(providerKey)).config.margin; @@ -555,6 +557,8 @@ describe("eth->arb lnv2 positive bridge tests", () => { await expect(withdraw('arb2eth', transferId03, 15000)).to.be.revertedWith("arbitrum mock call failed"); expect(await withdraw('arb2eth', transferId03, 5000)).to.equal(true); console.log("ln bridge test finished"); + + // !warning there is a bug for lnv2 to slash a native token cross transfer with opposite bridge } }); }); diff --git a/helix-contract/test/5_test_ln_v3.js b/helix-contract/test/5_test_ln_v3.js new file mode 100644 index 00000000..089011bd --- /dev/null +++ b/helix-contract/test/5_test_ln_v3.js @@ -0,0 +1,561 @@ +const { expect } = require("chai"); +const { solidity } = require("ethereum-waffle"); +const chai = require("chai"); +const ethUtil = require('ethereumjs-util'); +const abi = require('ethereumjs-abi'); +const secp256k1 = require('secp256k1'); + +chai.use(solidity); + +async function getBlockTimestamp() { + const blockNumber = await ethers.provider.getBlockNumber(); + const block = await ethers.provider.getBlock(blockNumber); + return block.timestamp; +} + +describe("lnv3 bridge tests", () => { + before(async () => { + }); + + it("test_lnv3_flow", async function () { + const [owner, relayer, user, slasher] = await ethers.getSigners(); + const dao = owner.address; + const protocolFee = 100; + const penalty = 200; + const nullAddress = "0x0000000000000000000000000000000000000000"; + const nativeTokenAddress = nullAddress; + const baseFee = 300; + const liquidityFeeRate = 1; + const initTokenBalance = 1000000; + const initPenalty = 10000; + const transferAmount = 3000; + const ethChainId = 31337; + const arbChainId = 31337; + const transferLimit = 10000; + + // deploy erc20 token contract + const tokenNameOnEthereum = "Darwinia Ring On Ethereum"; + const tokenSymbolOnEthereum = "RING.e"; + const ethContract = await ethers.getContractFactory("Erc20"); + const ethToken = await ethContract.deploy(tokenNameOnEthereum, tokenSymbolOnEthereum, 18); + await ethToken.deployed(); + + const tokenNameOnArbitrum = "Darwinia Ring On Arbitrum"; + const tokenSymbolOnArbitrum = "RING.a"; + const arbContract = await ethers.getContractFactory("Erc20"); + const arbToken = await ethContract.deploy(tokenNameOnArbitrum, tokenSymbolOnArbitrum, 17); + await arbToken.deployed(); + console.log("contract deploy erc20 finished"); + + const tokenNameNativeOnEthereum = "Ethereum Native Token"; + const tokenSymbolNativeOnEthereum = "ETH"; + const tokenNameNativeOnArbitrum = "Arbitrum Native Token"; + const tokenSymbolNativeOnArbitrum = "aETH"; + + // mint some tokens on source chain and target chain for relayer + await ethToken.mint(relayer.address, initTokenBalance); + await arbToken.mint(relayer.address, initTokenBalance); + await ethToken.mint(user.address, initTokenBalance); + await arbToken.mint(user.address, initTokenBalance); + await ethToken.mint(owner.address, initTokenBalance); + await arbToken.mint(owner.address, initTokenBalance); + await ethToken.mint(slasher.address, initTokenBalance); + await arbToken.mint(slasher.address, initTokenBalance); + + // deploy inboundLane + const inboxContract = await ethers.getContractFactory("MockArbitrumInbox"); + const inbox = await inboxContract.deploy(); + await inbox.deployed(); + console.log("deploy mock inbox success"); + //******* deploy inboundLane/outboundLane finished ******** + + + const bridgeContract = await ethers.getContractFactory("HelixLnBridgeV3"); + + const ethBridge = await bridgeContract.deploy(); + await ethBridge.deployed(); + await ethBridge.initialize(dao); + const arbBridge = await bridgeContract.deploy(); + await arbBridge.deployed(); + await arbBridge.initialize(dao); + + // eth -> arb messager service + console.log("deploy etherum to arbitrum l1->l2 message service"); + const eth2arbSendServiceContract = await ethers.getContractFactory("Eth2ArbSendService"); + const eth2arbSendService = await eth2arbSendServiceContract.deploy(dao, inbox.address, arbChainId); + await eth2arbSendService.deployed(); + const eth2arbRecvServiceContract = await ethers.getContractFactory("MockEth2ArbReceiveService"); + const eth2arbRecvService = await eth2arbRecvServiceContract.deploy(dao, ethChainId); + await eth2arbRecvService.deployed(); + + await eth2arbSendService.setRemoteMessager(eth2arbRecvService.address); + await eth2arbRecvService.setRemoteMessagerAlias(inbox.address); + + // arb -> eth message service + console.log("deploy arbitrum to ethereum layerzero message service"); + const endpointContract = await ethers.getContractFactory("LayerZeroEndpointMock"); + const endpoint = await endpointContract.deploy(arbChainId); + await endpoint.deployed(); + console.log("deploy mock endpoint success"); + //******* deploy endpoint finished ******** + + // deploy layerzero messager + const lzMessagerContract = await ethers.getContractFactory("LayerZeroMessager"); + const lzMessagerEth = await lzMessagerContract.deploy(dao, endpoint.address); + await lzMessagerEth.deployed(); + const lzMessagerArb = await lzMessagerContract.deploy(dao, endpoint.address); + await lzMessagerArb.deployed(); + + await lzMessagerEth.setRemoteMessager(arbChainId, arbChainId, lzMessagerArb.address); + await lzMessagerArb.setRemoteMessager(ethChainId, ethChainId, lzMessagerEth.address); + console.log("messager service deploy finished"); + + console.log("configure message service for token bridge"); + // authorise + await eth2arbSendService.authoriseAppCaller(ethBridge.address, true); + await eth2arbRecvService.authoriseAppCaller(arbBridge.address, true); + await lzMessagerEth.authoriseAppCaller(ethBridge.address, true); + await lzMessagerArb.authoriseAppCaller(arbBridge.address, true); + + await ethBridge.setSendService(arbChainId, arbBridge.address, eth2arbSendService.address); + await ethBridge.setReceiveService(arbChainId, arbBridge.address, lzMessagerEth.address); + await arbBridge.setSendService(ethChainId, ethBridge.address, lzMessagerArb.address); + await arbBridge.setReceiveService(ethChainId, ethBridge.address, eth2arbRecvService.address); + + // configure + // register token + console.log("register token info"); + await ethBridge.registerTokenInfo( + arbChainId, + ethToken.address, + arbToken.address, + protocolFee, + penalty, + 18, + 17, + 1 // index + ); + await arbBridge.registerTokenInfo( + ethChainId, + arbToken.address, + ethToken.address, + protocolFee, + penalty, + 17, + 18, + 1 + ); + + // native token + await ethBridge.registerTokenInfo( + arbChainId, + nativeTokenAddress, + nativeTokenAddress, + protocolFee, + penalty, + 18, + 18, + 2 + ); + + await arbBridge.registerTokenInfo( + ethChainId, + nativeTokenAddress, + nativeTokenAddress, + protocolFee, + penalty, + 18, + 18, + 2 + ); + + console.log("provider register"); + // provider + await ethToken.connect(relayer).approve(ethBridge.address, initTokenBalance); + await arbToken.connect(relayer).approve(arbBridge.address, initTokenBalance); + // register on source chain + // register + await arbBridge.connect(relayer).registerLnProvider( + ethChainId, + arbToken.address, + ethToken.address, + baseFee, + liquidityFeeRate, + transferLimit + ); + // deposit penalty reserve + await arbBridge.connect(relayer).depositPenaltyReserve( + arbToken.address, + initPenalty + ); + + const tx = await ethBridge.connect(relayer).registerLnProvider( + arbChainId, + ethToken.address, + arbToken.address, + baseFee, + liquidityFeeRate, + transferLimit + ); + let lockReceipt = await tx.wait(); + let lockGasUsed = lockReceipt.cumulativeGasUsed; + console.log("register lnProvider usedGas", lockGasUsed); + // deposit penalty reserve + await ethBridge.connect(relayer).depositPenaltyReserve( + ethToken.address, + initPenalty + ); + + await arbBridge.connect(relayer).registerLnProvider( + ethChainId, + nativeTokenAddress, + nativeTokenAddress, + baseFee, + liquidityFeeRate, + transferLimit + ); + // deposit penalty reserve + await arbBridge.connect(relayer).depositPenaltyReserve( + nativeTokenAddress, + initPenalty, + { value: initPenalty } + ); + + await ethBridge.connect(relayer).registerLnProvider( + arbChainId, + nativeTokenAddress, + nativeTokenAddress, + baseFee, + liquidityFeeRate, + transferLimit + ); + // deposit penalty reserve + await ethBridge.connect(relayer).depositPenaltyReserve( + nativeTokenAddress, + initPenalty, + { value: initPenalty } + ); + + async function getChainInfo(direction, isNative) { + if (direction === 'eth2arb') { + let srcToken = ethToken.address; + let dstToken = arbToken.address; + if (isNative) { + srcToken = nativeTokenAddress; + dstToken = nativeTokenAddress; + } + return { + srcChainId: ethChainId, + dstChainId: arbChainId, + srcToken: srcToken, + dstToken: dstToken, + srcBridge: ethBridge, + dstBridge: arbBridge, + extParams: relayer.address, + }; + } else { + let srcToken = arbToken.address; + let dstToken = ethToken.address; + if (isNative) { + srcToken = nativeTokenAddress; + dstToken = nativeTokenAddress; + } + return { + srcChainId: arbChainId, + dstChainId: ethChainId, + srcToken: srcToken, + dstToken: dstToken, + srcBridge: arbBridge, + dstBridge: ethBridge, + extParams: await eth2arbSendService.encodeParams(0, 200, 200, relayer.address), + }; + } + } + + async function getTargetAmount(direction, sourceAmount, isNative) { + if (isNative) { + return sourceAmount; + } + if (direction === 'eth2arb') { + return sourceAmount/(10); + } else { + return sourceAmount * 10; + } + } + + async function balanceOf(tokenAddress, account) { + if (tokenAddress == nativeTokenAddress) { + return await ethers.provider.getBalance(account); + } else { + const token = await ethers.getContractAt("Erc20", tokenAddress); + return await token.balanceOf(account); + } + } + + // balance + // srcChain: user -> source bridge contract [amount + providerFee + protocolFee] + async function transfer(direction, timestamp, isNative) { + const chainInfo = await getChainInfo(direction, isNative); + const totalFee = Number(await chainInfo.srcBridge.totalFee( + chainInfo.dstChainId, + relayer.address, + chainInfo.srcToken, + chainInfo.dstToken, + transferAmount + )); + const balanceOfUser = await balanceOf(chainInfo.srcToken, user.address); + const balanceOfBackingBefore = await balanceOf(chainInfo.srcToken, chainInfo.srcBridge.address); + const params = [ + chainInfo.dstChainId, + relayer.address, + chainInfo.srcToken, + chainInfo.dstToken, + totalFee, + transferAmount, + user.address, + timestamp, + ]; + let value = 0; + if (isNative) { + value = totalFee + transferAmount; + } + const tx = await chainInfo.srcBridge.connect(user).lockAndRemoteRelease( + params, + { value: value } + ); + const balanceOfUserAfter = await balanceOf(chainInfo.srcToken, user.address); + const balanceOfBackingAfter = await balanceOf(chainInfo.srcToken, chainInfo.srcBridge.address); + let lockReceipt = await tx.wait(); + let lockGasUsed = lockReceipt.cumulativeGasUsed; + let gasFee = lockReceipt.cumulativeGasUsed.mul(lockReceipt.effectiveGasPrice); + console.log("transferAndLockMargin gas used", lockGasUsed, lockReceipt.effectiveGasPrice, gasFee); + if (!isNative) { + expect(balanceOfUser.sub(balanceOfUserAfter)).to.equal(totalFee + transferAmount); + } else { + expect(balanceOfUser.sub(balanceOfUserAfter).sub(gasFee)).to.equal(totalFee + transferAmount); + } + expect(balanceOfBackingAfter - balanceOfBackingBefore).to.equal(totalFee + transferAmount); + const targetAmount = await getTargetAmount(direction, transferAmount, isNative); + return await chainInfo.srcBridge.getTransferId( + params, + targetAmount + ); + } + + // balance + // on target: relayer -> user + async function relay(direction, transferId, timestamp, isNative) { + const chainInfo = await getChainInfo(direction, isNative); + const balanceOfUser = await balanceOf(chainInfo.dstToken, user.address); + const balanceOfRelayer = await balanceOf(chainInfo.dstToken, relayer.address); + const targetAmount = await getTargetAmount(direction, transferAmount, isNative); + let value = 0; + if (isNative) { + value = targetAmount; + } + const relayTransaction = await chainInfo.dstBridge.connect(relayer).relay( + [ + chainInfo.srcChainId, + relayer.address, // provider + chainInfo.srcToken, // sourceToken + chainInfo.dstToken, // targetToken + transferAmount, + targetAmount, + user.address, + timestamp, + ], + transferId, + true, + { value: value } + ); + + // check relay result + //const fillInfo = await chainInfo.dstBridge.fillTransfers(transferId); + //expect(fillInfo.timestamp).to.equal(relayTimestamp); + const slashInfo = await chainInfo.dstBridge.slashInfos(transferId); + expect(slashInfo.slasher).to.equal(nullAddress); + const balanceOfUserAfter = await balanceOf(chainInfo.dstToken, user.address); + const balanceOfRelayerAfter = await balanceOf(chainInfo.dstToken, relayer.address); + expect(balanceOfUserAfter.sub(balanceOfUser)).to.equal(targetAmount); + + let relayReceipt = await relayTransaction.wait(); + let relayGasUsed = relayReceipt.cumulativeGasUsed; + let gasFee = relayReceipt.cumulativeGasUsed.mul(relayReceipt.effectiveGasPrice); + if (!isNative) { + expect(balanceOfRelayer - balanceOfRelayerAfter).to.equal(targetAmount); + } else { + expect(balanceOfRelayer.sub(balanceOfRelayerAfter).sub(gasFee)).to.equal(targetAmount); + } + + console.log("relay gas used", relayGasUsed); + } + + async function slash(direction, expectedTransferId, timestamp, isNative) { + const chainInfo = await getChainInfo(direction, isNative); + const dstToken = await ethers.getContractAt("Erc20", chainInfo.dstToken); + await dstToken.connect(slasher).approve(chainInfo.dstBridge.address, initTokenBalance); + + const balanceOfUser = await balanceOf(chainInfo.dstToken, user.address); + const balanceOfSlasher = await balanceOf(chainInfo.dstToken, slasher.address); + const balanceOfSlasherOnSrc = await balanceOf(chainInfo.srcToken, slasher.address); + const targetAmount = await getTargetAmount(direction, transferAmount, isNative); + + const feePrepaid = ethers.utils.parseEther("0.01"); + let value = feePrepaid; + if (isNative) { + value = feePrepaid.add(targetAmount); + } + + const slashTransaction = await chainInfo.dstBridge.connect(slasher).requestSlashAndRemoteRelease( + [ + chainInfo.srcChainId, + relayer.address, + chainInfo.srcToken, + chainInfo.dstToken, + transferAmount, + targetAmount, + user.address, + timestamp, + ], + expectedTransferId, + feePrepaid, + chainInfo.extParams, + {value: value} + ); + + let slashReceipt = await slashTransaction.wait(); + let slashGasUsed = slashReceipt.cumulativeGasUsed; + let gasFee = slashReceipt.cumulativeGasUsed.mul(slashReceipt.effectiveGasPrice); + + const slashInfo = await chainInfo.dstBridge.slashInfos(expectedTransferId); + const balanceOfUserAfter = await balanceOf(chainInfo.dstToken, user.address); + const balanceOfSlasherAfter = await balanceOf(chainInfo.dstToken, slasher.address); + const balanceOfSlasherAfterOnSrc = await balanceOf(chainInfo.srcToken, slasher.address); + const totalFee = Number(await chainInfo.srcBridge.totalFee( + chainInfo.dstChainId, + relayer.address, + chainInfo.srcToken, + chainInfo.dstToken, + transferAmount + )); + expect(balanceOfUserAfter.sub(balanceOfUser)).to.equal(targetAmount); + if (!isNative) { + expect(balanceOfSlasher - balanceOfSlasherAfter).to.equal(targetAmount); + expect(balanceOfSlasherAfterOnSrc - balanceOfSlasherOnSrc).to.equal(transferAmount + penalty + totalFee - protocolFee); + } else { + expect(balanceOfSlasherAfter.sub(balanceOfSlasher).add(feePrepaid).add(gasFee)).to.equal(penalty + totalFee - protocolFee); + } + expect(slashInfo.slasher).to.equal(slasher.address); + return slashTransaction; + } + + async function withdraw(direction, transferIds, result, isNative) { + const chainInfo = await getChainInfo(direction, isNative); + + let totalWithdrawAmount = 0; + for (const transferId of transferIds) { + const lockInfo = await chainInfo.srcBridge.lockInfos(transferId); + totalWithdrawAmount += Number(lockInfo.amountWithFeeAndPenalty) - penalty; + } + + const balanceOfRelayerBefore = await balanceOf(chainInfo.srcToken, relayer.address); + const balanceOfBackingBefore = await balanceOf(chainInfo.srcToken, chainInfo.srcBridge.address); + const feePrepaid = ethers.utils.parseEther("0.01"); + const withdrawTransaction = await chainInfo.dstBridge.connect(relayer).requestWithdrawLiquidity( + chainInfo.srcChainId, + transferIds, + relayer.address, + chainInfo.extParams, + {value: feePrepaid} + ); + const balanceOfRelayerAfter = await balanceOf(chainInfo.srcToken, relayer.address); + const balanceOfBackingAfter = await balanceOf(chainInfo.srcToken, chainInfo.srcBridge.address); + + if (result) { + expect(balanceOfRelayerAfter - balanceOfRelayerBefore).to.equal(totalWithdrawAmount); + expect(balanceOfBackingBefore - balanceOfBackingAfter).to.equal(totalWithdrawAmount); + } else { + expect(balanceOfRelayerAfter - balanceOfRelayerBefore).to.equal(0); + expect(balanceOfBackingBefore - balanceOfBackingAfter).to.equal(0); + } + } + + // eth -> arb + { + await ethToken.connect(user).approve(ethBridge.address, initTokenBalance); + // test normal transfer and relay + // 1. transfer from eth to arb + let timestamp = (await ethers.provider.getBlock("latest")).timestamp; + const transferId01 = await transfer('eth2arb', timestamp, false); + const blockTimestamp01 = (await ethers.provider.getBlock("latest")).timestamp; + // 2. relay "transfer from eth to arb" + await relay('eth2arb', transferId01, timestamp, false); + // 3. repeat relay + await expect(relay('eth2arb', transferId01, timestamp, false)).to.be.revertedWith("transfer has been filled"); + + // test slash + // 1. slash a relayed tx + await expect(slash("eth2arb", transferId01, timestamp, false)).to.be.revertedWith("transfer has been filled"); + // 2. slash a normal unrelayed tx + const transferId02 = await transfer('eth2arb', blockTimestamp01, false); + const blockTimestamp02 = (await ethers.provider.getBlock("latest")).timestamp; + // 2.1. slash when not expired + await expect(slash("eth2arb", transferId02, blockTimestamp01, false)).to.be.revertedWith("time not expired"); + await hre.network.provider.request({ + method: "evm_increaseTime", + params: [3601], + }); + // 2.2. slashed + await slash("eth2arb", transferId02, blockTimestamp01, false); + + // withdraw + await withdraw('eth2arb', [transferId01], true, false); + // withdraw twice failed + await withdraw('eth2arb', [transferId01], false, false); + // withdraw a slashed transfer failed + await withdraw('eth2arb', [transferId02], false, false); + console.log("eth2arb test finished"); + } + + // test arb2eth direction + { + let timestamp = (await ethers.provider.getBlock("latest")).timestamp; + await arbToken.connect(user).approve(arbBridge.address, initTokenBalance); + const transferId11 = await transfer('arb2eth', timestamp, false); + const blockTimestamp11 = (await ethers.provider.getBlock("latest")).timestamp; + await relay('arb2eth', transferId11, timestamp, false); + await expect(relay('arb2eth', transferId11, timestamp, false)).to.be.revertedWith("transfer has been filled"); + + await expect(slash("arb2eth", transferId11, timestamp, false)).to.be.revertedWith("transfer has been filled"); + const transferId12 = await transfer('arb2eth', blockTimestamp11, false); + const blockTimestamp12 = (await ethers.provider.getBlock("latest")).timestamp; + await expect(slash("arb2eth", transferId12, blockTimestamp11, false)).to.be.revertedWith("time not expired"); + await hre.network.provider.request({ + method: "evm_increaseTime", + params: [3601], + }); + await slash("arb2eth", transferId12, blockTimestamp11, false); + console.log("arb2eth test finished"); + } + + // test native token + { + let timestamp = (await ethers.provider.getBlock("latest")).timestamp; + const transferId21 = await transfer('arb2eth', timestamp, true); + const blockTimestamp21 = (await ethers.provider.getBlock("latest")).timestamp; + await relay('arb2eth', transferId21, timestamp, true); + await expect(relay('arb2eth', transferId21, timestamp, true)).to.be.revertedWith("transfer has been filled"); + + await expect(slash("arb2eth", transferId21, timestamp, true)).to.be.revertedWith("transfer has been filled"); + const transferId22 = await transfer('arb2eth', blockTimestamp21, true); + const blockTimestamp22 = (await ethers.provider.getBlock("latest")).timestamp; + await expect(slash("arb2eth", transferId22, blockTimestamp21, true)).to.be.revertedWith("time not expired"); + await hre.network.provider.request({ + method: "evm_increaseTime", + params: [3601], + }); + await slash("arb2eth", transferId22, blockTimestamp21, true); + console.log("test finished"); + } + }); +}); diff --git a/zksync-deployer/copy_zksync_contract.sh b/zksync-deployer/copy_zksync_contract.sh index 8f2aa335..a642195c 100644 --- a/zksync-deployer/copy_zksync_contract.sh +++ b/zksync-deployer/copy_zksync_contract.sh @@ -11,4 +11,7 @@ cp -r ../helix-contract/contracts/ln/messager/interface ./contracts/ln/messager/ cp -r ../helix-contract/contracts/ln/messager/LayerZeroMessager.sol ./contracts/ln/messager/ cp -r ../helix-contract/contracts/ln/LnDefaultBridge.sol ./contracts/ln/ cp -r ../helix-contract/contracts/ln/LnOppositeBridge.sol ./contracts/ln/ +cp -r ../helix-contract/contracts/ln/HelixLnBridgeV3.sol ./contracts/ln/ +cp -r ../helix-contract/contracts/utils ./contracts/ +cp -r ../helix-contract/contracts/interfaces ./contracts/ cp -r ../helix-contract/contracts/ln/test/TestToken.sol ./contracts/ln/test/ diff --git a/zksync-deployer/deploy/deploy_ln_layerzero.ts b/zksync-deployer/deploy/deploy_ln_layerzero.ts index 3a3061b0..d1fea702 100644 --- a/zksync-deployer/deploy/deploy_ln_layerzero.ts +++ b/zksync-deployer/deploy/deploy_ln_layerzero.ts @@ -1,17 +1,19 @@ -import { Wallet } from "zksync-web3"; +import { Wallet } from "zksync-ethers"; import * as ethers from "ethers"; import { HardhatRuntimeEnvironment } from "hardhat/types"; import { Deployer } from "@matterlabs/hardhat-zksync-deploy"; const privateKey = process.env.PRIKEY const dao = "0x88a39B052d477CfdE47600a7C9950a441Ce61cb4"; -const endpoint = "0x093D2CF57f764f09C3c2Ac58a42A2601B8C79281"; +const endpoint = "0x9b896c0e23220469C7AE69cb4BbAE391eAa4C8da"; export default async function (hre: HardhatRuntimeEnvironment) { // deploy proxy admin contract console.log(`Running deploy script for the zksync layerzero contract`); // Initialize the wallet. + //const provider = Provider.getDefaultProvider(types.Network.Sepolia); + //const ethProvider = ethers.getDefaultProvider("sepolia"); const wallet = new Wallet(privateKey); // Create deployer object and load the artifact of the contract you want to deploy. @@ -19,7 +21,7 @@ export default async function (hre: HardhatRuntimeEnvironment) { // deploy create2 tool contract const artifact = await deployer.loadArtifact("LayerZeroMessager"); const contract = await deployer.deploy(artifact, [dao, endpoint]); - const contractAddress = contract.address; + const contractAddress = contract.target; console.log(`layerzero contract was deployed to ${contractAddress}`); const verificationId = await hre.run("verify:verify", { address: contractAddress, diff --git a/zksync-deployer/deploy/deploy_ln_test_token.ts b/zksync-deployer/deploy/deploy_ln_test_token.ts index b4faff5b..60374a96 100644 --- a/zksync-deployer/deploy/deploy_ln_test_token.ts +++ b/zksync-deployer/deploy/deploy_ln_test_token.ts @@ -1,4 +1,4 @@ -import { Wallet } from "zksync-web3"; +import { Wallet } from "zksync-ethers"; import * as ethers from "ethers"; import { HardhatRuntimeEnvironment } from "hardhat/types"; import { Deployer } from "@matterlabs/hardhat-zksync-deploy"; @@ -9,12 +9,12 @@ const tokens = [ { name: "Helix Test Token USDT", symbol: "USDT", - decimals: 18 + decimals: 6 }, { name: "Helix Test Token USDC", symbol: "USDC", - decimals: 18 + decimals: 6 } ]; @@ -32,7 +32,7 @@ export default async function (hre: HardhatRuntimeEnvironment) { for (const token of tokens) { const contract = await deployer.deploy(artifact, [token.name, token.symbol, token.decimals]); - const contractAddress = contract.address; + const contractAddress = contract.target; console.log(`ln test token contract was deployed to ${contractAddress}`); const verificationId = await hre.run("verify:verify", { address: contractAddress, diff --git a/zksync-deployer/deploy/deploy_ln_default_logic.ts b/zksync-deployer/deploy/deploy_lnv2_default_logic.ts similarity index 92% rename from zksync-deployer/deploy/deploy_ln_default_logic.ts rename to zksync-deployer/deploy/deploy_lnv2_default_logic.ts index 65eff008..175132ac 100644 --- a/zksync-deployer/deploy/deploy_ln_default_logic.ts +++ b/zksync-deployer/deploy/deploy_lnv2_default_logic.ts @@ -1,4 +1,4 @@ -import { Wallet } from "zksync-web3"; +import { Wallet } from "zksync-ethers"; import * as ethers from "ethers"; import { HardhatRuntimeEnvironment } from "hardhat/types"; import { Deployer } from "@matterlabs/hardhat-zksync-deploy"; @@ -17,7 +17,7 @@ export default async function (hre: HardhatRuntimeEnvironment) { // deploy create2 tool contract const artifact = await deployer.loadArtifact("LnDefaultBridge"); const contract = await deployer.deploy(artifact, []); - const contractAddress = contract.address; + const contractAddress = contract.target; console.log(`ln default bridge logic contract was deployed to ${contractAddress}`); const verificationId = await hre.run("verify:verify", { address: contractAddress, diff --git a/zksync-deployer/deploy/deploy_ln_default_proxy.ts b/zksync-deployer/deploy/deploy_lnv2_default_proxy.ts similarity index 86% rename from zksync-deployer/deploy/deploy_ln_default_proxy.ts rename to zksync-deployer/deploy/deploy_lnv2_default_proxy.ts index 04a1d372..12b1f213 100644 --- a/zksync-deployer/deploy/deploy_ln_default_proxy.ts +++ b/zksync-deployer/deploy/deploy_lnv2_default_proxy.ts @@ -1,4 +1,4 @@ -import { Wallet, utils, ContractFactory } from "zksync-web3"; +import { Wallet, ContractFactory } from "zksync-ethers"; import * as ethers from "ethers"; import { HardhatRuntimeEnvironment } from "hardhat/types"; import { Deployer } from "@matterlabs/hardhat-zksync-deploy"; @@ -7,10 +7,9 @@ import { ProxyDeployer } from "./proxy.ts"; const privateKey = process.env.PRIKEY const zkSyncNetwork = { - url: "https://zksync2-testnet.zksync.dev", - proxyAdmin: "0xd7b3aC0c9E99e9B2EF1C9D2a5ff397867c8c8A3E", + proxyAdmin: "0x57E8fcaAfDE61b179BAe86cDAbfaca99E2A16484", dao: "0x88a39B052d477CfdE47600a7C9950a441Ce61cb4", - logicAddress: "0x6213E3bc566f7d7A73Fd7565c97ac5Ffb8624674", + logicAddress: "0xa1C2a266Ba82ce80243B975090016EE68C6d125B", }; export default async function (hre: HardhatRuntimeEnvironment) { diff --git a/zksync-deployer/deploy/deploy_lnv3_logic.ts b/zksync-deployer/deploy/deploy_lnv3_logic.ts new file mode 100644 index 00000000..87a12e29 --- /dev/null +++ b/zksync-deployer/deploy/deploy_lnv3_logic.ts @@ -0,0 +1,31 @@ +import { Wallet } from "zksync-ethers"; +import * as ethers from "ethers"; +import { HardhatRuntimeEnvironment } from "hardhat/types"; +import { Deployer } from "@matterlabs/hardhat-zksync-deploy"; + +const privateKey = process.env.PRIKEY + +export default async function (hre: HardhatRuntimeEnvironment) { + // deploy proxy admin contract + console.log(`Running deploy script for the zksync lnv3 logic contract`); + + // Initialize the wallet. + const wallet = new Wallet(privateKey); + + // Create deployer object and load the artifact of the contract you want to deploy. + const deployer = new Deployer(hre, wallet); + // deploy create2 tool contract + const artifact = await deployer.loadArtifact("HelixLnBridgeV3"); + const contract = await deployer.deploy(artifact, []); + const contractAddress = contract.target; + //const contractAddress = '0x3BbfC2D50E048436c51AF4df1b48E321260962a8'; + console.log(`lnv3 bridge logic contract was deployed to ${contractAddress}`); + const verificationId = await hre.run("verify:verify", { + address: contractAddress, + contract: "contracts/ln/HelixLnBridgeV3.sol:HelixLnBridgeV3", + constructorArguments: [], + }); + + console.log(`HelixLnBridgeV3 Logic Verification ID: ${verificationId}`); +} + diff --git a/zksync-deployer/deploy/deploy_lnv3_proxy.ts b/zksync-deployer/deploy/deploy_lnv3_proxy.ts new file mode 100644 index 00000000..5bfe7513 --- /dev/null +++ b/zksync-deployer/deploy/deploy_lnv3_proxy.ts @@ -0,0 +1,39 @@ +//import { Wallet, utils, ContractFactory } from "zksync-web3"; +import { Wallet, ContractFactory } from "zksync-ethers"; +import * as ethers from "ethers"; +import { HardhatRuntimeEnvironment } from "hardhat/types"; +import { Deployer } from "@matterlabs/hardhat-zksync-deploy"; +import { ProxyDeployer } from "./proxy.ts"; + +const privateKey = process.env.PRIKEY + +const zkSyncNetwork = { + proxyAdmin: "0x57E8fcaAfDE61b179BAe86cDAbfaca99E2A16484", + dao: "0x88a39B052d477CfdE47600a7C9950a441Ce61cb4", + logicAddress: "0x93944493105771aaa13B93fcb6c9a0642118d675", +}; + +export default async function (hre: HardhatRuntimeEnvironment) { + // deploy proxy admin contract + console.log(`Running deploy script for the zksync lnv3 bridge proxy contract`); + + // Initialize the wallet. + const wallet = new Wallet(privateKey); + + // Create deployer object and load the artifact of the contract you want to deploy. + const deployer = new Deployer(hre, wallet); + const artifact = await deployer.loadArtifact("HelixLnBridgeV3"); + + // deploy proxy contract + const logicFactory = new ContractFactory(artifact.abi, artifact.bytecode, wallet); + const proxyAddress = await ProxyDeployer.deployProxyContract(deployer, zkSyncNetwork.proxyAdmin, logicFactory, zkSyncNetwork.logicAddress, [zkSyncNetwork.dao]); + console.log(`proxy contract was deployed to ${proxyAddress}`); + + const calldata = ProxyDeployer.getInitializerData(logicFactory.interface, [zkSyncNetwork.dao], "initialize"); + const proxyVerificationId = await hre.run("verify:verify", { + address: proxyAddress, + constructorArguments: [zkSyncNetwork.logicAddress, zkSyncNetwork.proxyAdmin, calldata], + }); + console.log(`Proxy Verification ID: ${proxyVerificationId}`); +} + diff --git a/zksync-deployer/deploy/deploy_proxy_admin.ts b/zksync-deployer/deploy/deploy_proxy_admin.ts index 2e772a41..a80dbde2 100644 --- a/zksync-deployer/deploy/deploy_proxy_admin.ts +++ b/zksync-deployer/deploy/deploy_proxy_admin.ts @@ -1,4 +1,4 @@ -import { Wallet, utils } from "zksync-web3"; +import { Wallet } from "zksync-ethers"; import * as ethers from "ethers"; import { HardhatRuntimeEnvironment } from "hardhat/types"; import { Deployer } from "@matterlabs/hardhat-zksync-deploy"; @@ -21,7 +21,7 @@ export default async function (hre: HardhatRuntimeEnvironment) { const proxyAdminContract = await deployer.deploy(artifact, []); // Show the contract info. - const contractAddress = proxyAdminContract.address; + const contractAddress = proxyAdminContract.target; //const contractAddress = await ProxyDeployer.deployProxyAdmin(deployer); console.log(`deployed to ${contractAddress}`); diff --git a/zksync-deployer/deploy/proxy.ts b/zksync-deployer/deploy/proxy.ts index b4dee2b2..7e9693b6 100644 --- a/zksync-deployer/deploy/proxy.ts +++ b/zksync-deployer/deploy/proxy.ts @@ -23,7 +23,7 @@ var ProxyDeployer = { const artifact = await deployer.loadArtifact("TransparentUpgradeableProxy"); const proxyContract = await deployer.deploy(artifact, [logicAddress, proxyAdminAddr, calldata]); console.log("proxy args", logicAddress, proxyAdminAddr, calldata); - return proxyContract.address; + return proxyContract.target; } } diff --git a/zksync-deployer/hardhat.config.ts b/zksync-deployer/hardhat.config.ts index de4bb9cf..c13e0dd7 100644 --- a/zksync-deployer/hardhat.config.ts +++ b/zksync-deployer/hardhat.config.ts @@ -13,15 +13,19 @@ const zkSyncTestnet = zksync: true, } : { - url: "https://zksync2-testnet.zksync.dev", - ethNetwork: "goerli", + //url: "https://zksync2-testnet.zksync.dev", + url: "https://sepolia.era.zksync.dev", + //url: "https://mainnet.era.zksync.io", + ethNetwork: "sepolia", + //ethNetwork: "mainnet", zksync: true, - verifyURL: 'https://zksync2-testnet-explorer.zksync.dev/contract_verification', + verifyURL: 'https://explorer.sepolia.era.zksync.dev/contract_verification', + //verifyURL: 'https://zksync2-mainnet-explorer.zksync.io/contract_verification', }; const config: HardhatUserConfig = { zksolc: { - version: "1.3.13", + version: "1.3.19", compilerSource: "binary", settings: { "compilerPath": "/usr/local/bin/zksolc", diff --git a/zksync-deployer/package.json b/zksync-deployer/package.json index 1b6e70db..33e33c57 100644 --- a/zksync-deployer/package.json +++ b/zksync-deployer/package.json @@ -6,25 +6,27 @@ "author": "Antonio ", "license": "MIT", "devDependencies": { - "@matterlabs/hardhat-zksync-deploy": "^0.6.1", - "@matterlabs/hardhat-zksync-solc": "^0.3.13", - "@matterlabs/hardhat-zksync-verify": "^0.2.0", - "@nomicfoundation/hardhat-verify": "^1.1.0", + "@matterlabs/hardhat-zksync-deploy": "^1.1.2", + "@matterlabs/hardhat-zksync-solc": "^1.0.6", + "@matterlabs/hardhat-zksync-verify": "^1.2.2", "@types/chai": "^4.3.4", "@types/mocha": "^10.0.1", "@zeppelin-solidity/contracts": "npm:@openzeppelin/contracts@v4.7.3", "chai": "^4.3.7", "dotenv": "^16.0.3", - "ethers": "^5.7.2", - "hardhat": "^2.12.4", + "ethers": "^6.7.0", + "hardhat": "^2.19.4", "mocha": "^10.2.0", "ts-node": "^10.9.1", - "typescript": "^4.9.4", - "zksync-web3": "^0.13.0" + "typescript": "^4.9.4" }, "scripts": { - "build": "sh copy_zksync_contract.sh && npx hardhat compile", + "build": "sh copy_zksync_contract.sh && yarn hardhat compile", "deploy": "yarn hardhat deploy-zksync --script", "verify": "yarn hardhat verify" + }, + "dependencies": { + "zksync-ethers": "^6.0.0", + "zksync-web3": "^0.17.1" } } diff --git a/zksync-deployer/yarn.lock b/zksync-deployer/yarn.lock index 8c2b95ff..27ab9b80 100644 --- a/zksync-deployer/yarn.lock +++ b/zksync-deployer/yarn.lock @@ -2,6 +2,11 @@ # yarn lockfile v1 +"@adraffy/ens-normalize@1.10.0": + version "1.10.0" + resolved "https://registry.yarnpkg.com/@adraffy/ens-normalize/-/ens-normalize-1.10.0.tgz#d2a39395c587e092d77cbbc80acf956a54f38bf7" + integrity sha512-nA9XHtlAkYfJxY7bce8DcN7eKxWWCWkU+1GR9d+U6MbNpfwQp8TI7vqOsBsMcHoT4mBu2kypKoSKnghEzOOq5Q== + "@balena/dockerignore@^1.0.2": version "1.0.2" resolved "https://registry.yarnpkg.com/@balena/dockerignore/-/dockerignore-1.0.2.tgz#9ffe4726915251e8eb69f44ef3547e0da2c03e0d" @@ -410,31 +415,37 @@ "@jridgewell/resolve-uri" "^3.0.3" "@jridgewell/sourcemap-codec" "^1.4.10" -"@matterlabs/hardhat-zksync-deploy@^0.6.1": - version "0.6.3" - resolved "https://registry.yarnpkg.com/@matterlabs/hardhat-zksync-deploy/-/hardhat-zksync-deploy-0.6.3.tgz#833b208373e7037bf43671054328d82511444e2a" - integrity sha512-FB+2xFL/80JJwlGna+aHA6dk4ONrMFqThTZATYVJUAKooA0Aw5qmpmM8B3qsNB4LLzHSO/EmVrHIcLaPv8hYwQ== +"@matterlabs/hardhat-zksync-deploy@^1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@matterlabs/hardhat-zksync-deploy/-/hardhat-zksync-deploy-1.1.2.tgz#6ea95640a2e1db40395616d07819f32d437a7dde" + integrity sha512-Q9eBvMUAoodRFPmfzoHTkNKKYNs6oib2utZsxTPf6cq+mhdu7sqfY5Bu0XQzZQW35xzi5D23p9v1ubhOrGXK9Q== dependencies: + "@matterlabs/hardhat-zksync-solc" "^1.0.4" chalk "4.1.2" + ts-morph "^21.0.1" -"@matterlabs/hardhat-zksync-solc@0.3.17", "@matterlabs/hardhat-zksync-solc@^0.3.13": - version "0.3.17" - resolved "https://registry.yarnpkg.com/@matterlabs/hardhat-zksync-solc/-/hardhat-zksync-solc-0.3.17.tgz#72f199544dc89b268d7bfc06d022a311042752fd" - integrity sha512-aZgQ0yfXW5xPkfuEH1d44ncWV4T2LzKZd0VVPo4PL5cUrYs2/II1FaEDp5zsf3FxOR1xT3mBsjuSrtJkk4AL8Q== +"@matterlabs/hardhat-zksync-solc@^1.0.3", "@matterlabs/hardhat-zksync-solc@^1.0.4", "@matterlabs/hardhat-zksync-solc@^1.0.6": + version "1.0.6" + resolved "https://registry.yarnpkg.com/@matterlabs/hardhat-zksync-solc/-/hardhat-zksync-solc-1.0.6.tgz#7ef8438e6bb15244691600e2afa77aaff7dff9f0" + integrity sha512-0icYSufXba/Bbb7v2iXuZJ+IbYsiNpR4Wy6UizHnGuFw3OMHgh+saebQphuaN9yyRL2UPGZbPkQFHWBLZj5/xQ== dependencies: "@nomiclabs/hardhat-docker" "^2.0.0" chalk "4.1.2" - dockerode "^3.3.4" + dockerode "^4.0.0" + fs-extra "^11.1.1" + proper-lockfile "^4.1.2" + semver "^7.5.1" -"@matterlabs/hardhat-zksync-verify@^0.2.0": - version "0.2.0" - resolved "https://registry.yarnpkg.com/@matterlabs/hardhat-zksync-verify/-/hardhat-zksync-verify-0.2.0.tgz#a0c6b897202057873355b680244f72f573d86a97" - integrity sha512-iUwxhPlNk+HWe+UadLqQzdDb2fammbKYoz8wqVuyr9jygFUf8JNPLWDZOS0KCQgRn/dmT22+i9nSREOg66bAHA== +"@matterlabs/hardhat-zksync-verify@^1.2.2": + version "1.2.2" + resolved "https://registry.yarnpkg.com/@matterlabs/hardhat-zksync-verify/-/hardhat-zksync-verify-1.2.2.tgz#3cc568a65a5ef37e605e035afbcbddbcc116221c" + integrity sha512-l3q5JHlFA1O28TamAUcMtD/gVzDDeoyeVohGNpwYZ5qb8dPkWS3DkYCIrvsQFR4mHDzqoGKEZt1IKG/a/lYU+Q== dependencies: - "@matterlabs/hardhat-zksync-solc" "0.3.17" - axios "^1.4.0" + "@matterlabs/hardhat-zksync-solc" "^1.0.3" + "@nomicfoundation/hardhat-verify" "^2.0.0" + axios "^1.6.2" chalk "4.1.2" - dockerode "^3.3.4" + zksync-ethers "^6.0.0" "@metamask/eth-sig-util@^4.0.0": version "4.0.1" @@ -447,41 +458,74 @@ tweetnacl "^1.0.3" tweetnacl-util "^0.15.1" +"@noble/curves@1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.2.0.tgz#92d7e12e4e49b23105a2555c6984d41733d65c35" + integrity sha512-oYclrNgRaM9SsBUBVbb8M6DTV7ZHRTKugureoYEncY5c65HOmRzvSiTE3y5CYaPYJA/GVkrhXEoF0M3Ya9PMnw== + dependencies: + "@noble/hashes" "1.3.2" + "@noble/hashes@1.2.0", "@noble/hashes@~1.2.0": version "1.2.0" resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.2.0.tgz#a3150eeb09cc7ab207ebf6d7b9ad311a9bdbed12" integrity sha512-FZfhjEDbT5GRswV3C6uvLPHMiVD6lQBmpoX5+eSiPaMTXte/IKqI5dykDxzZB/WBeK/CDuQRBWarPdi3FNY2zQ== +"@noble/hashes@1.3.2": + version "1.3.2" + resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.3.2.tgz#6f26dbc8fbc7205873ce3cee2f690eba0d421b39" + integrity sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ== + "@noble/secp256k1@1.7.1", "@noble/secp256k1@~1.7.0": version "1.7.1" resolved "https://registry.yarnpkg.com/@noble/secp256k1/-/secp256k1-1.7.1.tgz#b251c70f824ce3ca7f8dc3df08d58f005cc0507c" integrity sha512-hOUk6AyBFmqVrv7k5WAw/LpszxVbj9gGN4JRkIX52fdFAj1UA61KXmZDvqVEm+pOyec3+fIeZB02LYa/pWOArw== -"@nomicfoundation/ethereumjs-block@5.0.1": - version "5.0.1" - resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-block/-/ethereumjs-block-5.0.1.tgz#6f89664f55febbd723195b6d0974773d29ee133d" - integrity sha512-u1Yioemi6Ckj3xspygu/SfFvm8vZEO8/Yx5a1QLzi6nVU0jz3Pg2OmHKJ5w+D9Ogk1vhwRiqEBAqcb0GVhCyHw== - dependencies: - "@nomicfoundation/ethereumjs-common" "4.0.1" - "@nomicfoundation/ethereumjs-rlp" "5.0.1" - "@nomicfoundation/ethereumjs-trie" "6.0.1" - "@nomicfoundation/ethereumjs-tx" "5.0.1" - "@nomicfoundation/ethereumjs-util" "9.0.1" +"@nodelib/fs.scandir@2.1.5": + version "2.1.5" + resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" + integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g== + dependencies: + "@nodelib/fs.stat" "2.0.5" + run-parallel "^1.1.9" + +"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2": + version "2.0.5" + resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b" + integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== + +"@nodelib/fs.walk@^1.2.3": + version "1.2.8" + resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a" + integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== + dependencies: + "@nodelib/fs.scandir" "2.1.5" + fastq "^1.6.0" + +"@nomicfoundation/ethereumjs-block@5.0.2": + version "5.0.2" + resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-block/-/ethereumjs-block-5.0.2.tgz#13a7968f5964f1697da941281b7f7943b0465d04" + integrity sha512-hSe6CuHI4SsSiWWjHDIzWhSiAVpzMUcDRpWYzN0T9l8/Rz7xNn3elwVOJ/tAyS0LqL6vitUD78Uk7lQDXZun7Q== + dependencies: + "@nomicfoundation/ethereumjs-common" "4.0.2" + "@nomicfoundation/ethereumjs-rlp" "5.0.2" + "@nomicfoundation/ethereumjs-trie" "6.0.2" + "@nomicfoundation/ethereumjs-tx" "5.0.2" + "@nomicfoundation/ethereumjs-util" "9.0.2" ethereum-cryptography "0.1.3" ethers "^5.7.1" -"@nomicfoundation/ethereumjs-blockchain@7.0.1": - version "7.0.1" - resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-blockchain/-/ethereumjs-blockchain-7.0.1.tgz#80e0bd3535bfeb9baa29836b6f25123dab06a726" - integrity sha512-NhzndlGg829XXbqJEYrF1VeZhAwSPgsK/OB7TVrdzft3y918hW5KNd7gIZ85sn6peDZOdjBsAXIpXZ38oBYE5A== - dependencies: - "@nomicfoundation/ethereumjs-block" "5.0.1" - "@nomicfoundation/ethereumjs-common" "4.0.1" - "@nomicfoundation/ethereumjs-ethash" "3.0.1" - "@nomicfoundation/ethereumjs-rlp" "5.0.1" - "@nomicfoundation/ethereumjs-trie" "6.0.1" - "@nomicfoundation/ethereumjs-tx" "5.0.1" - "@nomicfoundation/ethereumjs-util" "9.0.1" +"@nomicfoundation/ethereumjs-blockchain@7.0.2": + version "7.0.2" + resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-blockchain/-/ethereumjs-blockchain-7.0.2.tgz#45323b673b3d2fab6b5008535340d1b8fea7d446" + integrity sha512-8UUsSXJs+MFfIIAKdh3cG16iNmWzWC/91P40sazNvrqhhdR/RtGDlFk2iFTGbBAZPs2+klZVzhRX8m2wvuvz3w== + dependencies: + "@nomicfoundation/ethereumjs-block" "5.0.2" + "@nomicfoundation/ethereumjs-common" "4.0.2" + "@nomicfoundation/ethereumjs-ethash" "3.0.2" + "@nomicfoundation/ethereumjs-rlp" "5.0.2" + "@nomicfoundation/ethereumjs-trie" "6.0.2" + "@nomicfoundation/ethereumjs-tx" "5.0.2" + "@nomicfoundation/ethereumjs-util" "9.0.2" abstract-level "^1.0.3" debug "^4.3.3" ethereum-cryptography "0.1.3" @@ -489,112 +533,112 @@ lru-cache "^5.1.1" memory-level "^1.0.0" -"@nomicfoundation/ethereumjs-common@4.0.1": - version "4.0.1" - resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-common/-/ethereumjs-common-4.0.1.tgz#4702d82df35b07b5407583b54a45bf728e46a2f0" - integrity sha512-OBErlkfp54GpeiE06brBW/TTbtbuBJV5YI5Nz/aB2evTDo+KawyEzPjBlSr84z/8MFfj8wS2wxzQX1o32cev5g== +"@nomicfoundation/ethereumjs-common@4.0.2": + version "4.0.2" + resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-common/-/ethereumjs-common-4.0.2.tgz#a15d1651ca36757588fdaf2a7d381a150662a3c3" + integrity sha512-I2WGP3HMGsOoycSdOTSqIaES0ughQTueOsddJ36aYVpI3SN8YSusgRFLwzDJwRFVIYDKx/iJz0sQ5kBHVgdDwg== dependencies: - "@nomicfoundation/ethereumjs-util" "9.0.1" + "@nomicfoundation/ethereumjs-util" "9.0.2" crc-32 "^1.2.0" -"@nomicfoundation/ethereumjs-ethash@3.0.1": - version "3.0.1" - resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-ethash/-/ethereumjs-ethash-3.0.1.tgz#65ca494d53e71e8415c9a49ef48bc921c538fc41" - integrity sha512-KDjGIB5igzWOp8Ik5I6QiRH5DH+XgILlplsHR7TEuWANZA759G6krQ6o8bvj+tRUz08YygMQu/sGd9mJ1DYT8w== +"@nomicfoundation/ethereumjs-ethash@3.0.2": + version "3.0.2" + resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-ethash/-/ethereumjs-ethash-3.0.2.tgz#da77147f806401ee996bfddfa6487500118addca" + integrity sha512-8PfoOQCcIcO9Pylq0Buijuq/O73tmMVURK0OqdjhwqcGHYC2PwhbajDh7GZ55ekB0Px197ajK3PQhpKoiI/UPg== dependencies: - "@nomicfoundation/ethereumjs-block" "5.0.1" - "@nomicfoundation/ethereumjs-rlp" "5.0.1" - "@nomicfoundation/ethereumjs-util" "9.0.1" + "@nomicfoundation/ethereumjs-block" "5.0.2" + "@nomicfoundation/ethereumjs-rlp" "5.0.2" + "@nomicfoundation/ethereumjs-util" "9.0.2" abstract-level "^1.0.3" bigint-crypto-utils "^3.0.23" ethereum-cryptography "0.1.3" -"@nomicfoundation/ethereumjs-evm@2.0.1": - version "2.0.1" - resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-evm/-/ethereumjs-evm-2.0.1.tgz#f35681e203363f69ce2b3d3bf9f44d4e883ca1f1" - integrity sha512-oL8vJcnk0Bx/onl+TgQOQ1t/534GKFaEG17fZmwtPFeH8S5soiBYPCLUrvANOl4sCp9elYxIMzIiTtMtNNN8EQ== +"@nomicfoundation/ethereumjs-evm@2.0.2": + version "2.0.2" + resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-evm/-/ethereumjs-evm-2.0.2.tgz#4c2f4b84c056047102a4fa41c127454e3f0cfcf6" + integrity sha512-rBLcUaUfANJxyOx9HIdMX6uXGin6lANCulIm/pjMgRqfiCRMZie3WKYxTSd8ZE/d+qT+zTedBF4+VHTdTSePmQ== dependencies: "@ethersproject/providers" "^5.7.1" - "@nomicfoundation/ethereumjs-common" "4.0.1" - "@nomicfoundation/ethereumjs-tx" "5.0.1" - "@nomicfoundation/ethereumjs-util" "9.0.1" + "@nomicfoundation/ethereumjs-common" "4.0.2" + "@nomicfoundation/ethereumjs-tx" "5.0.2" + "@nomicfoundation/ethereumjs-util" "9.0.2" debug "^4.3.3" ethereum-cryptography "0.1.3" mcl-wasm "^0.7.1" rustbn.js "~0.2.0" -"@nomicfoundation/ethereumjs-rlp@5.0.1": - version "5.0.1" - resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-rlp/-/ethereumjs-rlp-5.0.1.tgz#0b30c1cf77d125d390408e391c4bb5291ef43c28" - integrity sha512-xtxrMGa8kP4zF5ApBQBtjlSbN5E2HI8m8FYgVSYAnO6ssUoY5pVPGy2H8+xdf/bmMa22Ce8nWMH3aEW8CcqMeQ== +"@nomicfoundation/ethereumjs-rlp@5.0.2": + version "5.0.2" + resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-rlp/-/ethereumjs-rlp-5.0.2.tgz#4fee8dc58a53ac6ae87fb1fca7c15dc06c6b5dea" + integrity sha512-QwmemBc+MMsHJ1P1QvPl8R8p2aPvvVcKBbvHnQOKBpBztEo0omN0eaob6FeZS/e3y9NSe+mfu3nNFBHszqkjTA== -"@nomicfoundation/ethereumjs-statemanager@2.0.1": - version "2.0.1" - resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-statemanager/-/ethereumjs-statemanager-2.0.1.tgz#8824a97938db4471911e2d2f140f79195def5935" - integrity sha512-B5ApMOnlruVOR7gisBaYwFX+L/AP7i/2oAahatssjPIBVDF6wTX1K7Qpa39E/nzsH8iYuL3krkYeUFIdO3EMUQ== +"@nomicfoundation/ethereumjs-statemanager@2.0.2": + version "2.0.2" + resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-statemanager/-/ethereumjs-statemanager-2.0.2.tgz#3ba4253b29b1211cafe4f9265fee5a0d780976e0" + integrity sha512-dlKy5dIXLuDubx8Z74sipciZnJTRSV/uHG48RSijhgm1V7eXYFC567xgKtsKiVZB1ViTP9iFL4B6Je0xD6X2OA== dependencies: - "@nomicfoundation/ethereumjs-common" "4.0.1" - "@nomicfoundation/ethereumjs-rlp" "5.0.1" + "@nomicfoundation/ethereumjs-common" "4.0.2" + "@nomicfoundation/ethereumjs-rlp" "5.0.2" debug "^4.3.3" ethereum-cryptography "0.1.3" ethers "^5.7.1" js-sdsl "^4.1.4" -"@nomicfoundation/ethereumjs-trie@6.0.1": - version "6.0.1" - resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-trie/-/ethereumjs-trie-6.0.1.tgz#662c55f6b50659fd4b22ea9f806a7401cafb7717" - integrity sha512-A64It/IMpDVODzCgxDgAAla8jNjNtsoQZIzZUfIV5AY6Coi4nvn7+VReBn5itlxMiL2yaTlQr9TRWp3CSI6VoA== +"@nomicfoundation/ethereumjs-trie@6.0.2": + version "6.0.2" + resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-trie/-/ethereumjs-trie-6.0.2.tgz#9a6dbd28482dca1bc162d12b3733acab8cd12835" + integrity sha512-yw8vg9hBeLYk4YNg5MrSJ5H55TLOv2FSWUTROtDtTMMmDGROsAu+0tBjiNGTnKRi400M6cEzoFfa89Fc5k8NTQ== dependencies: - "@nomicfoundation/ethereumjs-rlp" "5.0.1" - "@nomicfoundation/ethereumjs-util" "9.0.1" + "@nomicfoundation/ethereumjs-rlp" "5.0.2" + "@nomicfoundation/ethereumjs-util" "9.0.2" "@types/readable-stream" "^2.3.13" ethereum-cryptography "0.1.3" readable-stream "^3.6.0" -"@nomicfoundation/ethereumjs-tx@5.0.1": - version "5.0.1" - resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-tx/-/ethereumjs-tx-5.0.1.tgz#7629dc2036b4a33c34e9f0a592b43227ef4f0c7d" - integrity sha512-0HwxUF2u2hrsIM1fsasjXvlbDOq1ZHFV2dd1yGq8CA+MEYhaxZr8OTScpVkkxqMwBcc5y83FyPl0J9MZn3kY0w== +"@nomicfoundation/ethereumjs-tx@5.0.2": + version "5.0.2" + resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-tx/-/ethereumjs-tx-5.0.2.tgz#117813b69c0fdc14dd0446698a64be6df71d7e56" + integrity sha512-T+l4/MmTp7VhJeNloMkM+lPU3YMUaXdcXgTGCf8+ZFvV9NYZTRLFekRwlG6/JMmVfIfbrW+dRRJ9A6H5Q/Z64g== dependencies: "@chainsafe/ssz" "^0.9.2" "@ethersproject/providers" "^5.7.2" - "@nomicfoundation/ethereumjs-common" "4.0.1" - "@nomicfoundation/ethereumjs-rlp" "5.0.1" - "@nomicfoundation/ethereumjs-util" "9.0.1" + "@nomicfoundation/ethereumjs-common" "4.0.2" + "@nomicfoundation/ethereumjs-rlp" "5.0.2" + "@nomicfoundation/ethereumjs-util" "9.0.2" ethereum-cryptography "0.1.3" -"@nomicfoundation/ethereumjs-util@9.0.1": - version "9.0.1" - resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-util/-/ethereumjs-util-9.0.1.tgz#530cda8bae33f8b5020a8f199ed1d0a2ce48ec89" - integrity sha512-TwbhOWQ8QoSCFhV/DDfSmyfFIHjPjFBj957219+V3jTZYZ2rf9PmDtNOeZWAE3p3vlp8xb02XGpd0v6nTUPbsA== +"@nomicfoundation/ethereumjs-util@9.0.2": + version "9.0.2" + resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-util/-/ethereumjs-util-9.0.2.tgz#16bdc1bb36f333b8a3559bbb4b17dac805ce904d" + integrity sha512-4Wu9D3LykbSBWZo8nJCnzVIYGvGCuyiYLIJa9XXNVt1q1jUzHdB+sJvx95VGCpPkCT+IbLecW6yfzy3E1bQrwQ== dependencies: "@chainsafe/ssz" "^0.10.0" - "@nomicfoundation/ethereumjs-rlp" "5.0.1" + "@nomicfoundation/ethereumjs-rlp" "5.0.2" ethereum-cryptography "0.1.3" -"@nomicfoundation/ethereumjs-vm@7.0.1": - version "7.0.1" - resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-vm/-/ethereumjs-vm-7.0.1.tgz#7d035e0993bcad10716c8b36e61dfb87fa3ca05f" - integrity sha512-rArhyn0jPsS/D+ApFsz3yVJMQ29+pVzNZ0VJgkzAZ+7FqXSRtThl1C1prhmlVr3YNUlfpZ69Ak+RUT4g7VoOuQ== - dependencies: - "@nomicfoundation/ethereumjs-block" "5.0.1" - "@nomicfoundation/ethereumjs-blockchain" "7.0.1" - "@nomicfoundation/ethereumjs-common" "4.0.1" - "@nomicfoundation/ethereumjs-evm" "2.0.1" - "@nomicfoundation/ethereumjs-rlp" "5.0.1" - "@nomicfoundation/ethereumjs-statemanager" "2.0.1" - "@nomicfoundation/ethereumjs-trie" "6.0.1" - "@nomicfoundation/ethereumjs-tx" "5.0.1" - "@nomicfoundation/ethereumjs-util" "9.0.1" +"@nomicfoundation/ethereumjs-vm@7.0.2": + version "7.0.2" + resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-vm/-/ethereumjs-vm-7.0.2.tgz#3b0852cb3584df0e18c182d0672a3596c9ca95e6" + integrity sha512-Bj3KZT64j54Tcwr7Qm/0jkeZXJMfdcAtRBedou+Hx0dPOSIgqaIr0vvLwP65TpHbak2DmAq+KJbW2KNtIoFwvA== + dependencies: + "@nomicfoundation/ethereumjs-block" "5.0.2" + "@nomicfoundation/ethereumjs-blockchain" "7.0.2" + "@nomicfoundation/ethereumjs-common" "4.0.2" + "@nomicfoundation/ethereumjs-evm" "2.0.2" + "@nomicfoundation/ethereumjs-rlp" "5.0.2" + "@nomicfoundation/ethereumjs-statemanager" "2.0.2" + "@nomicfoundation/ethereumjs-trie" "6.0.2" + "@nomicfoundation/ethereumjs-tx" "5.0.2" + "@nomicfoundation/ethereumjs-util" "9.0.2" debug "^4.3.3" ethereum-cryptography "0.1.3" mcl-wasm "^0.7.1" rustbn.js "~0.2.0" -"@nomicfoundation/hardhat-verify@^1.1.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@nomicfoundation/hardhat-verify/-/hardhat-verify-1.1.0.tgz#36c7f78adebd641d641ab5dd4660111520bb3055" - integrity sha512-mXHP17gz4wDsWiXIz8fBRE/8T2KJglWE/QGk5A6nwsubyeqWgjqimfbwTLyaPESphKvis3hX6G75QP5a9Cd8cQ== +"@nomicfoundation/hardhat-verify@^2.0.0": + version "2.0.3" + resolved "https://registry.yarnpkg.com/@nomicfoundation/hardhat-verify/-/hardhat-verify-2.0.3.tgz#173557f8cfa53c8c9da23a326f54d24fe459ae68" + integrity sha512-ESbRu9by53wu6VvgwtMtm108RSmuNsVqXtzg061D+/4R7jaWh/Wl/8ve+p6SdDX7vA1Z3L02hDO1Q3BY4luLXQ== dependencies: "@ethersproject/abi" "^5.1.2" "@ethersproject/address" "^5.0.2" @@ -771,6 +815,16 @@ "@sentry/types" "5.30.0" tslib "^1.9.3" +"@ts-morph/common@~0.22.0": + version "0.22.0" + resolved "https://registry.yarnpkg.com/@ts-morph/common/-/common-0.22.0.tgz#8951d451622a26472fbc3a227d6c3a90e687a683" + integrity sha512-HqNBuV/oIlMKdkLshXd1zKBqNQCsuPEsgQOkfFQ/eUKjRlwndXW1AjN9LVkBEIukm00gGXSRmfkl0Wv5VXLnlw== + dependencies: + fast-glob "^3.3.2" + minimatch "^9.0.3" + mkdirp "^3.0.1" + path-browserify "^1.0.1" + "@tsconfig/node10@^1.0.7": version "1.0.9" resolved "https://registry.yarnpkg.com/@tsconfig/node10/-/node10-1.0.9.tgz#df4907fc07a886922637b15e02d4cebc4c0021b2" @@ -825,6 +879,11 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-20.4.8.tgz#b5dda19adaa473a9bf0ab5cbd8f30ec7d43f5c85" integrity sha512-0mHckf6D2DiIAzh8fM8f3HQCvMKDpK94YQ0DSVkfWTG9BZleYIWudw9cJxX8oCk9bM+vAkDyujDV6dmKHbvQpg== +"@types/node@18.15.13": + version "18.15.13" + resolved "https://registry.yarnpkg.com/@types/node/-/node-18.15.13.tgz#f64277c341150c979e42b00e4ac289290c9df469" + integrity sha512-N+0kuo9KgrUQ1Sn/ifDXsvg0TTleP7rIy4zOBGECxAljqvqfqpTfzx0Q1NUedOixRMBfe2Whhb056a42cWs26Q== + "@types/pbkdf2@^3.0.0": version "3.1.0" resolved "https://registry.yarnpkg.com/@types/pbkdf2/-/pbkdf2-3.1.0.tgz#039a0e9b67da0cdc4ee5dab865caa6b267bb66b1" @@ -893,6 +952,11 @@ aes-js@3.0.0: resolved "https://registry.yarnpkg.com/aes-js/-/aes-js-3.0.0.tgz#e21df10ad6c2053295bcbb8dab40b09dbea87e4d" integrity sha512-H7wUZRn8WpTq9jocdxQ2c8x2sKo9ZVmzfRE13GiNJXfp7NcKYEdvl3vspKjXox6RIG2VtaRe4JFvxG4rqp2Zuw== +aes-js@4.0.0-beta.5: + version "4.0.0-beta.5" + resolved "https://registry.yarnpkg.com/aes-js/-/aes-js-4.0.0-beta.5.tgz#8d2452c52adedebc3a3e28465d858c11ca315873" + integrity sha512-G965FqalsNyrPqgEGON7nIx1e/OVENSgiEIzyC63haUMuvNnwIgIjMs52hlTCKhkBny7A2ORNlfY9Zu+jmGk1Q== + agent-base@6: version "6.0.2" resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77" @@ -994,12 +1058,12 @@ asynckit@^0.4.0: resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q== -axios@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/axios/-/axios-1.4.0.tgz#38a7bf1224cd308de271146038b551d725f0be1f" - integrity sha512-S4XCWMEmzvo64T9GfvQDOXgYRDJ/wsSZc7Jvdgx5u1sd0JwsuPLqb3SYmusag+edF6ziyMensPVqLTSc1PiSEA== +axios@^1.6.2: + version "1.6.5" + resolved "https://registry.yarnpkg.com/axios/-/axios-1.6.5.tgz#2c090da14aeeab3770ad30c3a1461bc970fb0cd8" + integrity sha512-Ii012v05KEVuUoFWmMW/UQv9aRIc3ZwkWDcM+h5Il8izZCtRVpDUfwpoFf7eOtajT3QiGR4yDUx7lPqHJULgbg== dependencies: - follow-redirects "^1.15.0" + follow-redirects "^1.15.4" form-data "^4.0.0" proxy-from-env "^1.1.0" @@ -1089,7 +1153,7 @@ brace-expansion@^2.0.1: dependencies: balanced-match "^1.0.0" -braces@~3.0.2: +braces@^3.0.2, braces@~3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== @@ -1320,6 +1384,11 @@ cliui@^7.0.2: strip-ansi "^6.0.0" wrap-ansi "^7.0.0" +code-block-writer@^12.0.0: + version "12.0.0" + resolved "https://registry.yarnpkg.com/code-block-writer/-/code-block-writer-12.0.0.tgz#4dd58946eb4234105aff7f0035977b2afdc2a770" + integrity sha512-q4dMFMlXtKR3XNBHyMHt/3pwYNA69EDk00lloMOaaUMKPUXBw6lpXtbu3MMVG6/uOihGnRDOlkyqsONEUj60+w== + color-convert@^1.9.0: version "1.9.3" resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" @@ -1386,10 +1455,10 @@ core-util-is@~1.0.0: resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85" integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ== -cpu-features@~0.0.8: - version "0.0.8" - resolved "https://registry.yarnpkg.com/cpu-features/-/cpu-features-0.0.8.tgz#a2d464b023b8ad09004c8cdca23b33f192f63546" - integrity sha512-BbHBvtYhUhksqTjr6bhNOjGgMnhwhGTQmOoZGD+K7BCaQDCuZl/Ve1ZxUSMRwVC4D/rkCPQ2MAIeYzrWyK7eEg== +cpu-features@~0.0.9: + version "0.0.9" + resolved "https://registry.yarnpkg.com/cpu-features/-/cpu-features-0.0.9.tgz#5226b92f0f1c63122b0a3eb84cb8335a4de499fc" + integrity sha512-AKjgn2rP2yJyfbepsmLfiYcmtNn/2eUvocUyM/09yB0YDiz39HteK/5/T4Onf0pmdYDMgkBoGvRLvEguzyL7wQ== dependencies: buildcheck "~0.0.6" nan "^2.17.0" @@ -1483,15 +1552,15 @@ docker-modem@^1.0.8: readable-stream "~1.0.26-4" split-ca "^1.0.0" -docker-modem@^3.0.0: - version "3.0.8" - resolved "https://registry.yarnpkg.com/docker-modem/-/docker-modem-3.0.8.tgz#ef62c8bdff6e8a7d12f0160988c295ea8705e77a" - integrity sha512-f0ReSURdM3pcKPNS30mxOHSbaFLcknGmQjwSfmbcdOw1XWKXVhukM3NJHhr7NpY9BIyyWQb0EBo3KQvvuU5egQ== +docker-modem@^5.0.3: + version "5.0.3" + resolved "https://registry.yarnpkg.com/docker-modem/-/docker-modem-5.0.3.tgz#50c06f11285289f58112b5c4c4d89824541c41d0" + integrity sha512-89zhop5YVhcPEt5FpUFGr3cDyceGhq/F9J+ZndQ4KfqNvfbJpPMfgeixFgUj5OjCYAboElqODxY5Z1EBsSa6sg== dependencies: debug "^4.1.1" readable-stream "^3.5.0" split-ca "^1.0.1" - ssh2 "^1.11.0" + ssh2 "^1.15.0" dockerode@^2.5.8: version "2.5.8" @@ -1502,13 +1571,13 @@ dockerode@^2.5.8: docker-modem "^1.0.8" tar-fs "~1.16.3" -dockerode@^3.3.4: - version "3.3.5" - resolved "https://registry.yarnpkg.com/dockerode/-/dockerode-3.3.5.tgz#7ae3f40f2bec53ae5e9a741ce655fff459745629" - integrity sha512-/0YNa3ZDNeLr/tSckmD69+Gq+qVNhvKfAHNeZJBnp7EOP6RGKV8ORrJHkUn20So5wU+xxT7+1n5u8PjHbfjbSA== +dockerode@^4.0.0: + version "4.0.2" + resolved "https://registry.yarnpkg.com/dockerode/-/dockerode-4.0.2.tgz#dedc8529a1db3ac46d186f5912389899bc309f7d" + integrity sha512-9wM1BVpVMFr2Pw3eJNXrYYt6DT9k0xMcsSCjtPvyQ+xa1iPg/Mo3T/gUcwI0B2cczqCeCYRPF8yFYDwtFXT0+w== dependencies: "@balena/dockerignore" "^1.0.2" - docker-modem "^3.0.0" + docker-modem "^5.0.3" tar-fs "~2.0.1" dotenv@^16.0.3: @@ -1621,7 +1690,7 @@ ethereumjs-util@^6.0.0, ethereumjs-util@^6.2.1: ethjs-util "0.1.6" rlp "^2.2.3" -ethers@^5.7.1, ethers@^5.7.2: +ethers@^5.7.1, ethers@~5.7.0: version "5.7.2" resolved "https://registry.yarnpkg.com/ethers/-/ethers-5.7.2.tgz#3a7deeabbb8c030d4126b24f84e525466145872e" integrity sha512-wswUsmWo1aOK8rR7DIKiWSw9DbLWe6x98Jrn8wcTflTVvaXhAMaB5zGAXy0GYQEQp9iO1iSHWVyARQm11zUtyg== @@ -1657,6 +1726,19 @@ ethers@^5.7.1, ethers@^5.7.2: "@ethersproject/web" "5.7.1" "@ethersproject/wordlists" "5.7.0" +ethers@^6.7.0: + version "6.9.2" + resolved "https://registry.yarnpkg.com/ethers/-/ethers-6.9.2.tgz#6f4632f62e2350fa8354ff28624027a175ef85a4" + integrity sha512-YpkrtILnMQz5jSEsJQRTpduaGT/CXuLnUIuOYzHA0v/7c8IX91m2J48wSKjzGL5L9J/Us3tLoUdb+OwE3U+FFQ== + dependencies: + "@adraffy/ens-normalize" "1.10.0" + "@noble/curves" "1.2.0" + "@noble/hashes" "1.3.2" + "@types/node" "18.15.13" + aes-js "4.0.0-beta.5" + tslib "2.4.0" + ws "8.5.0" + ethjs-util@0.1.6, ethjs-util@^0.1.6: version "0.1.6" resolved "https://registry.yarnpkg.com/ethjs-util/-/ethjs-util-0.1.6.tgz#f308b62f185f9fe6237132fb2a9818866a5cd536" @@ -1678,6 +1760,24 @@ fast-deep-equal@^3.1.1: resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== +fast-glob@^3.3.2: + version "3.3.2" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.2.tgz#a904501e57cfdd2ffcded45e99a54fef55e46129" + integrity sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow== + dependencies: + "@nodelib/fs.stat" "^2.0.2" + "@nodelib/fs.walk" "^1.2.3" + glob-parent "^5.1.2" + merge2 "^1.3.0" + micromatch "^4.0.4" + +fastq@^1.6.0: + version "1.16.0" + resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.16.0.tgz#83b9a9375692db77a822df081edb6a9cf6839320" + integrity sha512-ifCoaXsDrsdkWTtiNJX5uzHDsrck5TzfKKDcuFFTIrrc/BS076qgEIfoIy1VeZqViznfKiysPYTh/QeHtnIsYA== + dependencies: + reusify "^1.0.4" + fill-range@^7.0.1: version "7.0.1" resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" @@ -1705,11 +1805,16 @@ flat@^5.0.2: resolved "https://registry.yarnpkg.com/flat/-/flat-5.0.2.tgz#8ca6fe332069ffa9d324c327198c598259ceb241" integrity sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ== -follow-redirects@^1.12.1, follow-redirects@^1.15.0: +follow-redirects@^1.12.1: version "1.15.2" resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.2.tgz#b460864144ba63f2681096f274c4e57026da2c13" integrity sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA== +follow-redirects@^1.15.4: + version "1.15.4" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.4.tgz#cdc7d308bf6493126b17ea2191ea0ccf3e535adf" + integrity sha512-Cr4D/5wlrb0z9dgERpUL3LrmPKVDsETIJhaCMeDfuFYcqa5bldGV6wBsAN6X/vxlXQtFBMrXdXxdL8CbDTGniw== + form-data@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452" @@ -1745,6 +1850,15 @@ fs-extra@^0.30.0: path-is-absolute "^1.0.0" rimraf "^2.2.8" +fs-extra@^11.1.1: + version "11.2.0" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-11.2.0.tgz#e70e17dfad64232287d01929399e0ea7c86b0e5b" + integrity sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw== + dependencies: + graceful-fs "^4.2.0" + jsonfile "^6.0.1" + universalify "^2.0.0" + fs-extra@^7.0.1: version "7.0.1" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-7.0.1.tgz#4f189c44aa123b895f722804f55ea23eadc348e9" @@ -1779,7 +1893,7 @@ get-func-name@^2.0.0: resolved "https://registry.yarnpkg.com/get-func-name/-/get-func-name-2.0.0.tgz#ead774abee72e20409433a066366023dd6887a41" integrity sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig== -glob-parent@~5.1.2: +glob-parent@^5.1.2, glob-parent@~5.1.2: version "5.1.2" resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== @@ -1810,28 +1924,28 @@ glob@^7.1.3: once "^1.3.0" path-is-absolute "^1.0.0" -graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.1.9: +graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.1.9, graceful-fs@^4.2.0, graceful-fs@^4.2.4: version "4.2.11" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== -hardhat@^2.12.4: - version "2.17.1" - resolved "https://registry.yarnpkg.com/hardhat/-/hardhat-2.17.1.tgz#4b6c8c8f624fd23d9f40185a4af24815d05a486a" - integrity sha512-1PxRkfjhEzXs/wDxI5YgzYBxNmvzifBTjYzuopwel+vXpAhCudplusJthN5eig0FTs4qbi828DBIITEDh8x9LA== +hardhat@^2.19.4: + version "2.19.4" + resolved "https://registry.yarnpkg.com/hardhat/-/hardhat-2.19.4.tgz#5112c30295d8be2e18e55d847373c50483ed1902" + integrity sha512-fTQJpqSt3Xo9Mn/WrdblNGAfcANM6XC3tAEi6YogB4s02DmTf93A8QsGb8uR0KR8TFcpcS8lgiW4ugAIYpnbrQ== dependencies: "@ethersproject/abi" "^5.1.2" "@metamask/eth-sig-util" "^4.0.0" - "@nomicfoundation/ethereumjs-block" "5.0.1" - "@nomicfoundation/ethereumjs-blockchain" "7.0.1" - "@nomicfoundation/ethereumjs-common" "4.0.1" - "@nomicfoundation/ethereumjs-evm" "2.0.1" - "@nomicfoundation/ethereumjs-rlp" "5.0.1" - "@nomicfoundation/ethereumjs-statemanager" "2.0.1" - "@nomicfoundation/ethereumjs-trie" "6.0.1" - "@nomicfoundation/ethereumjs-tx" "5.0.1" - "@nomicfoundation/ethereumjs-util" "9.0.1" - "@nomicfoundation/ethereumjs-vm" "7.0.1" + "@nomicfoundation/ethereumjs-block" "5.0.2" + "@nomicfoundation/ethereumjs-blockchain" "7.0.2" + "@nomicfoundation/ethereumjs-common" "4.0.2" + "@nomicfoundation/ethereumjs-evm" "2.0.2" + "@nomicfoundation/ethereumjs-rlp" "5.0.2" + "@nomicfoundation/ethereumjs-statemanager" "2.0.2" + "@nomicfoundation/ethereumjs-trie" "6.0.2" + "@nomicfoundation/ethereumjs-tx" "5.0.2" + "@nomicfoundation/ethereumjs-util" "9.0.2" + "@nomicfoundation/ethereumjs-vm" "7.0.2" "@nomicfoundation/solidity-analyzer" "^0.1.0" "@sentry/node" "^5.18.1" "@types/bn.js" "^5.1.0" @@ -2066,6 +2180,15 @@ jsonfile@^4.0.0: optionalDependencies: graceful-fs "^4.1.6" +jsonfile@^6.0.1: + version "6.1.0" + resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-6.1.0.tgz#bc55b2634793c679ec6403094eb13698a6ec0aae" + integrity sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ== + dependencies: + universalify "^2.0.0" + optionalDependencies: + graceful-fs "^4.1.6" + jsonparse@^1.2.0: version "1.3.1" resolved "https://registry.yarnpkg.com/jsonparse/-/jsonparse-1.3.1.tgz#3f4dae4a91fac315f71062f8521cc239f1366280" @@ -2160,6 +2283,13 @@ lru-cache@^5.1.1: dependencies: yallist "^3.0.2" +lru-cache@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" + integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== + dependencies: + yallist "^4.0.0" + lru_map@^0.3.3: version "0.3.3" resolved "https://registry.yarnpkg.com/lru_map/-/lru_map-0.3.3.tgz#b5c8351b9464cbd750335a79650a0ec0e56118dd" @@ -2198,6 +2328,19 @@ memorystream@^0.3.1: resolved "https://registry.yarnpkg.com/memorystream/-/memorystream-0.3.1.tgz#86d7090b30ce455d63fbae12dda51a47ddcaf9b2" integrity sha512-S3UwM3yj5mtUSEfP41UZmt/0SCoVYUcU1rkXv+BQ5Ig8ndL4sPoJNBUJERafdPb5jjHJGuMgytgKvKIf58XNBw== +merge2@^1.3.0: + version "1.4.1" + resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" + integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== + +micromatch@^4.0.4: + version "4.0.5" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6" + integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA== + dependencies: + braces "^3.0.2" + picomatch "^2.3.1" + mime-db@1.52.0: version "1.52.0" resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" @@ -2234,6 +2377,13 @@ minimatch@^3.0.4, minimatch@^3.1.1: dependencies: brace-expansion "^1.1.7" +minimatch@^9.0.3: + version "9.0.3" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.3.tgz#a6e00c3de44c3a542bfaae70abfc22420a6da825" + integrity sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg== + dependencies: + brace-expansion "^2.0.1" + minimist@^1.2.6: version "1.2.8" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" @@ -2251,6 +2401,11 @@ mkdirp@^0.5.1: dependencies: minimist "^1.2.6" +mkdirp@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-3.0.1.tgz#e44e4c5607fb279c168241713cc6e0fea9adcb50" + integrity sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg== + mnemonist@^0.38.0: version "0.38.5" resolved "https://registry.yarnpkg.com/mnemonist/-/mnemonist-0.38.5.tgz#4adc7f4200491237fe0fa689ac0b86539685cade" @@ -2300,10 +2455,10 @@ ms@2.1.3, ms@^2.1.1: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== -nan@^2.17.0: - version "2.17.0" - resolved "https://registry.yarnpkg.com/nan/-/nan-2.17.0.tgz#c0150a2368a182f033e9aa5195ec76ea41a199cb" - integrity sha512-2ZTgtl0nJsO0KQCjEpxcIr5D+Yv90plTitZt9JBfQvVJDS5seMl3FOvsh3+9CoYWXf/1l5OaZzzF6nDm4cagaQ== +nan@^2.17.0, nan@^2.18.0: + version "2.18.0" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.18.0.tgz#26a6faae7ffbeb293a39660e88a76b82e30b7554" + integrity sha512-W7tfG7vMOGtD30sHoZSSc/JVYiyDPEyQVso/Zz+/uQd0B0L46gtC+pHha5FFMRpil6fm/AoEcRWyOVi4+E/f8w== nanoid@3.3.3: version "3.3.3" @@ -2321,9 +2476,9 @@ node-addon-api@^2.0.0: integrity sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA== node-fetch@^2.6.0: - version "2.6.12" - resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.12.tgz#02eb8e22074018e3d5a83016649d04df0e348fba" - integrity sha512-C/fGU2E8ToujUivIO0H+tpQ6HWo4eEmchoPIoXtxCrVghxdKq+QOHqEZW7tuP3KlV3bC8FRMO5nMCC7Zm1VP6g== + version "2.7.0" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.7.0.tgz#d0f0fa6e3e2dc1d27efcd8ad99d550bda94d187d" + integrity sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A== dependencies: whatwg-url "^5.0.0" @@ -2399,6 +2554,11 @@ p-try@^1.0.0: resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3" integrity sha512-U1etNYuMJoIz3ZXSrrySFjsXQTWOx2/jdi86L+2pRvph/qMKL6sbcCYdH23fqsbm8TH2Gn0OybpT4eSFlCVHww== +path-browserify@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-1.0.1.tgz#d98454a9c3753d5790860f16f68867b9e46be1fd" + integrity sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g== + path-exists@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" @@ -2435,7 +2595,7 @@ pbkdf2@^3.0.17: safe-buffer "^5.0.1" sha.js "^2.4.8" -picomatch@^2.0.4, picomatch@^2.2.1: +picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.3.1: version "2.3.1" resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== @@ -2445,6 +2605,15 @@ process-nextick-args@~2.0.0: resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== +proper-lockfile@^4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/proper-lockfile/-/proper-lockfile-4.1.2.tgz#c8b9de2af6b2f1601067f98e01ac66baa223141f" + integrity sha512-TjNPblN4BwAWMXU8s9AEz4JmQxnD1NNL7bNOY/AKUzyamc379FWASUhc/K1pL2noVb+XmZKLL68cjzLsiOAMaA== + dependencies: + graceful-fs "^4.2.4" + retry "^0.12.0" + signal-exit "^3.0.2" + proxy-from-env@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2" @@ -2467,9 +2636,9 @@ pump@^3.0.0: once "^1.3.1" punycode@^2.1.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.0.tgz#f67fa67c94da8f4d0cfff981aee4118064199b8f" - integrity sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA== + version "2.3.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.1.tgz#027422e2faec0b25e1549c3e1bd8309b9133b6e5" + integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg== queue-microtask@^1.2.2, queue-microtask@^1.2.3: version "1.2.3" @@ -2549,6 +2718,16 @@ resolve@1.17.0: dependencies: path-parse "^1.0.6" +retry@^0.12.0: + version "0.12.0" + resolved "https://registry.yarnpkg.com/retry/-/retry-0.12.0.tgz#1b42a6266a21f07421d1b0b54b7dc167b01c013b" + integrity sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow== + +reusify@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" + integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== + rimraf@^2.2.8: version "2.7.1" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" @@ -2578,6 +2757,13 @@ run-parallel-limit@^1.1.0: dependencies: queue-microtask "^1.2.2" +run-parallel@^1.1.9: + version "1.2.0" + resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" + integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA== + dependencies: + queue-microtask "^1.2.2" + rustbn.js@~0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/rustbn.js/-/rustbn.js-0.2.0.tgz#8082cb886e707155fd1cb6f23bd591ab8d55d0ca" @@ -2622,6 +2808,13 @@ semver@^6.3.0: resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== +semver@^7.5.1: + version "7.5.4" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.4.tgz#483986ec4ed38e1c6c48c34894a9182dbff68a6e" + integrity sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA== + dependencies: + lru-cache "^6.0.0" + serialize-javascript@6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-6.0.0.tgz#efae5d88f45d7924141da8b5c3a7a7e663fefeb8" @@ -2647,6 +2840,11 @@ sha.js@^2.4.0, sha.js@^2.4.8: inherits "^2.0.1" safe-buffer "^5.0.1" +signal-exit@^3.0.2: + version "3.0.7" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" + integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== + slice-ansi@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-4.0.0.tgz#500e8dd0fd55b05815086255b3195adf2a45fe6b" @@ -2689,16 +2887,16 @@ split-ca@^1.0.0, split-ca@^1.0.1: resolved "https://registry.yarnpkg.com/split-ca/-/split-ca-1.0.1.tgz#6c83aff3692fa61256e0cd197e05e9de157691a6" integrity sha512-Q5thBSxp5t8WPTTJQS59LrGqOZqOsrhDGDVm8azCqIBjSBd7nd9o2PM+mDulQQkh8h//4U6hFZnc/mul8t5pWQ== -ssh2@^1.11.0: - version "1.14.0" - resolved "https://registry.yarnpkg.com/ssh2/-/ssh2-1.14.0.tgz#8f68440e1b768b66942c9e4e4620b2725b3555bb" - integrity sha512-AqzD1UCqit8tbOKoj6ztDDi1ffJZ2rV2SwlgrVVrHPkV5vWqGJOVp5pmtj18PunkPJAuKQsnInyKV+/Nb2bUnA== +ssh2@^1.15.0: + version "1.15.0" + resolved "https://registry.yarnpkg.com/ssh2/-/ssh2-1.15.0.tgz#2f998455036a7f89e0df5847efb5421748d9871b" + integrity sha512-C0PHgX4h6lBxYx7hcXwu3QWdh4tg6tZZsTfXcdvc5caW/EMxaB4H9dWsl7qk+F7LAW762hp8VbXOX7x4xUYvEw== dependencies: asn1 "^0.2.6" bcrypt-pbkdf "^1.0.2" optionalDependencies: - cpu-features "~0.0.8" - nan "^2.17.0" + cpu-features "~0.0.9" + nan "^2.18.0" stacktrace-parser@^0.1.10: version "0.1.10" @@ -2874,6 +3072,14 @@ tr46@~0.0.3: resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw== +ts-morph@^21.0.1: + version "21.0.1" + resolved "https://registry.yarnpkg.com/ts-morph/-/ts-morph-21.0.1.tgz#712302a0f6e9dbf1aa8d9cf33a4386c4b18c2006" + integrity sha512-dbDtVdEAncKctzrVZ+Nr7kHpHkv+0JDJb2MjjpBaj8bFeCkePU9rHfMklmhuLFnpeq/EJZk2IhStY6NzqgjOkg== + dependencies: + "@ts-morph/common" "~0.22.0" + code-block-writer "^12.0.0" + ts-node@^10.9.1: version "10.9.1" resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.9.1.tgz#e73de9102958af9e1f0b168a6ff320e25adcff4b" @@ -2893,6 +3099,11 @@ ts-node@^10.9.1: v8-compile-cache-lib "^3.0.1" yn "3.1.1" +tslib@2.4.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.4.0.tgz#7cecaa7f073ce680a05847aa77be941098f36dc3" + integrity sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ== + tslib@^1.9.3: version "1.14.1" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" @@ -2955,6 +3166,11 @@ universalify@^0.1.0: resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== +universalify@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.1.tgz#168efc2180964e6386d061e094df61afe239b18d" + integrity sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw== + unpipe@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" @@ -3019,6 +3235,11 @@ ws@7.4.6: resolved "https://registry.yarnpkg.com/ws/-/ws-7.4.6.tgz#5654ca8ecdeee47c33a9a4bf6d28e2be2980377c" integrity sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A== +ws@8.5.0: + version "8.5.0" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.5.0.tgz#bfb4be96600757fe5382de12c670dab984a1ed4f" + integrity sha512-BWX0SWVgLPzYwF8lTzEy1egjhS4S4OEAHfsO8o65WOVsrnSRGaSiUaa9e0ggGlkMTtBlmOpEXiie9RUcBO86qg== + ws@^7.4.6: version "7.5.9" resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.9.tgz#54fa7db29f4c7cec68b1ddd3a89de099942bb591" @@ -3039,6 +3260,11 @@ yallist@^3.0.2: resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== +yallist@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" + integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== + yargs-parser@20.2.4: version "20.2.4" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.4.tgz#b42890f14566796f85ae8e3a25290d205f154a54" @@ -3082,7 +3308,14 @@ yocto-queue@^0.1.0: resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== -zksync-web3@^0.13.0: - version "0.13.4" - resolved "https://registry.yarnpkg.com/zksync-web3/-/zksync-web3-0.13.4.tgz#1c5b1303436cb4cba1a0873ea07860b19f385331" - integrity sha512-AjCKhn9TRqsk2T9VLKxlod22rnVWOWGOjq+QXppFe2yTxZx9dVaai325OJ0aa7a3m5wx+9yhPqBu23jG2xPo5Q== +zksync-ethers@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/zksync-ethers/-/zksync-ethers-6.0.0.tgz#60ec1c38bb2a0b844433fa59a33633e258cb00d6" + integrity sha512-eQv8V3eK6dDHobI27mHydT1liqlKAoVJzdhxYfP4weE7emPMCcHfJBVVxN5HyitEkuwZC7ir7fa1Q7PK6ox+Cw== + +zksync-web3@^0.17.1: + version "0.17.1" + resolved "https://registry.yarnpkg.com/zksync-web3/-/zksync-web3-0.17.1.tgz#809c3b31295c29aae924ec2fe47f87701b539012" + integrity sha512-jMV4gfAQyehkIbNs81i4uvccHLe+XBu/tNPFb0Rm38pXccWY5VXzVE6XWS0dBiHlMfjdfUGn/sxwzJbWZDGYGQ== + dependencies: + ethers "~5.7.0"