Skip to content

CCIP : Lock and Unlock #1871

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

Merged
merged 39 commits into from
Apr 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
9fd975a
update billing
aelmanaa Apr 3, 2024
e257479
add pool type
aelmanaa Apr 3, 2024
04bab73
WETH
aelmanaa Apr 3, 2024
f385a33
nit
aelmanaa Apr 3, 2024
c259ad0
add mechanism
aelmanaa Apr 3, 2024
18d37af
add mechanism
aelmanaa Apr 3, 2024
df2284c
add mechanism
aelmanaa Apr 3, 2024
96ce2b2
add mechanism
aelmanaa Apr 3, 2024
840e9b4
enhance arhcitecture
aelmanaa Apr 3, 2024
ecb5b6f
enhance arhcitecture
aelmanaa Apr 3, 2024
e0b6670
enhance arhcitecture
aelmanaa Apr 3, 2024
008bce0
review
aelmanaa Apr 4, 2024
1e6dd4b
restyle
aelmanaa Apr 4, 2024
4b6179d
sort
aelmanaa Apr 4, 2024
143beda
increase limits
aelmanaa Apr 4, 2024
d0dcf26
nit
aelmanaa Apr 5, 2024
ead26cb
add token calculator
aelmanaa Apr 5, 2024
8735d4c
add token calculator
aelmanaa Apr 5, 2024
d582c8c
add token calculator
aelmanaa Apr 5, 2024
ab06264
add token calculator
aelmanaa Apr 5, 2024
db22f41
nit
aelmanaa Apr 5, 2024
fc1b982
nit
aelmanaa Apr 5, 2024
8db67cd
nit
aelmanaa Apr 5, 2024
7334c23
fix typecheck failure
aelmanaa Apr 5, 2024
98eb8c6
correct fees
aelmanaa Apr 5, 2024
575fd93
order fees
aelmanaa Apr 6, 2024
d30dcbd
fix sort
aelmanaa Apr 6, 2024
adf4473
fix sort
aelmanaa Apr 6, 2024
cf7660b
blockchain fees instead of message fees
aelmanaa Apr 9, 2024
d0c28b7
fees instead of premium
aelmanaa Apr 10, 2024
17cbdce
review
aelmanaa Apr 10, 2024
ee70a6a
release notes
aelmanaa Apr 10, 2024
8154cf9
upgradeability
aelmanaa Apr 11, 2024
e441bea
upgradeability
aelmanaa Apr 11, 2024
3083738
nit
aelmanaa Apr 11, 2024
b3e0a34
nit
aelmanaa Apr 11, 2024
f72e890
nit
aelmanaa Apr 11, 2024
cff6af6
nit
aelmanaa Apr 11, 2024
2bfdb8d
nit
aelmanaa Apr 11, 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
1 change: 1 addition & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
"tbody",
"thead",
"THENA",
"timelock",
"Tobe",
"tsconfigs",
"typechain",
Expand Down
96 changes: 94 additions & 2 deletions src/config/data/ccip/data.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,14 @@
import { ChainsConfig, LanesConfig, TokensConfig, Environment, Version } from "./types"
import {
ChainsConfig,
LanesConfig,
TokensConfig,
Environment,
Version,
SupportedTokenConfig,
determineTokenMechanism,
TokenMechanism,
NetworkFees,
} from "."

// For mainnet
import chainsMainnetv120 from "@config/data/ccip/v1_2_0/mainnet/chains.json"
Expand All @@ -12,7 +22,43 @@ import lanesTestnetv120 from "@config/data/ccip/v1_2_0/testnet/lanes.json"
import tokensTestnetv120 from "@config/data/ccip/v1_2_0/testnet/tokens.json"

import { SupportedChain } from "@config/types"
import { supportedChainToChainInRdd } from "@features/utils"
import { directoryToSupportedChain, supportedChainToChainInRdd } from "@features/utils"

