Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(ccip): CCIPFacet v1.0.0 #542

Draft
wants to merge 27 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 14 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
a831dc1
Generate boilerplate
ezynda3 Sep 18, 2023
a4aeab1
Add configuration
ezynda3 Sep 20, 2023
bcaf49a
Merge branch 'main' of github.com:lifinance/contracts into LF-4961-Im…
ezynda3 Sep 21, 2023
2de777e
Merge branch 'main' of github.com:lifinance/contracts into LF-4961-Im…
ezynda3 Sep 22, 2023
77e78ef
Implement CCIP business logic
ezynda3 Sep 22, 2023
3dfae65
Start implementing tests
ezynda3 Sep 25, 2023
fcd85ef
Formatting
ezynda3 Sep 25, 2023
0ec4b5a
Update tests
ezynda3 Sep 25, 2023
041774f
Merge branch 'main' of github.com:lifinance/contracts into LF-4961-Im…
ezynda3 Sep 28, 2023
657c5d8
Add convenience functions
ezynda3 Sep 29, 2023
acd60af
Update deploy scripts
ezynda3 Sep 29, 2023
7727181
Deploy to staging
ezynda3 Sep 29, 2023
6d5ec6f
Create demo script
ezynda3 Oct 3, 2023
9da5958
Add basic documentation
ezynda3 Oct 3, 2023
7376af6
Update demo
ezynda3 Oct 24, 2023
d24ebee
Merge branch 'main' into LF-4961-Implementing-CCIP-support
ezynda3 Oct 25, 2023
972b7b2
Add missing URI
ezynda3 Oct 25, 2023
1d3998f
Merge branch 'main' into LF-4961-Implementing-CCIP-support
ezynda3 Oct 27, 2023
bd5c154
Implement destination calls for CCIP
ezynda3 Oct 27, 2023
bffeaf1
Update demo
ezynda3 Oct 27, 2023
05d6a18
Remove unneeded payload args
ezynda3 Oct 30, 2023
650ae7a
Update demo script
ezynda3 Oct 30, 2023
c3470e4
Redeploy to staging
ezynda3 Oct 30, 2023
fa77981
Revert back to previous version
ezynda3 Oct 30, 2023
f9211b6
Update demo script
ezynda3 Oct 30, 2023
96dc26f
Merge branch 'main' of github.com:lifinance/contracts into LF-4961-Im…
ezynda3 Nov 10, 2023
24806fb
Merge branch 'main' into LF-4961-Implementing-CCIP-support
ezynda3 Jan 18, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 57 additions & 0 deletions config/ccip.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
{
"routers": {
"mainnet": {
"router": "0xE561d5E02207fb5eB32cca20a699E0d8919a1476"
},
"sepolia": {
"router": "0xD0daae2231E9CB96b94C8512223533293C3693Bf"
},
"optimism": {
"router": "0x261c05167db67B2b619f9d312e0753f3721ad6E8"
},
"avalanche": {
"router": "0x27F39D0af3303703750D4001fCc1844c6491563c"
},
"mumbai": {
"router": "0x70499c328e1E2a3c41108bd3730F6670a44595D1"
},
"polygon": {
"router": "0x3C3D92629A02a8D95D5CB9650fe49C3544f69B43"
},
"bsc-testnet": {
"router": "0x9527e2d01a3064ef6b50c1da1c0cc523803bcff2"
}
},
"chainSelectors": [
{
"chainId": 1,
"selector": 5009297550715157269
},
{
"chainId": 10,
"selector": 3734403246176062136
},
{
"chainId": 43114,
"selector": 6433500567565415381
},
{
"chainId": 137,
"selector": 4051577828743386545
}
],
"testChainSelectors": [
{
"chainId": 11155111,
"selector": 16015286601757825753
},
{
"chainId": 80001,
"selector": 12532609583862916517
},
{
"chainId": 97,
"selector": 13264668187771770619
}
]
}
30 changes: 30 additions & 0 deletions deployments/_deployments_log_file.json
Original file line number Diff line number Diff line change
Expand Up @@ -13375,5 +13375,35 @@
]
}
}
},
"CCIPFacet": {
"avalanche": {
"staging": {
"0.0.1": [
{
"ADDRESS": "0x6982237928de8e4a1a3622226D3a9C2bd89515Fc",
"OPTIMIZER_RUNS": "1000000",
"TIMESTAMP": "2023-09-29 16:56:13",
"CONSTRUCTOR_ARGS": "0x00000000000000000000000027f39d0af3303703750d4001fcc1844c6491563c",
"SALT": "",
"VERIFIED": "true"
}
]
}
},
"mainnet": {
"staging": {
"0.0.1": [
{
"ADDRESS": "0x6982237928de8e4a1a3622226D3a9C2bd89515Fc",
"OPTIMIZER_RUNS": "1000000",
"TIMESTAMP": "2023-09-29 16:55:28",
"CONSTRUCTOR_ARGS": "0x000000000000000000000000e561d5e02207fb5eb32cca20a699e0d8919a1476",
"SALT": "",
"VERIFIED": "true"
}
]
}
}
}
}
4 changes: 4 additions & 0 deletions deployments/avalanche.diamond.staging.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,10 @@
"0xe1FaF1759cAB242c5A790Da72c8f0cC7F5e09f59": {
"Name": "CircleBridgeFacet",
"Version": "1.0.0"
},
"0x6982237928de8e4a1a3622226D3a9C2bd89515Fc": {
"Name": "CCIPFacet",
"Version": "0.0.1"
}
},
"Periphery": {
Expand Down
3 changes: 2 additions & 1 deletion deployments/avalanche.staging.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,6 @@
"FeeCollector": "0x0222D030e8DFAEDE2a4e7B5F181Ac1A4206A75f0",
"Receiver": "0x59B341fF54543D66C7393FfD2A050E256c97669E",
"ServiceFeeCollector": "0x9cc3164f01ED3796Fdf7Da538484D634608D2203",
"CircleBridgeFacet": "0xe1FaF1759cAB242c5A790Da72c8f0cC7F5e09f59"
"CircleBridgeFacet": "0xe1FaF1759cAB242c5A790Da72c8f0cC7F5e09f59",
"CCIPFacet": "0x6982237928de8e4a1a3622226D3a9C2bd89515Fc"
}
6 changes: 5 additions & 1 deletion deployments/mainnet.diamond.staging.json
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,10 @@
"0xE8Ff7BFEF5DacB57E87bC2d0B6CCFefBE5f546BC": {
"Name": "OptimismBridgeFacet",
"Version": "1.0.0"
},
"0x6982237928de8e4a1a3622226D3a9C2bd89515Fc": {
"Name": "CCIPFacet",
"Version": "0.0.1"
0xDEnYO marked this conversation as resolved.
Show resolved Hide resolved
}
},
"Periphery": {
Expand All @@ -103,4 +107,4 @@
"ServiceFeeCollector": "0xf068cc770f32042Ff4a8fD196045641234dFaa47"
}
}
}
}
5 changes: 3 additions & 2 deletions deployments/mainnet.staging.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,5 +28,6 @@
"RoninBridgeFacet": "0xFB4C992Cc7cfA7Eb3e44b928C6f756C07a3feb04",
"SquidFacet": "0x933A3AfE2087FB8F5c9EE9A033477C42CC14c18E",
"SynapseBridgeFacet": "0x57F98A94AC66e197AF6776D5c094FF0da2C0B198",
"ThorSwapFacet": "0xa696287F37d21D566B9A80AC29b2640FF910C176"
}
"ThorSwapFacet": "0xa696287F37d21D566B9A80AC29b2640FF910C176",
"CCIPFacet": "0x6982237928de8e4a1a3622226D3a9C2bd89515Fc"
}
98 changes: 98 additions & 0 deletions docs/CCIPFacet.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
# CCIP Facet

