Skip to content

Commit

Permalink
feat: add WalletChangedDuringExecution error (#186)
Browse files Browse the repository at this point in the history
  • Loading branch information
chybisov authored May 10, 2024
1 parent e47e610 commit 37d53a3
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 12 deletions.
58 changes: 46 additions & 12 deletions src/core/EVM/EVMStepExecutor.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
import type { ExtendedTransactionInfo, FullStatusData } from '@lifi/types'
import type {
ExtendedTransactionInfo,
FullStatusData,
Process,
} from '@lifi/types'
import type {
Address,
Hash,
Expand Down Expand Up @@ -49,11 +53,10 @@ export class EVMStepExecutor extends BaseStepExecutor {
this.multisig = options.multisig
}

// TODO: add checkChain method and update wallet client inside executors
// This can come in handy when we execute multiple routes simultaneously and
// should be sure that we are on the right chain when waiting for transactions.
checkChain = async (
step: LiFiStepExtended
// Ensure that we are using the right chain and wallet when executing transactions.
checkWalletClient = async (
step: LiFiStepExtended,
process?: Process
): Promise<WalletClient | undefined> => {
const updatedWalletClient = await switchChain(
this.walletClient,
Expand All @@ -65,22 +68,48 @@ export class EVMStepExecutor extends BaseStepExecutor {
if (updatedWalletClient) {
this.walletClient = updatedWalletClient
}

// Prevent execution of the quote by wallet different from the one which requested the quote
if (this.walletClient.account?.address !== step.action.fromAddress) {
let processToUpdate = process
if (!processToUpdate) {
// We need to create some process if we don't have one so we can show the error
processToUpdate = this.statusManager.findOrCreateProcess(
step,
'TRANSACTION'
)
}
const errorMessage =
'The wallet address that requested the quote does not match the wallet address attempting to sign the transaction.'
this.statusManager.updateProcess(step, processToUpdate.type, 'FAILED', {
error: {
code: LiFiErrorCode.WalletChangedDuringExecution,
message: errorMessage,
},
})
this.statusManager.updateExecution(step, 'FAILED')
throw new TransactionError(
LiFiErrorCode.WalletChangedDuringExecution,
errorMessage
)
}
return updatedWalletClient
}

executeStep = async (step: LiFiStepExtended): Promise<LiFiStepExtended> => {
// Make sure that the chain is still correct
step.execution = this.statusManager.initExecutionObject(step)

// Find if it's bridging and the step is waiting for a transaction on the receiving chain
const recievingChainProcess = step.execution?.process.find(
(process) => process.type === 'RECEIVING_CHAIN'
)

// Make sure that the chain is still correct
// If the step is waiting for a transaction on the receiving chain, we do not switch the chain
// All changes are already done from the source chain
// Return the step
if (recievingChainProcess?.substatus !== 'WAIT_DESTINATION_TRANSACTION') {
const updatedWalletClient = await this.checkChain(step)
const updatedWalletClient = await this.checkWalletClient(step)
if (!updatedWalletClient) {
return step
}
Expand All @@ -93,8 +122,6 @@ export class EVMStepExecutor extends BaseStepExecutor {
this.multisig?.shouldBatchTransactions &&
!!this.multisig.sendBatchTransaction

step.execution = this.statusManager.initExecutionObject(step)

const fromChain = await config.getChainById(step.action.fromChainId)
const toChain = await config.getChainById(step.action.toChainId)

Expand Down Expand Up @@ -166,7 +193,10 @@ export class EVMStepExecutor extends BaseStepExecutor {
let txHash: Hash
if (process.txHash) {
// Make sure that the chain is still correct
const updatedWalletClient = await this.checkChain(step)
const updatedWalletClient = await this.checkWalletClient(
step,
process
)
if (!updatedWalletClient) {
return step
}
Expand Down Expand Up @@ -209,7 +239,10 @@ export class EVMStepExecutor extends BaseStepExecutor {

// STEP 3: Send the transaction
// Make sure that the chain is still correct
const updatedWalletClient = await this.checkChain(step)
const updatedWalletClient = await this.checkWalletClient(
step,
process
)
if (!updatedWalletClient) {
return step
}
Expand Down Expand Up @@ -406,6 +439,7 @@ export class EVMStepExecutor extends BaseStepExecutor {
)
}
let statusResponse: FullStatusData

try {
if (!processTxHash) {
throw new Error('Transaction hash is undefined.')
Expand Down
13 changes: 13 additions & 0 deletions src/core/Solana/SolanaStepExecutor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,16 @@ export class SolanaStepExecutor extends BaseStepExecutor {
this.walletAdapter = options.walletAdapter
}

checkWalletAdapter = (step: LiFiStepExtended) => {
// Prevent execution of the quote by wallet different from the one which requested the quote
if (this.walletAdapter.publicKey!.toString() !== step.action.fromAddress) {
throw new TransactionError(
LiFiErrorCode.WalletChangedDuringExecution,
'The wallet address that requested the quote does not match the wallet address attempting to sign the transaction.'
)
}
}

executeStep = async (step: LiFiStepExtended): Promise<LiFiStepExtended> => {
step.execution = this.statusManager.initExecutionObject(step)

Expand Down Expand Up @@ -130,6 +140,9 @@ export class SolanaStepExecutor extends BaseStepExecutor {
c.charCodeAt(0)
)
)

this.checkWalletAdapter(step)

txHash = await this.walletAdapter.sendTransaction(
versionedTransaction,
connection,
Expand Down
1 change: 1 addition & 0 deletions src/utils/errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ export enum LiFiErrorCode {
AllowanceRequired = 1014,
InsufficientFunds = 1015,
ExchangeRateUpdateCanceled = 1016,
WalletChangedDuringExecution = 1017,
}

export enum EthersErrorType {
Expand Down
6 changes: 6 additions & 0 deletions src/utils/parseError.ts
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,12 @@ export const parseError = async (
e.message,
e.htmlMessage
)
case LiFiErrorCode.WalletChangedDuringExecution:
return new TransactionError(
LiFiErrorCode.WalletChangedDuringExecution,
e.message,
e.htmlMessage
)
default: {
if (errorCode && typeof errorCode === 'number') {
if (Object.values(MetaMaskErrorCodes.rpc).includes(errorCode as any)) {
Expand Down

0 comments on commit 37d53a3

Please sign in to comment.