export const getAllEnvironments = () => [Environment.Mainnet, Environment.Testnet]
export const getAllVersions = () => [Version.V1_2_0]

export const networkFees: NetworkFees = {
tokenTransfers: {
[TokenMechanism.LockAndUnlock]: {
allLanes: { gasTokenFee: "0.07 %", linkFee: "0.063 %" },
},
[TokenMechanism.LockAndMint]: {
fromEthereum: { gasTokenFee: "0.50 USD", linkFee: "0.45 USD" },
toEthereum: { gasTokenFee: "5.00 USD", linkFee: "4.50 USD" },
nonEthereum: { gasTokenFee: "0.25 USD", linkFee: "0.225 USD" },
},
[TokenMechanism.BurnAndMint]: {
fromEthereum: { gasTokenFee: "0.50 USD", linkFee: "0.45 USD" },
toEthereum: { gasTokenFee: "5.00 USD", linkFee: "4.50 USD" },
nonEthereum: { gasTokenFee: "0.25 USD", linkFee: "0.225 USD" },
},
[TokenMechanism.BurnAndUnlock]: {
fromEthereum: { gasTokenFee: "0.50 USD", linkFee: "0.45 USD" },
toEthereum: { gasTokenFee: "5.00 USD", linkFee: "4.50 USD" },
nonEthereum: { gasTokenFee: "0.25 USD", linkFee: "0.225 USD" },
},
[TokenMechanism.NoPoolDestinationChain]: {
allLanes: { gasTokenFee: "", linkFee: "" },
},
[TokenMechanism.NoPoolSourceChain]: { allLanes: { gasTokenFee: "", linkFee: "" } },
[TokenMechanism.NoPoolsOnBothChains]: { allLanes: { gasTokenFee: "", linkFee: "" } },
[TokenMechanism.Unsupported]: { allLanes: { gasTokenFee: "", linkFee: "" } },
},
messaging: {
fromToEthereum: { gasTokenFee: "0.50 USD", linkFee: "0.45 USD" },
nonEthereum: { gasTokenFee: "0.10 USD", linkFee: "0.09 USD" },
},
}