## How it works

The CCIP Facet works by forwarding CCIP specific calls to the CCIP router contract.

```mermaid
graph LR;
D{LiFiDiamond}-- DELEGATECALL -->CCIPFacet;
CCIPFacet -- CALL --> C(CCIP)
```

## Public Methods

- `function startBridgeTokensViaCCIP(BridgeData calldata _bridgeData, CCIPData calldata _ccipData)`
- Simply bridges tokens using ccip
- `swapAndStartBridgeTokensViaccip(BridgeData memory _bridgeData, LibSwap.SwapData[] calldata _swapData, ccipData memory _ccipData)`
- Performs swap(s) before bridging tokens using ccip
- `quoteCCIPFee(BridgeData memory _bridgeData, CCIPData memory _ccipData) returns (uint256)`
- Returns the amount of fee in native tokens needed to bridge the tokens using ccip
- `encodeDestinationArgs(uint256 gasLimit, bool strictSequencing) returns (bytes memory)`
- Encodes the destination args for ccip. Only needed if doing calls on the destination chain.

## ccip Specific Parameters

The methods listed above take a variable labeled `_ccipData`. This data is specific to ccip and is represented as the following struct type:

```solidity
/// @param callData destination calldata (optional).
/// @param extraArgs extra arguments for destination call (only needed for destination calls)
struct CCIPData {
bytes callData;
bytes extraArgs;
}
```

