From 30813ab9229bfe90bb61888b3b81b3a69d424841 Mon Sep 17 00:00:00 2001 From: nikolay Date: Thu, 19 Dec 2024 16:29:01 +0200 Subject: [PATCH] chore: add whbar example Signed-off-by: nikolay --- tools/layer-zero-example/.env.example | 14 +- tools/layer-zero-example/README.md | 24 +++ tools/layer-zero-example/contracts/WHBAR.sol | 72 +++++++++ tools/layer-zero-example/hardhat.config.js | 9 ++ tools/layer-zero-example/test/whbarTests.js | 151 +++++++++++++++++++ 5 files changed, 269 insertions(+), 1 deletion(-) create mode 100644 tools/layer-zero-example/contracts/WHBAR.sol create mode 100644 tools/layer-zero-example/test/whbarTests.js diff --git a/tools/layer-zero-example/.env.example b/tools/layer-zero-example/.env.example index 84a2e6b485..3d47c98e8a 100644 --- a/tools/layer-zero-example/.env.example +++ b/tools/layer-zero-example/.env.example @@ -26,6 +26,18 @@ ERC721_BSC_CONTRACT=0x ONFT_ADAPTER_HEDERA_CONTRACT=0x ONFT_ADAPTER_BSC_CONTRACT=0x -# OFT HTS config +# HTS Connector config HTS_CONNECTOR_HEDERA_CONTRACT=0x HTS_CONNECTOR_BSC_CONTRACT=0x + +# HTS Adapter config +HTS_ADAPTER_HTS_HEDERA_CONTRACT=0x +HTS_ADAPTER_ERC20_BSC_CONTRACT=0x +HTS_ADAPTER_HEDERA_CONTRACT=0x +HTS_ADAPTER_BSC_CONTRACT=0x + +# WHBAR config +WHBAR_HEDERA_CONTRACT=0x +WHBAR_BSC_CONTRACT=0x +WHBAR_HEDERA_ADAPTER_CONTRACT=0x +WHBAR_BSC_ADAPTER_CONTRACT=0x diff --git a/tools/layer-zero-example/README.md b/tools/layer-zero-example/README.md index d91f1a1ec3..cb256496be 100644 --- a/tools/layer-zero-example/README.md +++ b/tools/layer-zero-example/README.md @@ -149,3 +149,27 @@ wait a couple minutes, the LZ progress can be tracked on https://testnet.layerze npx hardhat test --grep "HTSAdapterTests @hedera @test" --network hedera_testnet npx hardhat test --grep "HTSAdapterTests @bsc @test" --network bsc_testnet + +### WHBAR flow + +npx hardhat deploy-whbar --network hedera_testnet +npx hardhat deploy-erc20 --decimals 8 --mint 100000000 --network bsc_testnet + +npx hardhat deploy-oft-adapter --token --network hedera_testnet +npx hardhat deploy-oft-adapter --token --network bsc_testnet + +npx hardhat set-peer --source --target --network hedera_testnet +npx hardhat set-peer --source --target --network bsc_testnet + +fill the .env + +npx hardhat test --grep "WHBARTests @hedera @deposit" --network hedera_testnet + +npx hardhat test --grep "WHBARTests @hedera @fund-and-approve" --network hedera_testnet +npx hardhat test --grep "WHBARTests @bsc @fund-and-approve" --network bsc_testnet + +npx hardhat test --grep "WHBARTests @hedera @send" --network hedera_testnet +npx hardhat test --grep "WHBARTests @bsc @send" --network bsc_testnet + +npx hardhat test --grep "WHBARTests @hedera @test" --network hedera_testnet +npx hardhat test --grep "WHBARTests @bsc @test" --network bsc_testnet diff --git a/tools/layer-zero-example/contracts/WHBAR.sol b/tools/layer-zero-example/contracts/WHBAR.sol new file mode 100644 index 0000000000..3e1c50331d --- /dev/null +++ b/tools/layer-zero-example/contracts/WHBAR.sol @@ -0,0 +1,72 @@ +// SPDX-License-Identifier: Apache-2.0 +pragma solidity ^0.8.22; + +contract WHBAR { + string public name = "Wrapped HBAR"; + string public symbol = "WHBAR"; + uint8 public decimals = 8; + + event Approval(address indexed src, address indexed guy, uint wad); + event Transfer(address indexed src, address indexed dst, uint wad); + event Deposit(address indexed dst, uint wad); + event Withdrawal(address indexed src, uint wad); + + mapping(address => uint) public balanceOf; + mapping(address => mapping(address => uint)) public allowance; + + fallback() external payable { + deposit(); + } + + receive() external payable { + deposit(); + } + + function deposit() public payable { + balanceOf[msg.sender] += msg.value; + + emit Deposit(msg.sender, msg.value); + } + + function withdraw(uint wad) public { + require(balanceOf[msg.sender] >= wad); + + balanceOf[msg.sender] -= wad; + payable(msg.sender).transfer(wad); + + emit Withdrawal(msg.sender, wad); + } + + function totalSupply() public view returns (uint) { + return address(this).balance; + } + + function approve(address guy, uint wad) public returns (bool) { + allowance[msg.sender][guy] = wad; + + emit Approval(msg.sender, guy, wad); + + return true; + } + + function transfer(address dst, uint wad) public returns (bool) { + return transferFrom(msg.sender, dst, wad); + } + + function transferFrom(address src, address dst, uint wad) public returns (bool) { + require(balanceOf[src] >= wad); + + if (src != msg.sender && allowance[src][msg.sender] != + type(uint256).max) { + require(allowance[src][msg.sender] >= wad); + allowance[src][msg.sender] -= wad; + } + + balanceOf[src] -= wad; + balanceOf[dst] += wad; + + emit Transfer(src, dst, wad); + + return true; + } +} \ No newline at end of file diff --git a/tools/layer-zero-example/hardhat.config.js b/tools/layer-zero-example/hardhat.config.js index 968ab832c0..e2118af85e 100644 --- a/tools/layer-zero-example/hardhat.config.js +++ b/tools/layer-zero-example/hardhat.config.js @@ -63,6 +63,15 @@ const getEndpointAddress = (network) => { return ENDPOINT_V2; } +task('deploy-whbar', "Deploy WHBAR") + .setAction(async (taskArgs, hre) => { + const contractFactory = await ethers.getContractFactory('WHBAR'); + const contract = await contractFactory.deploy(); + await contract.deployTransaction.wait(); + + console.log(`(${hre.network.name}) WHBAR to: ` + contract.address); + }); + task('deploy-erc20', "Deploy ERC20 token") .addParam('mint', 'Initial mint') .addParam('decimals', 'Decimals') diff --git a/tools/layer-zero-example/test/whbarTests.js b/tools/layer-zero-example/test/whbarTests.js new file mode 100644 index 0000000000..d816cda38a --- /dev/null +++ b/tools/layer-zero-example/test/whbarTests.js @@ -0,0 +1,151 @@ +/*- + * + * Hedera JSON RPC Relay - Hardhat Example + * + * Copyright (C) 2024 Hedera Hashgraph, LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +const hre = require('hardhat'); +const { ethers } = hre; +const { Options, addressToBytes32 } = require('@layerzerolabs/lz-v2-utilities'); +const { expect } = require('chai'); + +const HEDERA_EID = 40285; +const BSC_EID = 40102; +const receiverAddress = '0xF51c7a9407217911d74e91642dbC58F18E51Deac'; +const amount = '50000000'; + +describe.only('WHBARTests', function() { + it('@hedera @deposit 1 hbar', async () => { + const signers = await ethers.getSigners(); + const contract = await ethers.getContractAt('WHBAR', process.env.WHBAR_HEDERA_CONTRACT); + + const tx = await contract.deposit({ + value: '1000000000000000000' // 1 hbar + }); + await tx.wait(); + + expect(await contract.balanceOf(signers[0].address)).to.equal(100_000_000); + }); + + it('@hedera @fund-and-approve transfer to adapter', async () => { + const contractERC20 = await ethers.getContractAt('ERC20Mock', process.env.WHBAR_HEDERA_CONTRACT); + const transferTx = await contractERC20.transfer(process.env.WHBAR_HEDERA_ADAPTER_CONTRACT, amount); + const receipt = await transferTx.wait(); + expect(!!receipt.status).to.be.true; + }); + + it('@bsc @fund-and-approve transfer to adapter', async () => { + const contractERC20 = await ethers.getContractAt('ERC20Mock', process.env.WHBAR_BSC_CONTRACT); + const transferTx = await contractERC20.transfer(process.env.WHBAR_BSC_ADAPTER_CONTRACT, amount); + const receipt = await transferTx.wait(); + expect(!!receipt.status).to.be.true; + }); + + it('@hedera @fund-and-approve adapter approval', async () => { + const contractERC20 = await ethers.getContractAt('ERC20Mock', process.env.WHBAR_HEDERA_CONTRACT); + const approveTx = await contractERC20.approve(process.env.WHBAR_HEDERA_ADAPTER_CONTRACT, amount); + const receipt = await approveTx.wait(); + expect(!!receipt.status).to.be.true; + }); + + it('@bsc @fund-and-approve adapter approval', async () => { + const contractERC20 = await ethers.getContractAt('ERC20Mock', process.env.WHBAR_BSC_CONTRACT); + const approveTx = await contractERC20.approve(process.env.WHBAR_BSC_ADAPTER_CONTRACT, amount); + const receipt = await approveTx.wait(); + expect(!!receipt.status).to.be.true; + }); + + it('@hedera @send to bsc', async () => { + const signers = await ethers.getSigners(); + + const sendParam = { + dstEid: BSC_EID, + to: addressToBytes32(receiverAddress), + amountLD: amount, + minAmountLD: amount, + extraOptions: Options.newOptions().addExecutorLzReceiveOption(3000000, 0).toBytes(), + composeMsg: ethers.utils.arrayify('0x'), + oftCmd: ethers.utils.arrayify('0x') + }; + + const contract = await ethers.getContractAt('ExampleOFTAdapter', process.env.WHBAR_HEDERA_ADAPTER_CONTRACT); + const tx = await contract.send(sendParam, { nativeFee: '500000000', lzTokenFee: 0 }, signers[0].address, { + gasLimit: 10_000_000, + value: '5000000000000000000' + }); + + const receipt = await tx.wait(); + if (!receipt.status) { + process.exit(`Execution failed. Tx hash: ${tx.hash}`); + } + + console.log(`(${hre.network.name}) successfully sent to Bsc via tx: ${tx.hash}`); + }); + + it('@bsc @send to hedera', async () => { + const signers = await ethers.getSigners(); + + const sendParam = { + dstEid: HEDERA_EID, + to: addressToBytes32(receiverAddress), + amountLD: amount, + minAmountLD: amount, + extraOptions: Options.newOptions().addExecutorLzReceiveOption(3000000, 0).toBytes(), + composeMsg: ethers.utils.arrayify('0x'), + oftCmd: ethers.utils.arrayify('0x') + }; + + const contract = await ethers.getContractAt('ExampleOFTAdapter', process.env.WHBAR_BSC_ADAPTER_CONTRACT); + const tx = await contract.send(sendParam, { nativeFee: '1000000000000000', lzTokenFee: 0 }, signers[0].address, { + gasLimit: 1_000_000, + value: '1000000000000000' + }); + + const receipt = await tx.wait(); + if (!receipt.status) { + process.exit(`Execution failed. Tx hash: ${tx.hash}`); + } + + console.log(`(${hre.network.name}) successfully sent to Hedera via tx: ${tx.hash}`); + }); + + it('@hedera @test balance', async () => { + const signers = await ethers.getSigners(); + + const contractERC20 = await ethers.getContractAt('ERC20Mock', process.env.WHBAR_HEDERA_CONTRACT); + const receiverBalance = await contractERC20.balanceOf(receiverAddress); + + console.log(`(${hre.network.name}) signer balance: ${await contractERC20.balanceOf(signers[0].address)}`); + console.log(`(${hre.network.name}) adapter balance: ${await contractERC20.balanceOf(process.env.WHBAR_HEDERA_ADAPTER_CONTRACT)}`); + console.log(`(${hre.network.name}) receiver balance: ${receiverBalance}`); + + expect(receiverBalance).to.equal(amount); + }); + + it('@bsc @test balance', async () => { + const signers = await ethers.getSigners(); + + const contractERC20 = await ethers.getContractAt('ERC20Mock', process.env.WHBAR_BSC_CONTRACT); + const receiverBalance = await contractERC20.balanceOf(receiverAddress); + + console.log(`(${hre.network.name}) signer balance: ${await contractERC20.balanceOf(signers[0].address)}`); + console.log(`(${hre.network.name}) adapter balance: ${await contractERC20.balanceOf(process.env.WHBAR_BSC_ADAPTER_CONTRACT)}`); + console.log(`(${hre.network.name}) receiver balance: ${receiverBalance}`); + + expect(receiverBalance).to.equal(amount); + }); +});