Skip to content
Closed
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
141 changes: 77 additions & 64 deletions packages/sdk-provider-bitcoin/src/BitcoinStepExecutor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,46 +56,61 @@ export class BitcoinStepExecutor extends BaseStepExecutor {
client: SDKClient,
step: LiFiStepExtended
): Promise<LiFiStepExtended> => {
step.execution = this.statusManager.initExecutionObject(step)
const isBridgeExecution = step.action.fromChainId !== step.action.toChainId
const executionType = isBridgeExecution ? 'CROSS_CHAIN' : 'SWAP'

const isNewExecution = !step.execution || step.execution.status === 'FAILED'
const isNewProcess =
isNewExecution || step.execution?.type !== executionType

if (isNewExecution) {
step = this.statusManager.updateExecution(step, {
type: executionType,
status: 'PENDING',
startedAt: Date.now(),
actions: [],
// Reset from previous (failed) execution
error: undefined,
signedAt: undefined,
})
}

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

const isBridgeExecution = fromChain.id !== toChain.id
const currentProcessType = isBridgeExecution ? 'CROSS_CHAIN' : 'SWAP'

let process = this.statusManager.findOrCreateProcess({
step,
type: currentProcessType,
chainId: fromChain.id,
})
if (isNewProcess) {
step = this.statusManager.updateExecution(step, {
type: executionType,
status: 'STARTED',
})
}

const publicClient = await getBitcoinPublicClient(client, ChainId.BTC)

if (process.status !== 'DONE') {
const action = step.execution?.actions.find((t) => t.type === executionType)
if (!action?.isDone) {
try {
let txHash: string
let txHex: string
if (process.txHash) {

if (action?.txHash) {
// Make sure that the chain is still correct
this.checkClient(step)

// Wait for exiting transaction
txHash = process.txHash
txHex = process.txHex
txHash = action.txHash
txHex = action.txHex ?? ''
} else {
process = this.statusManager.updateProcess(
step,
process.type,
'STARTED'
)
step = this.statusManager.updateExecution(step, {
type: executionType,
status: 'STARTED',
})

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

// Create new transaction
if (!step.transactionRequest) {
// biome-ignore lint/correctness/noUnusedVariables: destructuring
const { execution, ...stepBase } = step
const updatedStep = await getStepTransaction(client, stepBase)
const comparedStep = await stepComparison(
Expand All @@ -118,18 +133,17 @@ export class BitcoinStepExecutor extends BaseStepExecutor {
)
}

process = this.statusManager.updateProcess(
step,
process.type,
'ACTION_REQUIRED'
)
step = this.statusManager.updateExecution(step, {
type: executionType,
status: 'ACTION_REQUIRED',
})

if (!this.allowUserInteraction) {
return step
}

let transactionRequest: TransactionParameters = {
data: step.transactionRequest.data,
data: step.transactionRequest?.data,
}

if (this.executionOptions?.updateTransactionRequestHook) {
Expand Down Expand Up @@ -257,16 +271,19 @@ export class BitcoinStepExecutor extends BaseStepExecutor {
hex: txHex,
})

process = this.statusManager.updateProcess(
step,
process.type,
'PENDING',
{
step = this.statusManager.updateExecution(step, {
type: executionType,
status: 'PENDING',
signedAt: Date.now(),
action: {
type: executionType,
chainId: fromChain.id,
txHash: txHash,
txLink: `${fromChain.metamask.blockExplorerUrls[0]}tx/${txHash}`,
txHex,
}
)
isDone: false,
},
})
}

let replacementReason: ReplacementReason | undefined
Expand All @@ -276,15 +293,17 @@ export class BitcoinStepExecutor extends BaseStepExecutor {
senderAddress: this.client.account?.address,
onReplaced: (response) => {
replacementReason = response.reason
process = this.statusManager.updateProcess(
step,
process.type,
'PENDING',
{
step = this.statusManager.updateExecution(step, {
type: executionType,
status: 'PENDING',
action: {
type: executionType,
chainId: fromChain.id,
txHash: response.transaction.txid,
txLink: `${fromChain.metamask.blockExplorerUrls[0]}tx/${response.transaction.txid}`,
}
)
isDone: false,
},
})
},
})

Expand All @@ -296,42 +315,36 @@ export class BitcoinStepExecutor extends BaseStepExecutor {
}

if (transaction.txid !== txHash) {
process = this.statusManager.updateProcess(
step,
process.type,
'PENDING',
{
step = this.statusManager.updateExecution(step, {
type: executionType,
status: 'PENDING',
action: {
type: executionType,
chainId: fromChain.id,
txHash: transaction.txid,
txLink: `${fromChain.metamask.blockExplorerUrls[0]}tx/${transaction.txid}`,
}
)
}

if (isBridgeExecution) {
process = this.statusManager.updateProcess(step, process.type, 'DONE')
isDone: isBridgeExecution,
},
})
}
} catch (e: any) {
const error = await parseBitcoinErrors(e, step, process)
process = this.statusManager.updateProcess(
step,
process.type,
'FAILED',
{
error: {
message: error.cause.message,
code: error.code,
},
}
)
this.statusManager.updateExecution(step, 'FAILED')
const error = await parseBitcoinErrors(e, step)
step = this.statusManager.updateExecution(step, {
type: executionType,
status: 'FAILED',
error: {
message: error.cause.message,
code: error.code,
},
})
throw error
}
}

await waitForDestinationChainTransaction(
client,
step,
process,
executionType,
fromChain,
toChain,
this.statusManager,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,24 @@ import {
BaseError,
ErrorMessage,
LiFiErrorCode,
type LiFiStep,
type Process,
type LiFiStepExtended,
SDKError,
TransactionError,
UnknownError,
} from '@lifi/sdk'

export const parseBitcoinErrors = async (
e: Error,
step?: LiFiStep,
process?: Process
step?: LiFiStepExtended
): Promise<SDKError> => {
if (e instanceof SDKError) {
e.step = e.step ?? step
e.process = e.process ?? process
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Previously all the passed processes were the latest processes. Now we store them on execution level.

For debugging, one can take current step.execution.type and find a corresponding action by type.

Therefore passing down the action is excessive.

return e
}

const baseError = handleSpecificErrors(e)

return new SDKError(baseError, step, process)
return new SDKError(baseError, step)
}

const handleSpecificErrors = (e: any) => {
Expand Down
Loading