## 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 variaous 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: 'ccip', // 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=ccip&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=ccip&fromAddress={YOUR_WALLET_ADDRESS}'
```
1 change: 1 addition & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
- [Arbitrum Bridge Facet](./ArbitrumBridgeFacet.md)
- [CalldataVerification Facet](./CalldataVerificationFacet.md)
- [CBridge Facet](./CBridgeFacet.md)
- [CCIP Facet](./CCIPFacet.md)
- [Celer Circle Bridge Facet](./CelerCircleBridgeFacet.md)
- [Circle Bridge Facet](./CircleBridgeFacet.md)
- [DeBridge Facet](./DeBridgeFacet.md)
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@
},
"dependencies": {
"@arbitrum/sdk": "^3.0.0",
"@chainlink/contracts-ccip": "^0.7.6",
"@hop-protocol/sdk": "0.0.1-beta.310",
"@safe-global/api-kit": "^1.1.0",
"@safe-global/protocol-kit": "^1.0.1",
Expand Down
2 changes: 1 addition & 1 deletion remappings.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
eth-gas-reporter/=node_modules/eth-gas-reporter/
hardhat/=node_modules/hardhat/
hardhat-deploy/=node_modules/hardhat-deploy/

@openzeppelin/=lib/openzeppelin-contracts/
@chainlink-ccip/=node_modules/@chainlink/contracts-ccip/src/
celer-network/=lib/sgn-v2-contracts/
create3-factory/=lib/create3-factory/src/
solmate/=lib/solmate/src/
Expand Down
82 changes: 82 additions & 0 deletions script/demoScripts/demoCCIP.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import { providers, Wallet, utils, constants } from 'ethers'
import { CCIPFacet__factory, ERC20__factory } from '../../typechain'
import chalk from 'chalk'
import dotenv from 'dotenv'

dotenv.config()

const msg = (msg: string) => {
console.log(chalk.green(msg))
}

const LIFI_ADDRESS = '0xbEbCDb5093B47Cd7add8211E4c77B6826aF7bc5F' // LiFiDiamond address on AVAX stating
const BETS_TOKEN_ADDRESS = '0x94025780a1aB58868D9B2dBBB775f44b32e8E6e5'
const L2_GAS = 20000 // L2 Gas, Don't need to change it.
const destinationChainId = 1 // Mainnet

async function main() {
const jsonProvider = new providers.JsonRpcProvider(
process.env.ETH_NODE_URI_AVALANCHE
)
const provider = new providers.FallbackProvider([jsonProvider])

let wallet = new Wallet(<string>process.env.PRIVATE_KEY)
wallet = wallet.connect(provider)
const walletAddress = await wallet.getAddress()

const lifi = CCIPFacet__factory.connect(LIFI_ADDRESS, wallet)

// Bridge amount
const amount = utils.parseEther('10')

// LIFI Data
const lifiData = {
transactionId: utils.randomBytes(32),
bridge: 'CCIP',
integrator: 'ACME Devs',
referrer: constants.AddressZero,
sendingAssetId: constants.AddressZero,
receiver: walletAddress,
minAmount: amount,
destinationChainId: destinationChainId,
hasSourceSwaps: false,
hasDestinationCall: false,
}

// Bridge ERC20
lifiData.sendingAssetId = BETS_TOKEN_ADDRESS

const extraArgs = await lifi.encodeDestinationArgs(L2_GAS, false)

const bridgeData = {
callData: '0x',
extraArgs,
}

const fee = await lifi.quoteCCIPFee(lifiData, bridgeData)

msg('Approving BETS...')
const BETS = ERC20__factory.connect(BETS_TOKEN_ADDRESS, wallet)
let tx = await BETS.approve(LIFI_ADDRESS, amount)
await tx.wait()

msg('Sending BETS to Mainnet via CCIP...')
tx = await lifi.startBridgeTokensViaCCIP(lifiData, bridgeData, {
gasLimit: '500000',
value: fee,
})
msg('TX Sent. Waiting for receipt...')
await tx.wait()
msg('Done!')
}

main()
.then(() => {
console.error('Success')
process.exit(0)
})
.catch((error) => {
console.error('error')
console.error(error)
process.exit(1)
})
45 changes: 45 additions & 0 deletions script/deploy/facets/DeployCCIPFacet.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.17;

import { DeployScriptBase } from "./utils/DeployScriptBase.sol";
import { stdJson } from "forge-std/Script.sol";
import { CCIPFacet } from "lifi/Facets/CCIPFacet.sol";

contract DeployScript is DeployScriptBase {
using stdJson for string;

constructor() DeployScriptBase("CCIPFacet") {}

function run()
public
returns (CCIPFacet deployed, bytes memory constructorArgs)
{
string memory path = string.concat(
vm.projectRoot(),
"/config/ccip.json"
);
string memory json = vm.readFile(path);
address router = json.readAddress(
string.concat(".routers.", network, ".router")
);

constructorArgs = abi.encode(router);

vm.startBroadcast(deployerPrivateKey);

if (isDeployed()) {
return (CCIPFacet(payable(predicted)), constructorArgs);
}

deployed = CCIPFacet(
payable(
factory.deploy(
salt,
bytes.concat(type(CCIPFacet).creationCode, constructorArgs)
)
)
);

vm.stopBroadcast();
}
}
Loading