Skip to content

Commit

Permalink
Enable Confirmed Txs and User Operations execution
Browse files Browse the repository at this point in the history
  • Loading branch information
yagopv committed Feb 20, 2025
1 parent 5bb59d3 commit f5abadd
Show file tree
Hide file tree
Showing 2 changed files with 47 additions and 16 deletions.
35 changes: 26 additions & 9 deletions packages/sdk-starter-kit/src/SafeClient.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
import Safe from '@safe-global/protocol-kit'
import SafeApiKit, { SafeMultisigTransactionListResponse } from '@safe-global/api-kit'
import { SafeTransaction, TransactionOptions, TransactionResult } from '@safe-global/types-kit'
import {
SafeMultisigTransactionResponse,
SafeTransaction,
TransactionOptions,
TransactionResult
} from '@safe-global/types-kit'

import {
createSafeClientResult,
Expand Down Expand Up @@ -89,18 +94,22 @@ export class SafeClient extends BaseClient {
* @throws {Error} If the transaction confirmation fails.
*/
async confirm({ safeTxHash }: ConfirmTransactionProps): Promise<SafeClientResult> {
let transactionResponse = await this.apiKit.getTransaction(safeTxHash)
const safeAddress = await this.protocolKit.getAddress()
const signedTransaction = await this.protocolKit.signTransaction(transactionResponse)
let transactionResponse = await this.apiKit.getTransaction(safeTxHash)

let isReadyToExecute = await this.#hasEnoughConfirmations(transactionResponse)

if (!isReadyToExecute) {
const signedTransaction = await this.protocolKit.signTransaction(transactionResponse)

await this.apiKit.confirmTransaction(safeTxHash, signedTransaction.encodedSignatures())
await this.apiKit.confirmTransaction(safeTxHash, signedTransaction.encodedSignatures())

transactionResponse = await this.apiKit.getTransaction(safeTxHash)
transactionResponse = await this.apiKit.getTransaction(safeTxHash)

if (
transactionResponse.confirmations &&
transactionResponse.confirmationsRequired === transactionResponse.confirmations.length
) {
isReadyToExecute = await this.#hasEnoughConfirmations(transactionResponse)
}

if (isReadyToExecute) {
const executedTransactionResponse: TransactionResult =
await this.protocolKit.executeTransaction(transactionResponse)

Expand Down Expand Up @@ -263,6 +272,14 @@ export class SafeClient extends BaseClient {
})
}

async #hasEnoughConfirmations(
transactionResponse: SafeMultisigTransactionResponse
): Promise<boolean> {
return transactionResponse
? transactionResponse.confirmations?.length === transactionResponse.confirmationsRequired
: false
}

async #reconnectSafe(): Promise<void> {
this.protocolKit = await this.protocolKit.connect({
provider: this.protocolKit.getSafeProvider().provider,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
SafeClientResult,
SendSafeOperationProps
} from '@safe-global/sdk-starter-kit/types'
import { SafeOperationResponse } from '@safe-global/types-kit'

/**
* @class
Expand Down Expand Up @@ -94,17 +95,23 @@ export class SafeOperationClient {
}: ConfirmSafeOperationProps): Promise<SafeClientResult> {
const safeAddress = await this.protocolKit.getAddress()
const threshold = await this.protocolKit.getThreshold()
let safeOperationResponse = await this.apiKit.getSafeOperation(safeOperationHash)

await this.apiKit.confirmSafeOperation(
safeOperationHash,
buildSignatureBytes([await this.protocolKit.signHash(safeOperationHash)])
)
let isReadyForBundler = await this.#hasEnoughConfirmations(safeOperationResponse, threshold)

const confirmedSafeOperation = await this.apiKit.getSafeOperation(safeOperationHash)
if (!isReadyForBundler) {
await this.apiKit.confirmSafeOperation(
safeOperationHash,
buildSignatureBytes([await this.protocolKit.signHash(safeOperationHash)])
)

if (confirmedSafeOperation?.confirmations?.length === threshold) {
safeOperationResponse = await this.apiKit.getSafeOperation(safeOperationHash)
isReadyForBundler = await this.#hasEnoughConfirmations(safeOperationResponse, threshold)
}

if (isReadyForBundler) {
const userOperationHash = await this.safe4337Pack.executeTransaction({
executable: confirmedSafeOperation
executable: safeOperationResponse
})

await this.#waitForOperationToFinish({ userOperationHash })
Expand Down Expand Up @@ -138,6 +145,13 @@ export class SafeOperationClient {
return this.apiKit.getPendingSafeOperations(safeAddress, options)
}

async #hasEnoughConfirmations(
safeOperationResponse: SafeOperationResponse,
threshold: number
): Promise<boolean> {
return safeOperationResponse ? safeOperationResponse.confirmations?.length === threshold : false
}

/**
* Helper method to wait for the operation to finish
* @param userOperationHash The userOperationHash to wait for. This comes from the bundler and can be obtained from the
Expand Down

0 comments on commit f5abadd

Please sign in to comment.