-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1046 from yingjingyang/main
add LI.FI
- Loading branch information
Showing
19 changed files
with
565 additions
and
79 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
PRIVATE_KEY=yyyy | ||
INFURA_ID=zzzz |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
node_modules | ||
.env | ||
|
||
# Hardhat files | ||
/cache | ||
/artifacts | ||
|
||
# TypeChain files | ||
/typechain | ||
/typechain-types | ||
|
||
# solidity-coverage files | ||
/coverage | ||
/coverage.json | ||
|
||
deployment.json |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
# LI.FI 介绍 | ||
LI.FI 是一种跨链桥接聚合协议,通过聚合 Bridge, DEX, Solver 来支持 Token 在任意链之间转移,交易。 | ||
应用场景举例如下: | ||
1)Optim 上的 USDT 转移到 Polygon 上 | ||
2)Optim 上的 USDT 转移到 Polygon 上,同时将 USDT swap 为 USDC | ||
3)Optim 上的 USDT 转移到 Polygon 上,同时将 10% USDT 变为 Polygon 上原生的 gas ( Matic ),以便后续的操作。这个特性对 EVM 链和非 EVM 链来说非常便利,但目前只支持 4 个链 | ||
4)Optim 上的 USDT 转移到 Polygon 上的同时,调用 Polygon 链上的一个合约进行相应处理 | ||
|
||
LI.FI 的操作很简单,用户只需在 origin chain 上发起一笔交易即可完成上述这些场景。 | ||
同时为方便其他 Dapp 集成,LI.FI 提供了对应的 [SDK](https://docs.li.fi/integrate-li.fi-js-sdk/install-li.fi-sdk) 和 相应的前端 [UI components](https://docs.li.fi/integrate-li.fi-widget/li.fi-widget-overview) | ||
|
||
# 跨链测试 | ||
下面我们将使用 ARB 和 OP 这两个 Layer2 演示 USDT 跨链 | ||
- 软件要求 | ||
``` | ||
node 版本需要为 v20.11.0 | ||
``` | ||
|
||
- 安装依赖 | ||
``` | ||
npm install | ||
``` | ||
|
||
- 配置 env 文件 | ||
```shell | ||
cp .env.example .env | ||
## 之后在 .env 文件中配置对应的私钥和infura | ||
``` | ||
|
||
- 发起跨链请求 | ||
``` | ||
npx hardhat run scripts/1-crossChainTokenTransfer.js --network optim | ||
``` | ||
|
||
- 检查跨链结果 | ||
``` | ||
npx hardhat run scripts/2-checkTokenTransferStatus.js --network optim | ||
``` | ||
|
||
|
||
## 参考文档 | ||
- 官方文档: https://docs.li.fi/ | ||
- 合约仓库: https://github.com/lifinance/contracts/blob/main/docs/README.md |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
// SPDX-License-Identifier: MIT | ||
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol) | ||
|
||
pragma solidity ^0.8.20; | ||
|
||
/** | ||
* @dev Interface of the ERC-20 standard as defined in the ERC. | ||
*/ | ||
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 value of tokens in existence. | ||
*/ | ||
function totalSupply() external view returns (uint256); | ||
|
||
/** | ||
* @dev Returns the value of tokens owned by `account`. | ||
*/ | ||
function balanceOf(address account) external view returns (uint256); | ||
|
||
/** | ||
* @dev Moves a `value` amount of 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 value) 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 a `value` amount of tokens 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 value) external returns (bool); | ||
|
||
/** | ||
* @dev Moves a `value` amount of tokens from `from` to `to` using the | ||
* allowance mechanism. `value` 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 value) external returns (bool); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
require("@nomicfoundation/hardhat-toolbox"); | ||
require('dotenv').config(); | ||
|
||
/** @type import('hardhat/config').HardhatUserConfig */ | ||
// module.exports = { | ||
// solidity: "0.8.24", | ||
// }; | ||
|
||
|
||
const settings = { | ||
optimizer: { | ||
enabled: true, | ||
runs: 200, | ||
}, | ||
}; | ||
|
||
function mnemonic() { | ||
return [process.env.PRIVATE_KEY]; | ||
} | ||
|
||
/** | ||
* @type import('hardhat/config').HardhatUserConfig | ||
*/ | ||
module.exports = { | ||
solidity: { | ||
compilers: [ | ||
{ version: '0.8.4', settings }, | ||
{ version: '0.4.21', settings }, | ||
{ version: '0.8.24', settings }, | ||
], | ||
}, | ||
networks: { | ||
localhost: { | ||
url: 'http://localhost:8545', | ||
//gasPrice: 125000000000, // you can adjust gasPrice locally to see how much it will cost on production | ||
/* | ||
notice no mnemonic here? it will just use account 0 of the hardhat node to deploy | ||
(you can put in a mnemonic here to set the deployer locally) | ||
*/ | ||
}, | ||
mainnet: { | ||
url: 'https://mainnet.infura.io/v3/' + process.env.INFURA_ID, //<---- YOUR INFURA ID! (or it won't work) | ||
accounts: mnemonic(), | ||
}, | ||
matic: { | ||
url: 'https://polygon-mainnet.infura.io/v3/' + process.env.INFURA_ID, | ||
accounts: mnemonic() | ||
}, | ||
optim: { | ||
url: "https://optimism-mainnet.infura.io/v3/" + process.env.INFURA_ID, | ||
accounts: mnemonic() | ||
}, | ||
sepolia: { | ||
url: "https://sepolia.infura.io/v3/" + process.env.INFURA_ID, | ||
accounts: mnemonic() | ||
}, | ||
arbitrum: { | ||
url: "https://arbitrum-mainnet.infura.io/v3/" + process.env.INFURA_ID, | ||
accounts: mnemonic() | ||
}, | ||
scroll: { | ||
url: "https://rpc.scroll.io", | ||
accounts: mnemonic() | ||
}, | ||
optim_sepolia: { | ||
url: "https://optimism-sepolia.infura.io/v3/" + process.env.INFURA_ID, | ||
accounts: mnemonic() | ||
}, | ||
|
||
}, | ||
mocha: { | ||
timeout: 200000 | ||
}, | ||
sourcify: { | ||
enabled: true | ||
}, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
{ | ||
"name": "hardhat-project", | ||
"devDependencies": { | ||
"@nomicfoundation/hardhat-toolbox": "^4.0.0", | ||
"dotenv": "^16.4.5", | ||
"hardhat": "^2.21.0", | ||
"node-fetch": "^2.7.0" | ||
} | ||
} |
70 changes: 70 additions & 0 deletions
70
basic/80-crossChainTransfer/LI.FI/scripts/1-crossChainTokenTransfer.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
// We require the Hardhat Runtime Environment explicitly here. This is optional | ||
// but useful for running the script in a standalone fashion through `node <script>`. | ||
// | ||
// You can also run a script with `npx hardhat run <script>`. If you do that, Hardhat | ||
// will compile your contracts, add the Hardhat Runtime Environment's members to the | ||
// global scope, and execute the script. | ||
const {ethers} = require("hardhat"); | ||
require('dotenv').config(); | ||
|
||
const { | ||
saveRedpacketDeployment, | ||
} = require("../utils"); | ||
|
||
async function getQuote (fromChain, toChain, fromToken, toToken, fromAmount, slippage, fromAddress, toAddress) { | ||
const result = await request( | ||
"https://li.quest/v1/quote", | ||
{ | ||
fromChain, | ||
toChain, | ||
fromToken, | ||
toToken, | ||
fromAmount, | ||
slippage, | ||
fromAddress, | ||
toAddress, | ||
} | ||
) | ||
|
||
return result; | ||
} | ||
|
||
|
||
async function main() { | ||
const [deployer] = await ethers.getSigners(); | ||
const fromChain = 'OPT'; | ||
const fromToken = 'USDT'; | ||
const toChain = 'ARB'; | ||
const toToken = 'USDT'; | ||
const fromAmount = '1000000'; | ||
const slippage = 0.05; | ||
const fromAddress = deployer.address; | ||
const toAddress = deployer.address; | ||
const signer = await ethers.provider.getSigner() | ||
const OPUSDTaddress = "0x94b008aA00579c1307B0EF2c499aD98a8ce58e58" | ||
let quote = await getQuote(fromChain, toChain, fromToken, toToken, fromAmount, slippage,fromAddress,toAddress); | ||
console.log(quote.transactionRequest) | ||
|
||
// approve USDT | ||
const usdtContracct = await ethers.getContractAt('IERC20', OPUSDTaddress, deployer); | ||
let approveTx = await usdtContracct.approve(quote.transactionRequest.to, fromAmount); | ||
await approveTx.wait(); | ||
console.log(`Approve USDT to ${quote.transactionRequest.to} successfully`) | ||
|
||
// send cross chain transfer request | ||
let tx = await signer.sendTransaction(quote.transactionRequest) | ||
await tx.wait(); | ||
console.log("send request successfully") | ||
|
||
// save tx has | ||
saveRedpacketDeployment({ | ||
crossChainTxHash: tx.hash, | ||
}); | ||
} | ||
|
||
// We recommend this pattern to be able to use async/await everywhere | ||
// and properly handle errors. | ||
main().catch((error) => { | ||
console.error(error); | ||
process.exitCode = 1; | ||
}); |
65 changes: 65 additions & 0 deletions
65
basic/80-crossChainTransfer/LI.FI/scripts/2-checkTokenTransferStatus.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
// We require the Hardhat Runtime Environment explicitly here. This is optional | ||
// but useful for running the script in a standalone fashion through `node <script>`. | ||
// | ||
// You can also run a script with `npx hardhat run <script>`. If you do that, Hardhat | ||
// will compile your contracts, add the Hardhat Runtime Environment's members to the | ||
// global scope, and execute the script. | ||
const {ethers} = require("hardhat"); | ||
require('dotenv').config(); | ||
|
||
const { | ||
readRedpacketDeployment, | ||
getStatus, | ||
} = require("../utils"); | ||
|
||
async function getQuote (fromChain, toChain, fromToken, toToken, fromAmount, slippage, fromAddress, toAddress) { | ||
const result = await request( | ||
"https://li.quest/v1/quote", | ||
{ | ||
fromChain, | ||
toChain, | ||
fromToken, | ||
toToken, | ||
fromAmount, | ||
slippage, | ||
fromAddress, | ||
toAddress, | ||
} | ||
) | ||
|
||
return result; | ||
} | ||
|
||
|
||
async function main() { | ||
const [deployer] = await ethers.getSigners(); | ||
const fromChain = 'OPT'; | ||
const fromToken = 'USDT'; | ||
const toChain = 'ARB'; | ||
const toToken = 'USDT'; | ||
const fromAmount = '1000000'; | ||
const slippage = 0.03; | ||
const fromAddress = deployer.address; | ||
const toAddress = deployer.address; | ||
const signer = await ethers.provider.getSigner() | ||
const OPUSDTaddress = "0x94b008aA00579c1307B0EF2c499aD98a8ce58e58" | ||
let quote = await getQuote(fromChain, toChain, fromToken, toToken, fromAmount, slippage,fromAddress,toAddress); | ||
// console.log(quote.transactionRequest) | ||
|
||
const deployment = readRedpacketDeployment(); | ||
let txHash = deployment.crossChainTxHash | ||
// Waiting for the transfer to complete | ||
let result; | ||
do { | ||
result = await getStatus(quote.tool, fromChain, toChain, txHash); | ||
console.log(`Transfer status: ${result.status}`) | ||
} while (result.status !== 'DONE' && result.status !== 'FAILED') | ||
console.log(result) | ||
} | ||
|
||
// We recommend this pattern to be able to use async/await everywhere | ||
// and properly handle errors. | ||
main().catch((error) => { | ||
console.error(error); | ||
process.exitCode = 1; | ||
}); |
Oops, something went wrong.