Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
36 changes: 31 additions & 5 deletions packages/bridge/src/bridgers/evm/evm-bridger.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { ref, toRaw } from '@distributedlab/reactivity'
import type { IProvider } from '@rarimo/provider'
import type {
Address,
BridgeChain,
ChainId,
DestinationTransaction,
Expand All @@ -10,13 +11,15 @@ import {
Amount,
ChainKind,
ChainTypes,
FEE_MANAGER_ABI,
getDestinationTx as fetchDestTx,
getSupportedChains as getChains,
NATIVE_TOKEN_ADDRESS,
} from '@rarimo/shared'
import { Contract } from 'ethers'

import { errors } from '@/errors'
import type { Bridger, BridgerCreateFn } from '@/types'
import type { Token } from '@/types'
import type { Bridger, BridgerCreateFn, Token } from '@/types'

import {
approve as _approve,
Expand Down Expand Up @@ -68,24 +71,46 @@ export const createEVMBridger: BridgerCreateFn = (

const approveIfNeeded = async (
token: Token,
operator: HexString,
operator: Address,
amount?: Amount,
) => {
return _approveIfNeeded(provider, operator, token, amount)
}

const approve = async (token: Token, operator: HexString) => {
const approve = async (token: Token, operator: Address) => {
return _approve(provider, operator, token)
}

const isApproveRequired = async (
token: Token,
operator: HexString,
operator: Address,
amount?: Amount,
) => {
return isApproveERC20Required(provider, operator, token, amount)
}

const getCommission = async (chain: BridgeChain, token: Token) => {
if (Number(chain.id) !== Number(provider.chainId)) {
throw new TypeError('provided chain is not the same as current')
}

const facade = new Contract(
chain.bridgeFacadeAddress,
FEE_MANAGER_ABI,
provider.getWeb3Provider?.(),
)

const amount = await facade.getCommission(
token.isNative ? NATIVE_TOKEN_ADDRESS : token.address,
)

const commission = Amount.fromBigInt(amount, token.decimals)

if (commission.isZero) throw new errors.BridgerZeroCommissionError()

return commission
}

return toRaw({
chainType: ChainTypes.EVM,
provider,
Expand All @@ -98,5 +123,6 @@ export const createEVMBridger: BridgerCreateFn = (
isApproveRequired,
approve,
approveIfNeeded,
getCommission,
})
}
6 changes: 3 additions & 3 deletions packages/bridge/src/errors/bridger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ export class BridgerInvalidChainTypeError extends RuntimeError {
}
}

export class BridgerChainNotSupportedError extends RuntimeError {
public name = 'BridgerChainNotSupportedError'
constructor(message = 'This chain is not supported yet') {
export class BridgerZeroCommissionError extends RuntimeError {
public name = 'BridgerZeroCommissionError'
constructor(message = 'Commission cannot be zero') {
super(message)
}
}
21 changes: 12 additions & 9 deletions packages/bridge/src/types/bridger.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { Computed, Raw, Ref } from '@distributedlab/reactivity'
import type { IProvider, TransactionResponse } from '@rarimo/provider'
import type {
Address,
Amount,
BridgeChain,
ChainId,
Expand Down Expand Up @@ -30,7 +31,7 @@ export type Bridger = Raw<{
/**
* Get the chain that are supported for the bridging by ID
*
* @returns Supported chain and information about it or void
* @returns A supported chain and information about it or void
*/
getChainById(id: ChainId): BridgeChain | void

Expand All @@ -41,7 +42,7 @@ export type Bridger = Raw<{
*/
getDestinationTx(
sourceChain: BridgeChain,
sourceTxHash: string,
sourceTxHash: HexString,
): Promise<DestinationTransaction>

/**
Expand All @@ -51,7 +52,7 @@ export type Bridger = Raw<{
*/
isApproveRequired(
token: Token,
operator: HexString,
operator: Address,
amount?: Amount,
): Promise<boolean>

Expand All @@ -60,22 +61,24 @@ export type Bridger = Raw<{
*
* @returns A Transaction Response or undefined if input token is native
*/
approve(
token: Token,
operator: HexString,
): Promise<TransactionResponse | void>
approve(token: Token, operator: Address): Promise<TransactionResponse | void>

/**
* Sets allowance for the provided operator address to spend the token if
* allowance amount is less than provided one
* allowance amount is less than the provided one
*
* @returns A Transaction Response or undefined if input token is native or allowance is enough
*/
approveIfNeeded(
token: Token,
operator: HexString,
operator: Address,
amount?: Amount,
): Promise<TransactionResponse | void>

/**
* @returns A fee amount for the bridging for the provided chain and token
*/
getCommission(chain: BridgeChain, token: Token): Promise<Amount>
}>

export type BridgerCreateFn = (p: IProvider) => Bridger
41 changes: 14 additions & 27 deletions packages/nft-checkout/src/operations/evm/evm-operation.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { extend, ref, toRaw } from '@distributedlab/reactivity'
import { BN } from '@distributedlab/tools'
import type { Token } from '@rarimo/bridge'
import type { IProvider } from '@rarimo/provider'
import {
Expand Down Expand Up @@ -41,8 +40,6 @@ import {
isSameChainOperation,
} from './helpers'

const RARIMO_BRIDGE_FEE = 2.5

/**
* An operation on an EVM chain.
*
Expand Down Expand Up @@ -89,6 +86,7 @@ export const EVMOperation = (provider: IProvider): CheckoutOperation => {
throw new errors.OperationInvalidChainPairError()
}

await handleCorrectProviderChain(provider, chainFrom)
await _loadTokens()

isSameChain = isSameChainOperation(params)
Expand Down Expand Up @@ -119,8 +117,6 @@ export const EVMOperation = (provider: IProvider): CheckoutOperation => {

_setStatus(CheckoutOperationStatus.PaymentTokensLoading)

await handleCorrectProviderChain(provider, chainFrom)

const withPairs = await getPaymentTokensWithPairs({
provider,
chainFrom,
Expand Down Expand Up @@ -243,53 +239,44 @@ export const EVMOperation = (provider: IProvider): CheckoutOperation => {
const _getChainToUSDCSwapAmountIn = async () => {
const { chainIdTo, slippage, price } = params

const chainFromUSDC = getTokenByAddress(
chainFromTokens,
USDC_MAP[chainFrom.name]!,
)!

const usdcAddress = USDC_MAP[chainTo.name]!
const getTokenArgs: [BridgeChain, Token[]] = [chainTo, chainToTokens]
const from = getSameChainSwapToToken(...getTokenArgs, usdcAddress)!
const to = getSameChainSwapToToken(...getTokenArgs, price.address)!
const fee = await swapper.getCommission(chainFrom, chainFromUSDC)

const estimateArgs = {
chainIdFrom: chainIdTo,
chainIdTo,
from,
to,
amountOut: Amount.fromBN(
bnFromAmountLike(price).addPercent(RARIMO_BRIDGE_FEE),
),
amountOut: price,
slippage,
}

// estimate USDC -> Target Token on the destination chain to determine
// how much USDC is required to bridge with and without bridge % fee
const estimationWithFee = await getEstimation(estimateArgs)
// how much USDC is required to bridge
const estimation = await getEstimation(estimateArgs)

// USDC could have different decimals on different chains, thus we need to
// convert it to the same decimals as the chain from token.
// If this method called - "swapToToken" always is USDC
const chainFromUSDCAmountOut = bnFromAmountLike(
estimationWithFee.amountIn,
estimation.amountIn,
).toDecimals(swapToToken.decimals)

// Amount from which percent will be subtracted on the backend side has
// precision chainFromUSDCAmountOut.decimals, thus we need to cut off
// the extra precision from the chainFromUSDCAmountOut.raw, so we will create
// a new BN instance from the chainFromUSDCAmountOut.value
const amountIn = Amount.fromBN(
BN.fromBigInt(
chainFromUSDCAmountOut.value,
chainFromUSDCAmountOut.decimals,
)
.subPercent(RARIMO_BRIDGE_FEE)
.toDecimals(estimationWithFee.amountIn.decimals),
)

intermediateOpts = {
...estimationWithFee,
amountIn,
...estimation,
amountIn: estimation.amountIn,
amountOut: price,
}

return Amount.fromBN(chainFromUSDCAmountOut)
return Amount.fromBN(chainFromUSDCAmountOut.add(fee.bn))
}

const _loadTokens = async () => {
Expand Down
1 change: 1 addition & 0 deletions packages/shared/src/api/dex.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ export const getSupportedChains = async ({
icon: chain.icon,
isTestnet: chain.kind.name === ChainKind.Testnet,
contractAddress: chain.swap_contract_address,
bridgeFacadeAddress: chain.bridge_facade_address,
dexType: chain.swap_contract_version,
token: {
...chain.native_token,
Expand Down
Loading