Skip to content
Open
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
25 changes: 17 additions & 8 deletions packages/sdk-provider-ethereum/src/EthereumStepExecutor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import {
type ExtendedChain,
getRelayerQuote,
getStepTransaction,
isTokenMessageSigningAllowed,
LiFiErrorCode,
type LiFiStep,
type LiFiStepExtended,
Expand Down Expand Up @@ -227,6 +226,7 @@ export class EthereumStepExecutor extends BaseStepExecutor {

private prepareUpdatedStep = async (
client: SDKClient,
viemClient: Client,
step: LiFiStepExtended,
signedTypedData?: SignedTypedData[]
) => {
Expand Down Expand Up @@ -285,6 +285,7 @@ export class EthereumStepExecutor extends BaseStepExecutor {
let transactionRequest: TransactionParameters | undefined
if (step.transactionRequest) {
transactionRequest = {
chainId: step.transactionRequest.chainId,
to: step.transactionRequest.to,
from: step.transactionRequest.from,
data: step.transactionRequest.data,
Expand All @@ -301,8 +302,8 @@ export class EthereumStepExecutor extends BaseStepExecutor {
// ? BigInt(step.transactionRequest.maxFeePerGas as string)
// : undefined,
maxPriorityFeePerGas:
this.client.account?.type === 'local'
? await getMaxPriorityFeePerGas(client, this.client)
viemClient.account?.type === 'local'
? await getMaxPriorityFeePerGas(client, viemClient)
: step.transactionRequest.maxPriorityFeePerGas
? BigInt(step.transactionRequest.maxPriorityFeePerGas)
: undefined,
Expand Down Expand Up @@ -432,10 +433,7 @@ export class EthereumStepExecutor extends BaseStepExecutor {
// Check if message signing is disabled - useful for smart contract wallets
// We also disable message signing for custom steps
const disableMessageSigning =
this.executionOptions?.disableMessageSigning ||
step.type !== 'lifi' ||
// We disable message signing for tokens with '₮' symbol
!isTokenMessageSigningAllowed(step.action.fromToken)
this.executionOptions?.disableMessageSigning || step.type !== 'lifi'

// Check if chain has Permit2 contract deployed. Permit2 should not be available for atomic batch.
const permit2Supported =
Expand Down Expand Up @@ -534,9 +532,20 @@ export class EthereumStepExecutor extends BaseStepExecutor {

await checkBalance(client, this.client.account!.address, step)

// Make sure that the client and chain is still correct
const updatedClient = await this.checkClient(step, process)
if (!updatedClient) {
return step
}

// Try to prepare a new transaction request and update the step with typed data
let { transactionRequest, isRelayerTransaction } =
await this.prepareUpdatedStep(client, step, signedTypedData)
await this.prepareUpdatedStep(
client,
updatedClient,
step,
signedTypedData
)

process = this.statusManager.updateProcess(
step,
Expand Down
14 changes: 1 addition & 13 deletions packages/sdk/src/core/utils.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { ChainId, ExtendedChain, LiFiStep, Token } from '@lifi/types'
import type { ChainId, ExtendedChain, LiFiStep } from '@lifi/types'
import type { RPCUrls } from '../types/core.js'

// Standard threshold for destination amount difference (0.5%)
Expand Down Expand Up @@ -57,15 +57,3 @@ export function getRpcUrlsFromChains(
}
return result
}

/**
* Checks whether a given token is eligible for message signing.
* Tokens with '₮' symbol in their name are disallowed,
* since such tokens may have non-standard signing requirements or compatibility issues with hardware wallets.
*
* @param token - The token object to check.
* @returns true if the token is allowed for message signing, false otherwise.
*/
export const isTokenMessageSigningAllowed = (token: Token): boolean => {
return !token.name?.includes('₮') && !token.symbol?.includes('₮')
}
2 changes: 1 addition & 1 deletion packages/sdk/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ export {
} from './core/execution.js'
export { StatusManager } from './core/StatusManager.js'
export { stepComparison } from './core/stepComparison.js'
export { isTokenMessageSigningAllowed } from './core/utils.js'
export { waitForDestinationChainTransaction } from './core/waitForDestinationChainTransaction.js'
export { BaseError } from './errors/baseError.js'
export type { ErrorCode } from './errors/constants.js'
Expand Down Expand Up @@ -66,6 +65,7 @@ export type {
Process,
ProcessStatus,
ProcessType,
RequestInterceptor,
RouteExecutionData,
RouteExecutionDataDictionary,
RouteExecutionDictionary,
Expand Down
7 changes: 7 additions & 0 deletions packages/sdk/src/types/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@ import type {
TokenAmount,
} from '@lifi/types'
import type { Client } from 'viem'
import type { ExtendedRequestInit } from './request.js'

export type RequestInterceptor = (
request: ExtendedRequestInit
) => ExtendedRequestInit | Promise<ExtendedRequestInit>

export interface SDKBaseConfig {
apiKey?: string
Expand All @@ -27,6 +32,8 @@ export interface SDKBaseConfig {
widgetVersion?: string
debug: boolean
preloadChains?: boolean
chainsRefetchInterval?: number
requestInterceptor?: RequestInterceptor
}

export interface SDKConfig extends Partial<Omit<SDKBaseConfig, 'integrator'>> {
Expand Down
15 changes: 9 additions & 6 deletions packages/sdk/src/utils/request.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ export const request = async <T = Response>(
retries: requestSettings.retries,
}
): Promise<T> => {
const { userId, integrator, widgetVersion, apiKey } = config
const { userId, integrator, widgetVersion, apiKey, requestInterceptor } =
config

if (!integrator) {
throw new SDKError(
Expand Down Expand Up @@ -71,6 +72,10 @@ export const request = async <T = Response>(
'x-lifi-integrator': integrator,
}

if (requestInterceptor) {
options = await requestInterceptor(options)
}

const response: Response = await fetch(
url,
stripExtendRequestInitProperties(options)
Expand All @@ -82,12 +87,10 @@ export const request = async <T = Response>(

return await response.json()
} catch (error) {
if (options.retries > 0 && (error as HTTPError).status === 500) {
const retries = options.retries ?? 0
if (retries > 0 && (error as HTTPError).status === 500) {
await sleep(500)
return request<T>(config, url, {
...options,
retries: options.retries - 1,
})
return request<T>(config, url, { ...options, retries: retries - 1 })
}

await (error as HTTPError).buildAdditionalDetails?.()
Expand Down