From 8a77995b32d1f96880dfef269bd8f380be706992 Mon Sep 17 00:00:00 2001 From: RuslanProgrammer Date: Wed, 3 Jan 2024 15:42:29 +0100 Subject: [PATCH 1/6] refactored --- contracts/L1Sender.sol | 30 +++++--- contracts/L2TokenReceiver.sol | 4 +- deploy/1_bridge.migration.ts | 13 ++-- deploy/2_token.migration.ts | 32 ++++----- deploy/3_init_bridge.migration.ts | 15 ++-- deploy/helpers/config-parser.ts | 2 +- test/Distribution.test.ts | 39 +++++++---- test/L1Sender.test.ts | 109 +++++++++++++++++++++++------- test/fork/L1Sender.fork.test.ts | 24 ++++--- 9 files changed, 172 insertions(+), 96 deletions(-) diff --git a/contracts/L1Sender.sol b/contracts/L1Sender.sol index 7e1d53a..530ad67 100644 --- a/contracts/L1Sender.sol +++ b/contracts/L1Sender.sol @@ -17,20 +17,33 @@ import {IL1Sender} from "./interfaces/IL1Sender.sol"; contract L1Sender is IL1Sender, ERC165, OwnableUpgradeable, UUPSUpgradeable { address public unwrappedDepositToken; + address public distribution; DepositTokenConfig public depositTokenConfig; RewardTokenConfig public rewardTokenConfig; - function L1Sender__init() external initializer { + function L1Sender__init( + address distribution_, + RewardTokenConfig calldata rewardTokenConfig_, + DepositTokenConfig calldata depositTokenConfig_ + ) external initializer { __Ownable_init(); __UUPSUpgradeable_init(); + + setDistribution(distribution_); + setRewardTokenConfig(rewardTokenConfig_); + setDepositTokenConfig(depositTokenConfig_); + } + + function setDistribution(address distribution_) public onlyOwner { + distribution = distribution_; } - function setRewardTokenConfig(RewardTokenConfig calldata newConfig_) external onlyOwner { + function setRewardTokenConfig(RewardTokenConfig calldata newConfig_) public onlyOwner { rewardTokenConfig = newConfig_; } - function setDepositTokenConfig(DepositTokenConfig calldata newConfig_) external onlyOwner { + function setDepositTokenConfig(DepositTokenConfig calldata newConfig_) public onlyOwner { require(newConfig_.receiver != address(0), "L1S: invalid receiver"); DepositTokenConfig storage oldConfig = depositTokenConfig; @@ -65,14 +78,13 @@ contract L1Sender is IL1Sender, ERC165, OwnableUpgradeable, UUPSUpgradeable { address oldToken_, address newToken_ ) private { - bool isTokenChanged_ = oldToken_ != newToken_; - bool isGatewayChanged_ = oldGateway_ != newGateway_; + bool isAllowedChanged_ = (oldToken_ != newToken_) || (oldGateway_ != newGateway_); - if (oldGateway_ != address(0) && (isTokenChanged_ || isGatewayChanged_)) { + if (oldGateway_ != address(0) && isAllowedChanged_) { IERC20(oldToken_).approve(oldGateway_, 0); } - if (isTokenChanged_ || isGatewayChanged_) { + if (isAllowedChanged_) { IERC20(newToken_).approve(newGateway_, type(uint256).max); } } @@ -102,7 +114,9 @@ contract L1Sender is IL1Sender, ERC165, OwnableUpgradeable, UUPSUpgradeable { ); } - function sendMintMessage(address user_, uint256 amount_, address refundTo_) external payable onlyOwner { + function sendMintMessage(address user_, uint256 amount_, address refundTo_) external payable { + require(_msgSender() == distribution, "L1S: invalid sender"); + RewardTokenConfig storage config = rewardTokenConfig; bytes memory receiverAndSenderAddresses_ = abi.encodePacked(config.receiver, address(this)); diff --git a/contracts/L2TokenReceiver.sol b/contracts/L2TokenReceiver.sol index 5a8df75..e836a9c 100644 --- a/contracts/L2TokenReceiver.sol +++ b/contracts/L2TokenReceiver.sol @@ -98,8 +98,8 @@ contract L2TokenReceiver is IL2TokenReceiver, ERC165, OwnableUpgradeable, UUPSUp tokenId: tokenId_, amount0Desired: amountAdd0_, amount1Desired: amountAdd1_, - amount0Min: 0, - amount1Min: 0, + amount0Min: amountMin0_, + amount1Min: amountMin1_, deadline: block.timestamp }); diff --git a/deploy/1_bridge.migration.ts b/deploy/1_bridge.migration.ts index 60eb335..4a90f20 100644 --- a/deploy/1_bridge.migration.ts +++ b/deploy/1_bridge.migration.ts @@ -1,4 +1,4 @@ -import { DefaultStorage, Deployer, Reporter } from '@solarity/hardhat-migrate'; +import { Deployer, Reporter } from '@solarity/hardhat-migrate'; import { parseConfig } from './helpers/config-parser'; @@ -44,7 +44,7 @@ module.exports = async function (deployer: Deployer) { const swapParams: IL2TokenReceiver.SwapParamsStruct = { tokenIn: WStETH, - tokenOut: MOR.address, + tokenOut: MOR, fee: config.swapParams.fee, sqrtPriceLimitX96: config.swapParams.sqrtPriceLimitX96, }; @@ -53,20 +53,21 @@ module.exports = async function (deployer: Deployer) { const l2TokenReceiverProxy = await deployer.deploy(ERC1967Proxy__factory, [l2TokenReceiverImpl, '0x'], { name: 'L2TokenReceiver Proxy', }); - const l2TokenReceiver = L2TokenReceiver__factory.connect(l2TokenReceiverProxy.address, await deployer.getSigner()); + const l2TokenReceiver = L2TokenReceiver__factory.connect( + await l2TokenReceiverProxy.getAddress(), + await deployer.getSigner(), + ); await l2TokenReceiver.L2TokenReceiver__init(swapRouter, nonfungiblePositionManager, swapParams); - DefaultStorage.set('l2TokenReceiver', l2TokenReceiver.address); const l2MessageReceiverImpl = await deployer.deploy(L2MessageReceiver__factory); const l2MessageReceiverProxy = await deployer.deploy(ERC1967Proxy__factory, [l2MessageReceiverImpl, '0x'], { name: 'L2MessageReceiver Proxy', }); const l2MessageReceiver = L2MessageReceiver__factory.connect( - l2MessageReceiverProxy.address, + await l2MessageReceiverProxy.getAddress(), await deployer.getSigner(), ); await l2MessageReceiver.L2MessageReceiver__init(); - DefaultStorage.set('l2MessageReceiver', l2MessageReceiver.address); await MOR.transferOwnership(l2MessageReceiver); diff --git a/deploy/2_token.migration.ts b/deploy/2_token.migration.ts index 5e65345..e1f9385 100644 --- a/deploy/2_token.migration.ts +++ b/deploy/2_token.migration.ts @@ -1,4 +1,4 @@ -import { DefaultStorage, Deployer, Reporter } from '@solarity/hardhat-migrate'; +import { Deployer, Reporter } from '@solarity/hardhat-migrate'; import { parseConfig } from './helpers/config-parser'; @@ -6,12 +6,13 @@ import { Distribution__factory, ERC1967Proxy__factory, L1Sender__factory, + L2MessageReceiver__factory, LZEndpointMock__factory, StETHMock__factory, WStETHMock__factory, } from '@/generated-types/ethers'; import { IL1Sender } from '@/generated-types/ethers/contracts/L1Sender'; -import { ZERO_ADDR } from '@/scripts/utils/constants'; +import { ETHER_ADDR } from '@/scripts/utils/constants'; module.exports = async function (deployer: Deployer) { const config = parseConfig(); @@ -46,39 +47,32 @@ module.exports = async function (deployer: Deployer) { if (config.arbitrumConfig) { arbitrumBridgeGatewayRouter = config.arbitrumConfig.arbitrumBridgeGatewayRouter; } else { - arbitrumBridgeGatewayRouter = ZERO_ADDR; + arbitrumBridgeGatewayRouter = ETHER_ADDR; } const distributionImpl = await deployer.deploy(Distribution__factory); const distributionProxy = await deployer.deploy(ERC1967Proxy__factory, [distributionImpl, '0x'], { name: 'Distribution Proxy', }); - const distribution = Distribution__factory.connect(distributionProxy.address, await deployer.getSigner()); - - const l1SenderImpl = await deployer.deploy(L1Sender__factory); - const l1SenderProxy = await deployer.deploy(ERC1967Proxy__factory, [l1SenderImpl, '0x'], { - name: 'L1Sender Proxy', - }); - const l1Sender = L1Sender__factory.connect(l1SenderProxy.address, await deployer.getSigner()); - await l1Sender.L1Sender__init(); + const distribution = Distribution__factory.connect(await distributionProxy.getAddress(), await deployer.getSigner()); const rewardTokenConfig: IL1Sender.RewardTokenConfigStruct = { gateway: lzEndpointL1, - receiver: DefaultStorage.get('l2MessageReceiver'), - // receiver: '0xc37fF39e5A50543AD01E42C4Cd88c2939dD13002', + receiver: await deployer.deployed(L2MessageReceiver__factory, 'L2MessageReceiver Proxy'), receiverChainId: config.chainsConfig.receiverChainId, }; - await l1Sender.setRewardTokenConfig(rewardTokenConfig); - const depositTokenConfig: IL1Sender.DepositTokenConfigStruct = { token: wStEth, gateway: arbitrumBridgeGatewayRouter, - receiver: DefaultStorage.get('l2TokenReceiver'), - // receiver: '0x56c7db3D200c92eAAb8a2c4a9C1DcB8c50D4041F', + receiver: await deployer.deployed(L2MessageReceiver__factory, 'L2MessageReceiver Proxy'), }; - await l1Sender.setDepositTokenConfig(depositTokenConfig); - await l1Sender.transferOwnership(await distribution.getAddress()); + const l1SenderImpl = await deployer.deploy(L1Sender__factory); + const l1SenderProxy = await deployer.deploy(ERC1967Proxy__factory, [l1SenderImpl, '0x'], { + name: 'L1Sender Proxy', + }); + const l1Sender = L1Sender__factory.connect(await l1SenderProxy.getAddress(), await deployer.getSigner()); + await l1Sender.L1Sender__init(distribution, rewardTokenConfig, depositTokenConfig); await distribution.Distribution_init(stETH, l1Sender, config.pools || []); diff --git a/deploy/3_init_bridge.migration.ts b/deploy/3_init_bridge.migration.ts index e4c9803..6b52653 100644 --- a/deploy/3_init_bridge.migration.ts +++ b/deploy/3_init_bridge.migration.ts @@ -24,22 +24,17 @@ module.exports = async function (deployer: Deployer) { lzEndpointL2 = await lzEndpointL2Mock.getAddress(); } - const l2MessageReceiver = await deployer.deployed( - L2MessageReceiver__factory, - // '0xc37fF39e5A50543AD01E42C4Cd88c2939dD13002', - ); + const l2MessageReceiver = await deployer.deployed(L2MessageReceiver__factory, 'L2MessageReceiver Proxy'); - const l1SenderAddress = (await deployer.deployed(L1Sender__factory)).address; - // const l1SenderAddress = '0xEec0DF0991458274fF0ede917E9827fFc67a8332'; + const l1Sender = await deployer.deployed(L1Sender__factory, 'L1Sender Proxy'); - const morAddress = (await deployer.deployed(MOR__factory)).address; - // const morAddress = '0x26BCDEb3E4e7EDf5657daF543132cAF792728908'; + const mor = await deployer.deployed(MOR__factory); const l2MessageReceiverConfig: IL2MessageReceiver.ConfigStruct = { gateway: lzEndpointL2, - sender: l1SenderAddress, + sender: l1Sender, senderChainId: config.chainsConfig.senderChainId, }; - await l2MessageReceiver.setParams(morAddress, l2MessageReceiverConfig); + await l2MessageReceiver.setParams(mor, l2MessageReceiverConfig); }; diff --git a/deploy/helpers/config-parser.ts b/deploy/helpers/config-parser.ts index ffe1b01..840e6e6 100644 --- a/deploy/helpers/config-parser.ts +++ b/deploy/helpers/config-parser.ts @@ -38,7 +38,7 @@ type PoolInitInfo = IDistribution.PoolStruct & { amounts: BigNumberish[]; }; -export function parseConfig(configPath: string = 'deploy/data/config_goerli.json'): Config { +export function parseConfig(configPath: string = 'deploy/data/config.json'): Config { const config: Config = JSON.parse(readFileSync(configPath, 'utf-8')) as Config; if (config.cap == undefined) { diff --git a/test/Distribution.test.ts b/test/Distribution.test.ts index 6fbe153..b9b92bd 100644 --- a/test/Distribution.test.ts +++ b/test/Distribution.test.ts @@ -8,6 +8,7 @@ import { Distribution__factory, GatewayRouterMock, IDistribution, + IL1Sender, L1Sender, L2MessageReceiver, L2TokenReceiver, @@ -141,25 +142,26 @@ describe('Distribution', () => { sqrtPriceLimitX96: 0, }); - const l1SenderProxy = await ERC1967ProxyFactory.deploy(l1SenderImplementation, '0x'); - l1Sender = l1SenderFactory.attach(l1SenderProxy) as L1Sender; - await l1Sender.L1Sender__init(); - await l1Sender.setDepositTokenConfig({ - token: wstETH, - gateway: gatewayRouter, - receiver: l2TokenReceiver, - }); - await l1Sender.setRewardTokenConfig({ - gateway: lZEndpointMockSender, - receiver: l2MessageReceiver, - receiverChainId: receiverChainId, - }); - // START deploy distribution contract const distributionProxy = await ERC1967ProxyFactory.deploy(await distributionImplementation.getAddress(), '0x'); distribution = distributionFactory.attach(await distributionProxy.getAddress()) as Distribution; // END + const rewardTokenConfig: IL1Sender.RewardTokenConfigStruct = { + gateway: lZEndpointMockSender, + receiver: l2MessageReceiver, + receiverChainId: receiverChainId, + }; + const depositTokenConfig: IL1Sender.DepositTokenConfigStruct = { + token: wstETH, + gateway: gatewayRouter, + receiver: l2TokenReceiver, + }; + + const l1SenderProxy = await ERC1967ProxyFactory.deploy(l1SenderImplementation, '0x'); + l1Sender = l1SenderFactory.attach(l1SenderProxy) as L1Sender; + await l1Sender.L1Sender__init(distribution, rewardTokenConfig, depositTokenConfig); + // Deploy reward token rewardToken = await MORFactory.deploy(wei(1000000000)); rewardToken.transferOwnership(l2MessageReceiver); @@ -256,6 +258,15 @@ describe('Distribution', () => { const poolData: IDistribution.PoolStruct = await distribution.pools(0); expect(_comparePoolStructs(pool, poolData)).to.be.true; }); + it('should correctly pool with constant reward', async () => { + const pool = getDefaultPool(); + pool.rewardDecrease = 0; + + await distribution.createPool(pool); + + const poolData: IDistribution.PoolStruct = await distribution.pools(0); + expect(_comparePoolStructs(pool, poolData)).to.be.true; + }); describe('should revert if try to create pool with incorrect data', () => { it('if `payoutStart == 0`', async () => { diff --git a/test/L1Sender.test.ts b/test/L1Sender.test.ts index 4aa4f0f..c4a0dff 100644 --- a/test/L1Sender.test.ts +++ b/test/L1Sender.test.ts @@ -4,6 +4,7 @@ import { ethers } from 'hardhat'; import { GatewayRouterMock, + IL1Sender, L1Sender, L1SenderV2, L2MessageReceiver, @@ -86,19 +87,20 @@ describe('L1Sender', () => { l2MessageReceiver = L2MessageReceiver.attach(l2MessageReceiverProxy) as L2MessageReceiver; await l2MessageReceiver.L2MessageReceiver__init(); - const l1SenderProxy = await ERC1967ProxyFactory.deploy(l1SenderImplementation, '0x'); - l1Sender = L1Sender.attach(l1SenderProxy) as L1Sender; - await l1Sender.L1Sender__init(); - await l1Sender.setDepositTokenConfig({ - token: depositToken, - gateway: gatewayRouter, - receiver: SECOND, - }); - await l1Sender.setRewardTokenConfig({ + const rewardTokenConfig: IL1Sender.RewardTokenConfigStruct = { gateway: lZEndpointMockL1, receiver: l2MessageReceiver, receiverChainId: receiverChainId, - }); + }; + const depositTokenConfig: IL1Sender.DepositTokenConfigStruct = { + token: depositToken, + gateway: gatewayRouter, + receiver: SECOND, + }; + + const l1SenderProxy = await ERC1967ProxyFactory.deploy(l1SenderImplementation, '0x'); + l1Sender = L1Sender.attach(l1SenderProxy) as L1Sender; + await l1Sender.L1Sender__init(OWNER, rewardTokenConfig, depositTokenConfig); await l2MessageReceiver.setParams(rewardToken, { gateway: lZEndpointMockL2, @@ -122,7 +124,36 @@ describe('L1Sender', () => { it('should revert if try to call init function twice', async () => { const reason = 'Initializable: contract is already initialized'; - await expect(l1Sender.L1Sender__init()).to.be.rejectedWith(reason); + const rewardTokenConfig: IL1Sender.RewardTokenConfigStruct = { + gateway: lZEndpointMockL1, + receiver: l2MessageReceiver, + receiverChainId: receiverChainId, + }; + const depositTokenConfig: IL1Sender.DepositTokenConfigStruct = { + token: depositToken, + gateway: gatewayRouter, + receiver: SECOND, + }; + + await expect(l1Sender.L1Sender__init(OWNER, rewardTokenConfig, depositTokenConfig)).to.be.rejectedWith(reason); + }); + it('should setup config', async () => { + expect(await l1Sender.distribution()).to.be.equal(await OWNER.getAddress()); + + expect(await l1Sender.rewardTokenConfig()).to.be.deep.equal([ + await lZEndpointMockL1.getAddress(), + await l2MessageReceiver.getAddress(), + receiverChainId, + ]); + + expect(await l1Sender.depositTokenConfig()).to.be.deep.equal([ + await depositToken.getAddress(), + await gatewayRouter.getAddress(), + await SECOND.getAddress(), + ]); + + expect(await unwrappedToken.allowance(l1Sender, depositToken)).to.be.equal(ethers.MaxUint256); + expect(await depositToken.allowance(l1Sender, gatewayRouter)).to.be.equal(ethers.MaxUint256); }); }); @@ -145,12 +176,32 @@ describe('L1Sender', () => { }); }); + describe('setDistribution', () => { + it('should set distribution', async () => { + await l1Sender.setDistribution(SECOND); + expect(await l1Sender.distribution()).to.be.equal(await SECOND.getAddress()); + }); + it('should revert if not called by the owner', async () => { + await expect(l1Sender.connect(SECOND).setDistribution(SECOND)).to.be.revertedWith( + 'Ownable: caller is not the owner', + ); + }); + }); + describe('setRewardTokenConfig', () => { - it('check config', async () => { + it('should set new config', async () => { + const newConfig = { + gateway: l2MessageReceiver, + receiver: lZEndpointMockL1, + receiverChainId: 0, + }; + + await l1Sender.setRewardTokenConfig(newConfig); + expect(await l1Sender.rewardTokenConfig()).to.be.deep.equal([ - await lZEndpointMockL1.getAddress(), await l2MessageReceiver.getAddress(), - receiverChainId, + await lZEndpointMockL1.getAddress(), + 0, ]); }); it('should revert if not called by the owner', async () => { @@ -165,16 +216,6 @@ describe('L1Sender', () => { }); describe('setDepositTokenConfig', () => { - it('check config', async () => { - expect(await l1Sender.depositTokenConfig()).to.be.deep.equal([ - await depositToken.getAddress(), - await gatewayRouter.getAddress(), - await SECOND.getAddress(), - ]); - - expect(await unwrappedToken.allowance(l1Sender, depositToken)).to.be.equal(ethers.MaxUint256); - expect(await depositToken.allowance(l1Sender, gatewayRouter)).to.be.equal(ethers.MaxUint256); - }); it('should reset allowances when token and gateway changed', async () => { const [WStETHMock, GatewayRouterMock, StETHMock] = await Promise.all([ ethers.getContractFactory('WStETHMock'), @@ -260,6 +301,24 @@ describe('L1Sender', () => { expect(await unwrappedToken.allowance(l1Sender, depositToken)).to.be.equal(ethers.MaxUint256); expect(await depositToken.allowance(l1Sender, newGatewayRouter)).to.be.equal(ethers.MaxUint256); }); + it('should not change allowances when only receiver changed', async () => { + const newConfig = { + token: depositToken, + gateway: gatewayRouter, + receiver: SECOND, + }; + + await l1Sender.setDepositTokenConfig(newConfig); + + expect(await l1Sender.depositTokenConfig()).to.be.deep.equal([ + await depositToken.getAddress(), + await gatewayRouter.getAddress(), + await SECOND.getAddress(), + ]); + + expect(await unwrappedToken.allowance(l1Sender, depositToken)).to.be.equal(ethers.MaxUint256); + expect(await depositToken.allowance(l1Sender, gatewayRouter)).to.be.equal(ethers.MaxUint256); + }); it('should revert if not called by the owner', async () => { await expect( l1Sender.connect(OWNER).setDepositTokenConfig({ @@ -299,7 +358,7 @@ describe('L1Sender', () => { it('should revert if not called by the owner', async () => { await expect( l1Sender.connect(SECOND).sendMintMessage(SECOND, '999', OWNER, { value: ethers.parseEther('0.1') }), - ).to.be.revertedWith('Ownable: caller is not the owner'); + ).to.be.revertedWith('L1S: invalid sender'); }); it('should not revert if not L2MessageReceiver sender', async () => { await l2MessageReceiver.setParams(rewardToken, { diff --git a/test/fork/L1Sender.fork.test.ts b/test/fork/L1Sender.fork.test.ts index 4cf6366..93bb8a0 100644 --- a/test/fork/L1Sender.fork.test.ts +++ b/test/fork/L1Sender.fork.test.ts @@ -7,6 +7,7 @@ import { Reverter } from '../helpers/reverter'; import { IGatewayRouter, IGatewayRouter__factory, + IL1Sender, IStETH, IStETH__factory, IWStETH, @@ -54,20 +55,21 @@ describe('L1Sender Fork', () => { ethers.getContractFactory('L1Sender', OWNER), ]); - const l1SenderImplementation = await L1Sender.deploy(); - const l1SenderProxy = await ERC1967ProxyFactory.deploy(l1SenderImplementation, '0x'); - l1Sender = L1Sender.attach(l1SenderProxy) as L1Sender; - l1Sender.L1Sender__init(); - await l1Sender.setDepositTokenConfig({ - token: wsteth, - gateway: arbitrumBridgeGatewayRouter, - receiver: SECOND, - }); - await l1Sender.setRewardTokenConfig({ + const rewardTokenConfig: IL1Sender.RewardTokenConfigStruct = { gateway: lzEndpointAddress, receiver: SECOND, receiverChainId: 110, - }); + }; + const depositTokenConfig: IL1Sender.DepositTokenConfigStruct = { + token: wsteth, + gateway: arbitrumBridgeGatewayRouter, + receiver: SECOND, + }; + + const l1SenderImplementation = await L1Sender.deploy(); + const l1SenderProxy = await ERC1967ProxyFactory.deploy(l1SenderImplementation, '0x'); + l1Sender = L1Sender.attach(l1SenderProxy) as L1Sender; + await l1Sender.L1Sender__init(OWNER, rewardTokenConfig, depositTokenConfig); await reverter.snapshot(); }); From 1bf6bea420423ffd56115beca3cdb210a143c419 Mon Sep 17 00:00:00 2001 From: RuslanProgrammer Date: Wed, 3 Jan 2024 15:43:04 +0100 Subject: [PATCH 2/6] added deploy all script --- deploy/deploy-all.ts | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 deploy/deploy-all.ts diff --git a/deploy/deploy-all.ts b/deploy/deploy-all.ts new file mode 100644 index 0000000..d4f6256 --- /dev/null +++ b/deploy/deploy-all.ts @@ -0,0 +1,16 @@ +import * as hre from 'hardhat'; + +async function main() { + const [networkL1, networkL2] = ['localhost', 'localhost']; + const verifyL1 = networkL1 !== 'localhost'; + const verifyL2 = networkL2 !== 'localhost'; + + await hre.run('migrate', { network: networkL1, verify: verifyL1, only: 1 }); + await hre.run('migrate', { network: networkL2, verify: verifyL2, only: 2, continue: true }); + await hre.run('migrate', { network: networkL1, verify: verifyL1, only: 3, continue: true }); +} + +main().catch((error) => { + console.error(error); + process.exitCode = 1; +}); From 9dbdc63e8c7b3506f4f09f6ebb1c535c64a74824 Mon Sep 17 00:00:00 2001 From: RuslanProgrammer Date: Wed, 3 Jan 2024 18:05:24 +0100 Subject: [PATCH 3/6] added config parser --- deploy/1_bridge.migration.ts | 2 +- deploy/2_token.migration.ts | 2 +- deploy/3_init_bridge.migration.ts | 2 +- deploy/helpers/config-parser.ts | 14 +++++++++++++- 4 files changed, 16 insertions(+), 4 deletions(-) diff --git a/deploy/1_bridge.migration.ts b/deploy/1_bridge.migration.ts index 4a90f20..6ec5a24 100644 --- a/deploy/1_bridge.migration.ts +++ b/deploy/1_bridge.migration.ts @@ -15,7 +15,7 @@ import { import { IL2TokenReceiver } from '@/generated-types/ethers/contracts/L2TokenReceiver'; module.exports = async function (deployer: Deployer) { - const config = parseConfig(); + const config = parseConfig(await deployer.getChainId()); let WStETH: string; let swapRouter: string; diff --git a/deploy/2_token.migration.ts b/deploy/2_token.migration.ts index e1f9385..51d940f 100644 --- a/deploy/2_token.migration.ts +++ b/deploy/2_token.migration.ts @@ -15,7 +15,7 @@ import { IL1Sender } from '@/generated-types/ethers/contracts/L1Sender'; import { ETHER_ADDR } from '@/scripts/utils/constants'; module.exports = async function (deployer: Deployer) { - const config = parseConfig(); + const config = parseConfig(await deployer.getChainId()); let stETH: string; let wStEth: string; diff --git a/deploy/3_init_bridge.migration.ts b/deploy/3_init_bridge.migration.ts index 6b52653..be257fa 100644 --- a/deploy/3_init_bridge.migration.ts +++ b/deploy/3_init_bridge.migration.ts @@ -11,7 +11,7 @@ import { import { IL2MessageReceiver } from '@/generated-types/ethers/contracts/L2MessageReceiver'; module.exports = async function (deployer: Deployer) { - const config = parseConfig(); + const config = parseConfig(await deployer.getChainId()); let lzEndpointL2: string; if (config.lzConfig) { diff --git a/deploy/helpers/config-parser.ts b/deploy/helpers/config-parser.ts index 840e6e6..ea1e017 100644 --- a/deploy/helpers/config-parser.ts +++ b/deploy/helpers/config-parser.ts @@ -38,7 +38,19 @@ type PoolInitInfo = IDistribution.PoolStruct & { amounts: BigNumberish[]; }; -export function parseConfig(configPath: string = 'deploy/data/config.json'): Config { +export function parseConfig(chainId: bigint): Config { + let configPath: string; + + if (chainId === 31337n) { + configPath = `deploy/data/config.json`; + } else if (chainId === 5n || chainId === 421613n) { + configPath = `deploy/data/config-goerli.json`; + } else if (chainId === 11155111n || chainId === 421614n) { + configPath = `deploy/data/config-sepolia.json`; + } else { + throw new Error(`Invalid chainId`); + } + const config: Config = JSON.parse(readFileSync(configPath, 'utf-8')) as Config; if (config.cap == undefined) { From 5cdf017756e8a49bfef1f06706017c9a224bdedf Mon Sep 17 00:00:00 2001 From: RuslanProgrammer Date: Wed, 3 Jan 2024 20:56:27 +0100 Subject: [PATCH 4/6] fixed deploy all --- deploy/1_bridge.migration.ts | 7 ++++++- deploy/2_token.migration.ts | 3 ++- deploy/3_init_bridge.migration.ts | 11 +++++++---- deploy/data/config_goerli.json | 4 ++-- deploy/data/config_sepolia.json | 4 ++-- deploy/deploy-all.sh | 9 +++++++++ deploy/deploy-all.ts | 16 ---------------- deploy/helpers/config-parser.ts | 4 ++-- 8 files changed, 30 insertions(+), 28 deletions(-) create mode 100755 deploy/deploy-all.sh delete mode 100644 deploy/deploy-all.ts diff --git a/deploy/1_bridge.migration.ts b/deploy/1_bridge.migration.ts index 6ec5a24..b28d1d2 100644 --- a/deploy/1_bridge.migration.ts +++ b/deploy/1_bridge.migration.ts @@ -1,4 +1,4 @@ -import { Deployer, Reporter } from '@solarity/hardhat-migrate'; +import { Deployer, Reporter, UserStorage } from '@solarity/hardhat-migrate'; import { parseConfig } from './helpers/config-parser'; @@ -41,6 +41,7 @@ module.exports = async function (deployer: Deployer) { } const MOR = await deployer.deploy(MOR__factory, [config.cap]); + if (!UserStorage.has('MOR')) UserStorage.set('MOR', await MOR.getAddress()); const swapParams: IL2TokenReceiver.SwapParamsStruct = { tokenIn: WStETH, @@ -53,6 +54,8 @@ module.exports = async function (deployer: Deployer) { const l2TokenReceiverProxy = await deployer.deploy(ERC1967Proxy__factory, [l2TokenReceiverImpl, '0x'], { name: 'L2TokenReceiver Proxy', }); + if (!UserStorage.has('L2TokenReceiver Proxy')) + UserStorage.set('L2TokenReceiver Proxy', await l2TokenReceiverProxy.getAddress()); const l2TokenReceiver = L2TokenReceiver__factory.connect( await l2TokenReceiverProxy.getAddress(), await deployer.getSigner(), @@ -63,6 +66,8 @@ module.exports = async function (deployer: Deployer) { const l2MessageReceiverProxy = await deployer.deploy(ERC1967Proxy__factory, [l2MessageReceiverImpl, '0x'], { name: 'L2MessageReceiver Proxy', }); + if (!UserStorage.has('L2MessageReceiver Proxy')) + UserStorage.set('L2MessageReceiver Proxy', await l2MessageReceiverProxy.getAddress()); const l2MessageReceiver = L2MessageReceiver__factory.connect( await l2MessageReceiverProxy.getAddress(), await deployer.getSigner(), diff --git a/deploy/2_token.migration.ts b/deploy/2_token.migration.ts index 51d940f..1160e47 100644 --- a/deploy/2_token.migration.ts +++ b/deploy/2_token.migration.ts @@ -1,4 +1,4 @@ -import { Deployer, Reporter } from '@solarity/hardhat-migrate'; +import { Deployer, Reporter, UserStorage } from '@solarity/hardhat-migrate'; import { parseConfig } from './helpers/config-parser'; @@ -71,6 +71,7 @@ module.exports = async function (deployer: Deployer) { const l1SenderProxy = await deployer.deploy(ERC1967Proxy__factory, [l1SenderImpl, '0x'], { name: 'L1Sender Proxy', }); + if (!UserStorage.has('L1Sender Proxy')) UserStorage.set('L1Sender Proxy', await l1SenderProxy.getAddress()); const l1Sender = L1Sender__factory.connect(await l1SenderProxy.getAddress(), await deployer.getSigner()); await l1Sender.L1Sender__init(distribution, rewardTokenConfig, depositTokenConfig); diff --git a/deploy/3_init_bridge.migration.ts b/deploy/3_init_bridge.migration.ts index be257fa..9d4561c 100644 --- a/deploy/3_init_bridge.migration.ts +++ b/deploy/3_init_bridge.migration.ts @@ -1,4 +1,4 @@ -import { Deployer } from '@solarity/hardhat-migrate'; +import { Deployer, UserStorage } from '@solarity/hardhat-migrate'; import { parseConfig } from './helpers/config-parser'; @@ -24,11 +24,14 @@ module.exports = async function (deployer: Deployer) { lzEndpointL2 = await lzEndpointL2Mock.getAddress(); } - const l2MessageReceiver = await deployer.deployed(L2MessageReceiver__factory, 'L2MessageReceiver Proxy'); + const l2MessageReceiver = L2MessageReceiver__factory.connect( + UserStorage.get('L2MessageReceiver Proxy'), + await deployer.getSigner(), + ); - const l1Sender = await deployer.deployed(L1Sender__factory, 'L1Sender Proxy'); + const l1Sender = L1Sender__factory.connect(UserStorage.get('L1Sender Proxy'), await deployer.getSigner()); - const mor = await deployer.deployed(MOR__factory); + const mor = MOR__factory.connect(UserStorage.get('MOR'), await deployer.getSigner()); const l2MessageReceiverConfig: IL2MessageReceiver.ConfigStruct = { gateway: lzEndpointL2, diff --git a/deploy/data/config_goerli.json b/deploy/data/config_goerli.json index b296b04..614909d 100644 --- a/deploy/data/config_goerli.json +++ b/deploy/data/config_goerli.json @@ -6,7 +6,7 @@ }, "pools": [ { - "payoutStart": 1703618736, + "payoutStart": 1735925178, "decreaseInterval": 86400, "withdrawLockPeriod": 120, "claimLockPeriod": 60, @@ -16,7 +16,7 @@ "isPublic": true }, { - "payoutStart": 1703618736, + "payoutStart": 1735925178, "decreaseInterval": 60, "withdrawLockPeriod": 1, "claimLockPeriod": 1, diff --git a/deploy/data/config_sepolia.json b/deploy/data/config_sepolia.json index ba83d7d..9f7a1a0 100644 --- a/deploy/data/config_sepolia.json +++ b/deploy/data/config_sepolia.json @@ -6,7 +6,7 @@ }, "pools": [ { - "payoutStart": 1703672149, + "payoutStart": 1704309630, "decreaseInterval": 86400, "withdrawLockPeriod": 120, "claimLockPeriod": 60, @@ -16,7 +16,7 @@ "isPublic": true }, { - "payoutStart": 1703672149, + "payoutStart": 1704309630, "decreaseInterval": 60, "withdrawLockPeriod": 1, "claimLockPeriod": 1, diff --git a/deploy/deploy-all.sh b/deploy/deploy-all.sh new file mode 100755 index 0000000..15372bc --- /dev/null +++ b/deploy/deploy-all.sh @@ -0,0 +1,9 @@ +#!/bin/bash +set -e + +verifyL1=$([ '$1' = 'localhost' ] && echo --verify || echo '') +verifyL2=$([ '$2' = 'localhost' ] && echo --verify || echo '') + +npx hardhat migrate --network $2 --only 1 $verifyL2 $3 +npx hardhat migrate --network $1 --only 2 $verifyL1 --continue +npx hardhat migrate --network $2 --only 3 $verifyL2 --continue diff --git a/deploy/deploy-all.ts b/deploy/deploy-all.ts deleted file mode 100644 index d4f6256..0000000 --- a/deploy/deploy-all.ts +++ /dev/null @@ -1,16 +0,0 @@ -import * as hre from 'hardhat'; - -async function main() { - const [networkL1, networkL2] = ['localhost', 'localhost']; - const verifyL1 = networkL1 !== 'localhost'; - const verifyL2 = networkL2 !== 'localhost'; - - await hre.run('migrate', { network: networkL1, verify: verifyL1, only: 1 }); - await hre.run('migrate', { network: networkL2, verify: verifyL2, only: 2, continue: true }); - await hre.run('migrate', { network: networkL1, verify: verifyL1, only: 3, continue: true }); -} - -main().catch((error) => { - console.error(error); - process.exitCode = 1; -}); diff --git a/deploy/helpers/config-parser.ts b/deploy/helpers/config-parser.ts index ea1e017..db73884 100644 --- a/deploy/helpers/config-parser.ts +++ b/deploy/helpers/config-parser.ts @@ -44,9 +44,9 @@ export function parseConfig(chainId: bigint): Config { if (chainId === 31337n) { configPath = `deploy/data/config.json`; } else if (chainId === 5n || chainId === 421613n) { - configPath = `deploy/data/config-goerli.json`; + configPath = `deploy/data/config_goerli.json`; } else if (chainId === 11155111n || chainId === 421614n) { - configPath = `deploy/data/config-sepolia.json`; + configPath = `deploy/data/config_sepolia.json`; } else { throw new Error(`Invalid chainId`); } From 3be724700a2c17b610b6bb5076db46e5b8f956ca Mon Sep 17 00:00:00 2001 From: RuslanProgrammer Date: Thu, 4 Jan 2024 11:57:45 +0100 Subject: [PATCH 5/6] fixed token bridge --- contracts/Distribution.sol | 2 +- contracts/L1Sender.sol | 4 ++-- deploy/2_token.migration.ts | 5 ++--- deploy/data/config_sepolia.json | 8 ++++---- 4 files changed, 9 insertions(+), 10 deletions(-) diff --git a/contracts/Distribution.sol b/contracts/Distribution.sol index 78cca71..bb7a71b 100644 --- a/contracts/Distribution.sol +++ b/contracts/Distribution.sol @@ -315,7 +315,7 @@ contract Distribution is IDistribution, OwnableUpgradeable, UUPSUpgradeable { IERC20(depositToken).safeTransfer(l1Sender, overplus_); - return L1Sender(l1Sender).sendDepositToken(gasLimit_, maxFeePerGas_, maxSubmissionCost_); + return L1Sender(l1Sender).sendDepositToken{value: msg.value}(gasLimit_, maxFeePerGas_, maxSubmissionCost_); } /**********************************************************************************************/ diff --git a/contracts/L1Sender.sol b/contracts/L1Sender.sol index 530ad67..a10fe12 100644 --- a/contracts/L1Sender.sol +++ b/contracts/L1Sender.sol @@ -81,11 +81,11 @@ contract L1Sender is IL1Sender, ERC165, OwnableUpgradeable, UUPSUpgradeable { bool isAllowedChanged_ = (oldToken_ != newToken_) || (oldGateway_ != newGateway_); if (oldGateway_ != address(0) && isAllowedChanged_) { - IERC20(oldToken_).approve(oldGateway_, 0); + IERC20(oldToken_).approve(IGatewayRouter(oldGateway_).getGateway(oldToken_), 0); } if (isAllowedChanged_) { - IERC20(newToken_).approve(newGateway_, type(uint256).max); + IERC20(newToken_).approve(IGatewayRouter(newGateway_).getGateway(newToken_), type(uint256).max); } } diff --git a/deploy/2_token.migration.ts b/deploy/2_token.migration.ts index 1160e47..8f4f460 100644 --- a/deploy/2_token.migration.ts +++ b/deploy/2_token.migration.ts @@ -6,7 +6,6 @@ import { Distribution__factory, ERC1967Proxy__factory, L1Sender__factory, - L2MessageReceiver__factory, LZEndpointMock__factory, StETHMock__factory, WStETHMock__factory, @@ -58,13 +57,13 @@ module.exports = async function (deployer: Deployer) { const rewardTokenConfig: IL1Sender.RewardTokenConfigStruct = { gateway: lzEndpointL1, - receiver: await deployer.deployed(L2MessageReceiver__factory, 'L2MessageReceiver Proxy'), + receiver: UserStorage.get('L2MessageReceiver Proxy'), receiverChainId: config.chainsConfig.receiverChainId, }; const depositTokenConfig: IL1Sender.DepositTokenConfigStruct = { token: wStEth, gateway: arbitrumBridgeGatewayRouter, - receiver: await deployer.deployed(L2MessageReceiver__factory, 'L2MessageReceiver Proxy'), + receiver: UserStorage.get('L2TokenReceiver Proxy'), }; const l1SenderImpl = await deployer.deploy(L1Sender__factory); diff --git a/deploy/data/config_sepolia.json b/deploy/data/config_sepolia.json index 9f7a1a0..b41fe6f 100644 --- a/deploy/data/config_sepolia.json +++ b/deploy/data/config_sepolia.json @@ -6,23 +6,23 @@ }, "pools": [ { - "payoutStart": 1704309630, + "payoutStart": 1704360948, "decreaseInterval": 86400, "withdrawLockPeriod": 120, "claimLockPeriod": 60, "initialReward": "14400000000000000000000", "rewardDecrease": "2468994701000000000", - "minimalStake": "1000000000000000", + "minimalStake": "10000000000", "isPublic": true }, { - "payoutStart": 1704309630, + "payoutStart": 1704360948, "decreaseInterval": 60, "withdrawLockPeriod": 1, "claimLockPeriod": 1, "initialReward": "100000000000000000000", "rewardDecrease": "100000000000000000000", - "minimalStake": "1000000000000000", + "minimalStake": "10000000000", "isPublic": false, "whitelistedUsers": [ "0x901F2d23823730fb7F2356920e0E273EFdCdFe17", From 7e91ee14a4506a8e87278b97ab03009c173238fd Mon Sep 17 00:00:00 2001 From: RuslanProgrammer Date: Fri, 5 Jan 2024 10:05:26 +0100 Subject: [PATCH 6/6] fixed tests --- contracts/mock/GatewayRouterMock.sol | 4 ++++ test/fork/L1Sender.fork.test.ts | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/contracts/mock/GatewayRouterMock.sol b/contracts/mock/GatewayRouterMock.sol index 534591f..185b417 100644 --- a/contracts/mock/GatewayRouterMock.sol +++ b/contracts/mock/GatewayRouterMock.sol @@ -16,4 +16,8 @@ contract GatewayRouterMock { return abi.encode(_token, _to, _amount, _maxGas, _gasPriceBid, _data); } + + function getGateway(address) external view returns (address) { + return address(this); + } } diff --git a/test/fork/L1Sender.fork.test.ts b/test/fork/L1Sender.fork.test.ts index 93bb8a0..be7467f 100644 --- a/test/fork/L1Sender.fork.test.ts +++ b/test/fork/L1Sender.fork.test.ts @@ -22,7 +22,7 @@ describe('L1Sender Fork', () => { let OWNER: SignerWithAddress; let SECOND: SignerWithAddress; - const arbitrumBridgeGatewayRouterAddress = '0x0F25c1DC2a9922304f2eac71DCa9B07E310e8E5a'; + const arbitrumBridgeGatewayRouterAddress = '0x72Ce9c846789fdB6fC1f34aC4AD25Dd9ef7031ef'; const lzEndpointAddress = '0x66A71Dcef29A0fFBDBE3c6a460a3B5BC225Cd675'; const stethAddress = '0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84'; const wstethAddress = '0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0';