export const loadReferenceData = ({ environment, version }: { environment: Environment; version: Version }) => {
let chainsReferenceData: ChainsConfig
Expand Down Expand Up @@ -63,6 +109,52 @@ export const getAllChains = ({
return [...chainsMainnetKeys, ...chainsTestnetKeys]
}

export const getAllSupportedTokens = (params: { environment: Environment; version: Version }) => {
const { lanesReferenceData } = loadReferenceData(params)
const tokens: Record<string, Record<SupportedChain, Record<SupportedChain, SupportedTokenConfig>>> = {}
Object.entries(lanesReferenceData).forEach(([sourceChainRdd, laneReferenceData]) => {
const sourceChain = directoryToSupportedChain(sourceChainRdd)

Object.entries(laneReferenceData).forEach(([destinationChainRdd, destinationLaneReferenceData]) => {
const supportedTokens = destinationLaneReferenceData.supportedTokens
if (supportedTokens) {
Object.entries(supportedTokens).forEach(([token, tokenConfig]) => {
const destinationChain = directoryToSupportedChain(destinationChainRdd)

tokens[token] = tokens[token] || {}
tokens[token][sourceChain] = tokens[token][sourceChain] || {}
tokens[token][sourceChain][destinationChain] = tokenConfig
})
}
})
})
if (Object.keys(tokens).length === 0) {
console.warn(`No supported tokens found for ${params.environment} ${params.version}`)
return []
}
return tokens
}

export const getTokenMechanism = (params: {
token: string
sourceChain: SupportedChain
destinationChain: SupportedChain
environment: Environment
version: Version
}) => {
const { tokensReferenceData } = loadReferenceData(params)
const sourceChainRdd = supportedChainToChainInRdd(params.sourceChain)
const destinationChainRdd = supportedChainToChainInRdd(params.destinationChain)

const tokenConfig = tokensReferenceData[params.token]
const sourceChainPoolInfo = tokenConfig[sourceChainRdd]
const destinationChainPoolInfo = tokenConfig[destinationChainRdd]
const sourceChainPoolType = sourceChainPoolInfo.poolType
const destinationChainPoolType = destinationChainPoolInfo.poolType
const tokenMechanism = determineTokenMechanism(sourceChainPoolType, destinationChainPoolType)
return tokenMechanism
}

const CCIPTokenImage =
"https://images.prismic.io/data-chain-link/86d5bc29-7511-49f5-bbd8-18a8ebc008b0_ccip-icon-white.png?auto=compress,format"

Expand Down
3 changes: 2 additions & 1 deletion src/config/data/ccip/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export * from "./data"
export * from "./types"
export * from "./utils"
export * from "./data"
59 changes: 48 additions & 11 deletions src/config/data/ccip/types.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
type RateLimiterConfig = {
export type RateLimiterConfig = {
capacity: string
isEnabled: boolean
rate: string
}

type SupportedTokenConfig = {
[token: string]: {
rateLimiterConfig: RateLimiterConfig
}
export type SupportedTokenConfig = {
rateLimiterConfig: RateLimiterConfig
}
export type SupportedTokensConfig = {
[token: string]: SupportedTokenConfig
}

export type LaneConfig = {
supportedTokens?: SupportedTokenConfig
supportedTokens?: SupportedTokensConfig
rateLimiterConfig: RateLimiterConfig
onRamp: string
}
Expand All @@ -20,10 +21,7 @@ export type DestinationsLaneConfig = {
[destinationChain: string]: LaneConfig
}

enum PoolType {
LockRelease = "lockRelease",
BurnMint = "burnMint",
}
export type PoolType = "lockRelease" | "burnMint" | "usdc"

type PoolInfo = {
tokenAddress: string
Expand All @@ -50,7 +48,46 @@ export type LanesConfig = {
}

export type TokensConfig = {
[token: string]: PoolInfo
[token: string]: {
[chain: string]: PoolInfo
}
}

export enum TokenMechanism {
LockAndMint = "Lock & Mint",
BurnAndUnlock = "Burn & Unlock",
LockAndUnlock = "Lock & Unlock",
BurnAndMint = "Burn & Mint",
NoPoolSourceChain = "No pool on source blockchain",
NoPoolDestinationChain = "No pool on destination blockchain",
NoPoolsOnBothChains = "No pools on both blockchains",
Unsupported = "Unsupported pool mechanism",
}

export type NetworkFeeStructure = {
gasTokenFee: string
linkFee: string
}

export type LaneSpecificFees = {
fromToEthereum?: NetworkFeeStructure
fromEthereum?: NetworkFeeStructure
toEthereum?: NetworkFeeStructure
nonEthereum?: NetworkFeeStructure
allLanes?: NetworkFeeStructure
}

export type LaneSpecificFeeKey = keyof LaneSpecificFees

export type TokenTransfersNetworkFees = {
[key in TokenMechanism]: LaneSpecificFees
}

export type MessagingNetworkFees = LaneSpecificFees

export type NetworkFees = {
tokenTransfers: TokenTransfersNetworkFees
messaging: MessagingNetworkFees
}

export enum Environment {
Expand Down
105 changes: 105 additions & 0 deletions src/config/data/ccip/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
import { SupportedChain, chainToTechnology } from "@config"
import { NetworkFeeStructure, PoolType, TokenMechanism, LaneSpecificFeeKey } from "./types"
import { networkFees } from "./data"

export const determineTokenMechanism = (
sourcePoolType: PoolType | undefined,
destinationPoolType: PoolType | undefined
): TokenMechanism => {
if (!sourcePoolType && destinationPoolType) {
return TokenMechanism.NoPoolSourceChain
} else if (sourcePoolType && !destinationPoolType) {
return TokenMechanism.NoPoolDestinationChain
} else if (!sourcePoolType && !destinationPoolType) {
return TokenMechanism.NoPoolsOnBothChains
}

if (sourcePoolType === "lockRelease" && destinationPoolType === "burnMint") {
return TokenMechanism.LockAndMint
} else if (sourcePoolType === "burnMint" && destinationPoolType === "lockRelease") {
return TokenMechanism.BurnAndUnlock
} else if (sourcePoolType === "lockRelease" && destinationPoolType === "lockRelease") {
return TokenMechanism.LockAndUnlock
} else if (
(sourcePoolType === "burnMint" && destinationPoolType === "burnMint") ||
(sourcePoolType === "usdc" && destinationPoolType === "usdc")
) {
return TokenMechanism.BurnAndMint
}

return TokenMechanism.Unsupported
}

export const calculateNetworkFeesForTokenMechanismDirect = (
mechanism: TokenMechanism,
laneSpecificFeeKey: LaneSpecificFeeKey
): NetworkFeeStructure => {
const feesForMechanism = networkFees.tokenTransfers[mechanism]
const specificFee = feesForMechanism ? feesForMechanism[laneSpecificFeeKey] : null

if (specificFee) {
return specificFee
} else {
console.error(`No fees defined for mechanism: ${mechanism} and lane key: ${laneSpecificFeeKey}`)
return { gasTokenFee: "0", linkFee: "0" }
}
}

export const calculateNetworkFeesForTokenMechanism = (
mechanism: TokenMechanism,
sourceChain: SupportedChain,
destinationChain: SupportedChain
): NetworkFeeStructure => {
const feesForMechanism = networkFees.tokenTransfers[mechanism]

if (feesForMechanism && feesForMechanism.allLanes) {
return feesForMechanism.allLanes
}

// If 'allLanes' is not available, determine the fee type based on the technology of source and destination chains
const sourceTechno = chainToTechnology[sourceChain]
const destinationTechno = chainToTechnology[destinationChain]

const isSourceEthereum = sourceTechno === "ETHEREUM"
const isDestinationEthereum = destinationTechno === "ETHEREUM"

let laneSpecificFeeKey: LaneSpecificFeeKey
if ((isSourceEthereum || isDestinationEthereum) && feesForMechanism.fromToEthereum) {
laneSpecificFeeKey = "fromToEthereum"
} else if (isSourceEthereum && feesForMechanism.fromEthereum) {
laneSpecificFeeKey = "fromEthereum"
} else if (isDestinationEthereum && feesForMechanism.toEthereum) {
laneSpecificFeeKey = "toEthereum"
} else {
laneSpecificFeeKey = "nonEthereum"
}

return calculateNetworkFeesForTokenMechanismDirect(mechanism, laneSpecificFeeKey)
}

export const calculateMessagingNetworkFeesDirect = (laneSpecificFeeKey: LaneSpecificFeeKey): NetworkFeeStructure => {
const messagingFees = networkFees.messaging[laneSpecificFeeKey]
if (messagingFees) {
return messagingFees
} else {
console.error(`No fees defined for lane key: ${laneSpecificFeeKey}`)
return { gasTokenFee: "0", linkFee: "0" }
}
}

export const calculateMessaingNetworkFees = (sourceChain: SupportedChain, destinationChain: SupportedChain) => {
const sourceTechno = chainToTechnology[sourceChain]
const destinationTechno = chainToTechnology[destinationChain]

const isSourceEthereum = sourceTechno === "ETHEREUM"
const isDestinationEthereum = destinationTechno === "ETHEREUM"

let laneSpecificFeeKey: LaneSpecificFeeKey
if (isSourceEthereum || isDestinationEthereum) {
laneSpecificFeeKey = "fromToEthereum"
} else {
laneSpecificFeeKey = "nonEthereum"
}

return calculateMessagingNetworkFeesDirect(laneSpecificFeeKey)
}
Loading
Loading