-
Notifications
You must be signed in to change notification settings - Fork 53
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
8 changed files
with
617 additions
and
0 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,8 @@ | ||
{ | ||
"mainnet": { | ||
"chainflipVault": "0xF5e10380213880111522dd0efD3dbb45b9f62Bcc" | ||
}, | ||
"arbitrum": { | ||
"chainflipVault": "0x79001a5e762f3bEFC8e5871b42F6734e00498920" | ||
} | ||
} |
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,92 @@ | ||
# Chainflip Facet | ||
|
||
## How it works | ||
|
||
The Chainflip Facet works by ... | ||
|
||
```mermaid | ||
graph LR; | ||
D{LiFiDiamond}-- DELEGATECALL -->ChainflipFacet; | ||
ChainflipFacet -- CALL --> C(Chainflip) | ||
``` | ||
|
||
## Public Methods | ||
|
||
- `function startBridgeTokensViaChainflip(BridgeData calldata _bridgeData, ChainflipData calldata _chainflipData)` | ||
- Simply bridges tokens using chainflip | ||
- `swapAndStartBridgeTokensViaChainflip(BridgeData memory _bridgeData, LibSwap.SwapData[] calldata _swapData, chainflipData memory _chainflipData)` | ||
- Performs swap(s) before bridging tokens using chainflip | ||
|
||
## chainflip Specific Parameters | ||
|
||
The methods listed above take a variable labeled `_chainflipData`. This data is specific to chainflip and is represented as the following struct type: | ||
|
||
```solidity | ||
/// @param example Example parameter. | ||
struct chainflipData { | ||
string example; | ||
} | ||
``` | ||
|
||
## Swap Data | ||
|
||
Some methods accept a `SwapData _swapData` parameter. | ||
|
||
Swapping is performed by a swap specific library that expects an array of calldata to can be run on various DEXs (i.e. Uniswap) to make one or multiple swaps before performing another action. | ||
|
||
The swap library can be found [here](../src/Libraries/LibSwap.sol). | ||
|
||
## LiFi Data | ||
|
||
Some methods accept a `BridgeData _bridgeData` parameter. | ||
|
||
This parameter is strictly for analytics purposes. It's used to emit events that we can later track and index in our subgraphs and provide data on how our contracts are being used. `BridgeData` and the events we can emit can be found [here](../src/Interfaces/ILiFi.sol). | ||
|
||
## Getting Sample Calls to interact with the Facet | ||
|
||
In the following some sample calls are shown that allow you to retrieve a populated transaction that can be sent to our contract via your wallet. | ||
|
||
All examples use our [/quote endpoint](https://apidocs.li.fi/reference/get_quote) to retrieve a quote which contains a `transactionRequest`. This request can directly be sent to your wallet to trigger the transaction. | ||
|
||
The quote result looks like the following: | ||
|
||
```javascript | ||
const quoteResult = { | ||
id: '0x...', // quote id | ||
type: 'lifi', // the type of the quote (all lifi contract calls have the type "lifi") | ||
tool: 'chainflip', // the bridge tool used for the transaction | ||
action: {}, // information about what is going to happen | ||
estimate: {}, // information about the estimated outcome of the call | ||
includedSteps: [], // steps that are executed by the contract as part of this transaction, e.g. a swap step and a cross step | ||
transactionRequest: { | ||
// the transaction that can be sent using a wallet | ||
data: '0x...', | ||
to: '0x...', | ||
value: '0x00', | ||
from: '{YOUR_WALLET_ADDRESS}', | ||
chainId: 100, | ||
gasLimit: '0x...', | ||
gasPrice: '0x...', | ||
}, | ||
} | ||
``` | ||
|
||
A detailed explanation on how to use the /quote endpoint and how to trigger the transaction can be found [here](https://docs.li.fi/products/more-integration-options/li.fi-api/transferring-tokens-example). | ||
|
||
**Hint**: Don't forget to replace `{YOUR_WALLET_ADDRESS}` with your real wallet address in the examples. | ||
|
||
### Cross Only | ||
|
||
To get a transaction for a transfer from 30 USDC.e on Avalanche to USDC on Binance you can execute the following request: | ||
|
||
```shell | ||
curl 'https://li.quest/v1/quote?fromChain=AVA&fromAmount=30000000&fromToken=USDC&toChain=BSC&toToken=USDC&slippage=0.03&allowBridges=chainflip&fromAddress={YOUR_WALLET_ADDRESS}' | ||
``` | ||
|
||
### Swap & Cross | ||
|
||
To get a transaction for a transfer from 30 USDT on Avalanche to USDC on Binance you can execute the following request: | ||
|
||
```shell | ||
curl 'https://li.quest/v1/quote?fromChain=AVA&fromAmount=30000000&fromToken=USDT&toChain=BSC&toToken=USDC&slippage=0.03&allowBridges=chainflip&fromAddress={YOUR_WALLET_ADDRESS}' | ||
``` |
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,132 @@ | ||
import { getContract, parseUnits, Narrow, zeroAddress } from 'viem' | ||
import { randomBytes } from 'crypto' | ||
import dotenv from 'dotenv' | ||
import erc20Artifact from '../../out/ERC20/ERC20.sol/ERC20.json' | ||
import chainflipFacetArtifact from '../../out/ChainflipFacet.sol/ChainflipFacet.json' | ||
import { ChainflipFacet, ILiFi } from '../../typechain' | ||
import { SupportedChain } from './utils/demoScriptChainConfig' | ||
import { | ||
ensureBalance, | ||
ensureAllowance, | ||
executeTransaction, | ||
setupEnvironment, | ||
} from './utils/demoScriptHelpers' | ||
|
||
dotenv.config() | ||
|
||
// #region ABIs | ||
|
||
const ERC20_ABI = erc20Artifact.abi as Narrow<typeof erc20Artifact.abi> | ||
const CHAINFLIP_FACET_ABI = chainflipFacetArtifact.abi as Narrow< | ||
typeof chainflipFacetArtifact.abi | ||
> | ||
|
||
// #endregion | ||
|
||
dotenv.config() | ||
|
||
async function main() { | ||
// === Set up environment === | ||
const srcChain: SupportedChain = 'mainnet' // Set source chain | ||
const destinationChainId = 1 // Set destination chain id | ||
|
||
const { | ||
client, | ||
publicClient, | ||
walletAccount, | ||
lifiDiamondAddress, | ||
lifiDiamondContract, | ||
} = await setupEnvironment(srcChain, CHAINFLIP_FACET_ABI) | ||
const signerAddress = walletAccount.address | ||
|
||
// === Contract addresses === | ||
const SRC_TOKEN_ADDRESS = '' as `0x${string}` // Set the source token address here. | ||
|
||
// If you need to retrieve a specific address from your config file | ||
// based on the chain and element name, use this helper function. | ||
// | ||
// First, ensure you import the relevant config file: | ||
// import config from '../../config/chainflip.json' | ||
// | ||
// Then, retrieve the address: | ||
// const EXAMPLE_ADDRESS = getConfigElement(config, srcChain, 'example'); | ||
// | ||
|
||
// === Instantiate contracts === | ||
const srcTokenContract = getContract({ | ||
address: SRC_TOKEN_ADDRESS, | ||
abi: ERC20_ABI, | ||
client, | ||
}) | ||
|
||
// If you need to interact with a contract, use the following helper. | ||
// Provide the contract address, ABI, and a client instance to initialize | ||
// the contract for both read and write operations. | ||
// | ||
// const exampleContract = getContract({ | ||
// address: EXAMPLE_ADDRESS, | ||
// abi: EXAMPLE_ABI, | ||
// client | ||
// }); | ||
// | ||
|
||
const srcTokenName = (await srcTokenContract.read.name()) as string | ||
const srcTokenSymbol = (await srcTokenContract.read.symbol()) as string | ||
const srcTokenDecimals = (await srcTokenContract.read.decimals()) as bigint | ||
const amount = parseUnits('10', srcTokenDecimals) // 10 * 1e{source token decimals} | ||
|
||
console.info( | ||
`\nBridge ${amount} ${srcTokenName} (${srcTokenSymbol}) from ${srcChain} --> {DESTINATION CHAIN NAME}` | ||
) | ||
console.info(`Connected wallet address: ${signerAddress}`) | ||
|
||
await ensureBalance(srcTokenContract, signerAddress, amount) | ||
|
||
await ensureAllowance( | ||
srcTokenContract, | ||
signerAddress, | ||
lifiDiamondAddress, | ||
amount, | ||
publicClient | ||
) | ||
|
||
// === In this part put necessary logic usually it's fetching quotes, estimating fees, signing messages etc. === | ||
|
||
// === Prepare bridge data === | ||
const bridgeData: ILiFi.BridgeDataStruct = { | ||
// Edit fields as needed | ||
transactionId: `0x${randomBytes(32).toString('hex')}`, | ||
bridge: 'chainflip', | ||
integrator: 'ACME Devs', | ||
referrer: zeroAddress, | ||
sendingAssetId: SRC_TOKEN_ADDRESS, | ||
receiver: signerAddress, | ||
destinationChainId, | ||
minAmount: amount, | ||
hasSourceSwaps: false, | ||
hasDestinationCall: false, | ||
} | ||
|
||
const chainflipData: ChainflipFacet.ChainflipDataStruct = { | ||
// Add your specific fields for Chainflip here. | ||
} | ||
|
||
// === Start bridging === | ||
await executeTransaction( | ||
() => | ||
lifiDiamondContract.write.startBridgeTokensViaChainflip( | ||
[bridgeData, chainflipData] | ||
// { value: fee } optional value | ||
), | ||
'Starting bridge tokens via Chainflip', | ||
publicClient, | ||
true | ||
) | ||
} | ||
|
||
main() | ||
.then(() => process.exit(0)) | ||
.catch((error) => { | ||
console.error(error) | ||
process.exit(1) | ||
}) |
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,34 @@ | ||
// SPDX-License-Identifier: UNLICENSED | ||
pragma solidity ^0.8.17; | ||
|
||
import { DeployScriptBase } from "./utils/DeployScriptBase.sol"; | ||
import { stdJson } from "forge-std/Script.sol"; | ||
import { ChainflipFacet } from "lifi/Facets/ChainflipFacet.sol"; | ||
|
||
contract DeployScript is DeployScriptBase { | ||
using stdJson for string; | ||
|
||
constructor() DeployScriptBase("ChainflipFacet") {} | ||
|
||
function run() | ||
public | ||
returns (ChainflipFacet deployed, bytes memory constructorArgs) | ||
{ | ||
constructorArgs = getConstructorArgs(); | ||
|
||
deployed = ChainflipFacet(deploy(type(ChainflipFacet).creationCode)); | ||
} | ||
|
||
function getConstructorArgs() internal override returns (bytes memory) { | ||
// get path of chainflip config file | ||
string memory path = string.concat(root, "/config/chainflip.json"); | ||
|
||
// Read the Chainflip vault address from config | ||
address chainflipVault = _getConfigContractAddress( | ||
path, | ||
string.concat(".", network, ".chainflipVault") | ||
); | ||
|
||
return abi.encode(chainflipVault); | ||
} | ||
} |
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,28 @@ | ||
// SPDX-License-Identifier: UNLICENSED | ||
pragma solidity ^0.8.17; | ||
|
||
import { UpdateScriptBase } from "./utils/UpdateScriptBase.sol"; | ||
import { stdJson } from "forge-std/StdJson.sol"; | ||
import { DiamondCutFacet, IDiamondCut } from "lifi/Facets/DiamondCutFacet.sol"; | ||
import { ChainflipFacet } from "lifi/Facets/ChainflipFacet.sol"; | ||
|
||
contract DeployScript is UpdateScriptBase { | ||
using stdJson for string; | ||
|
||
function run() | ||
public | ||
returns (address[] memory facets, bytes memory cutData) | ||
{ | ||
return update("ChainflipFacet"); | ||
} | ||
|
||
function getExcludes() internal pure override returns (bytes4[] memory) { | ||
// No functions to exclude | ||
return new bytes4[](0); | ||
} | ||
|
||
function getCallData() internal override returns (bytes memory) { | ||
// No initialization needed | ||
return new bytes(0); | ||
} | ||
} |
Oops, something went wrong.