From 608792350eec6ec370ce0347f2282acd2398b1b8 Mon Sep 17 00:00:00 2001 From: Daniel <25051234+dasanra@users.noreply.github.com> Date: Tue, 15 Oct 2024 16:52:56 +0200 Subject: [PATCH] feat(api-kit): add ordering props to getPendingTransactions --- packages/api-kit/src/SafeApiKit.ts | 60 ++++++++++++++++++- .../src/types/safeTransactionServiceTypes.ts | 7 +++ .../tests/e2e/getPendingTransactions.test.ts | 22 +++++++ packages/api-kit/tests/endpoint/index.test.ts | 4 +- packages/protocol-kit/package.json | 1 - packages/testing-kit/package.json | 1 + 6 files changed, 90 insertions(+), 5 deletions(-) diff --git a/packages/api-kit/src/SafeApiKit.ts b/packages/api-kit/src/SafeApiKit.ts index e7bd087ac..be9089339 100644 --- a/packages/api-kit/src/SafeApiKit.ts +++ b/packages/api-kit/src/SafeApiKit.ts @@ -12,6 +12,7 @@ import { ListOptions, ModulesResponse, OwnerResponse, + PendingTransactionsOptions, ProposeTransactionProps, SafeCreationInfoResponse, SafeDelegateListResponse, @@ -528,7 +529,7 @@ class SafeApiKit { * Returns the list of multi-signature transactions that are waiting for the confirmation of the Safe owners. * * @param safeAddress - The Safe address - * @param currentNonce - Current nonce of the Safe + * @param currentNonce - Deprecated, use inside object property: Current nonce of the Safe. * @returns The list of transactions waiting for the confirmation of the Safe owners * @throws "Invalid Safe address" * @throws "Invalid data" @@ -537,15 +538,70 @@ class SafeApiKit { async getPendingTransactions( safeAddress: string, currentNonce?: number + ): Promise + /** + * Returns the list of multi-signature transactions that are waiting for the confirmation of the Safe owners. + * + * @param safeAddress - The Safe address + * @param {PendingTransactionsOptions} options The options to filter the list of transactions + * @returns The list of transactions waiting for the confirmation of the Safe owners + * @throws "Invalid Safe address" + * @throws "Invalid data" + * @throws "Invalid ethereum address" + */ + async getPendingTransactions( + safeAddress: string, + { currentNonce, hasConfirmations, ordering, limit, offset }: PendingTransactionsOptions + ): Promise + async getPendingTransactions( + safeAddress: string, + propsOrCurrentNonce: PendingTransactionsOptions | number = {} ): Promise { if (safeAddress === '') { throw new Error('Invalid Safe address') } + + // TODO: Remove @deprecated migration code + let currentNonce: number | undefined + let hasConfirmations: boolean | undefined + let ordering: string | undefined + let limit: number | undefined + let offset: number | undefined + if (typeof propsOrCurrentNonce === 'object') { + ;({ currentNonce, hasConfirmations, ordering, limit, offset } = propsOrCurrentNonce) + } else { + console.warn( + 'Deprecated: Use `currentNonce` inside an object instead. See `PendingTransactionsOptions`.' + ) + currentNonce = propsOrCurrentNonce + } + // END of @deprecated migration code + const { address } = this.#getEip3770Address(safeAddress) const nonce = currentNonce ? currentNonce : (await this.getSafeInfo(address)).nonce + const url = new URL( + `${this.#txServiceBaseUrl}/v1/safes/${address}/multisig-transactions/?executed=false&nonce__gte=${nonce}` + ) + + if (hasConfirmations) { + url.searchParams.set('has_confirmations', hasConfirmations.toString()) + } + + if (ordering) { + url.searchParams.set('ordering', ordering) + } + + if (limit != null) { + url.searchParams.set('limit', limit.toString()) + } + + if (offset != null) { + url.searchParams.set('offset', offset.toString()) + } + return sendRequest({ - url: `${this.#txServiceBaseUrl}/v1/safes/${address}/multisig-transactions/?executed=false&nonce__gte=${nonce}`, + url: url.toString(), method: HttpMethod.Get }) } diff --git a/packages/api-kit/src/types/safeTransactionServiceTypes.ts b/packages/api-kit/src/types/safeTransactionServiceTypes.ts index a09256697..5b75d0147 100644 --- a/packages/api-kit/src/types/safeTransactionServiceTypes.ts +++ b/packages/api-kit/src/types/safeTransactionServiceTypes.ts @@ -124,6 +124,13 @@ export type ProposeTransactionProps = { origin?: string } +export type PendingTransactionsOptions = { + currentNonce?: number + hasConfirmations?: boolean + /** Which field to use when ordering the results. It can be: `nonce`, `created`, `modified` (default: `-created`) */ + ordering?: string +} & ListOptions + export type SafeMultisigTransactionListResponse = ListResponse export type TransferResponse = { diff --git a/packages/api-kit/tests/e2e/getPendingTransactions.test.ts b/packages/api-kit/tests/e2e/getPendingTransactions.test.ts index e136ae8b4..2808f553c 100644 --- a/packages/api-kit/tests/e2e/getPendingTransactions.test.ts +++ b/packages/api-kit/tests/e2e/getPendingTransactions.test.ts @@ -48,4 +48,26 @@ describe('getPendingTransactions', () => { chai.expect(transactionList.count).to.be.equal(10) chai.expect(transactionList.results.length).to.be.equal(10) }) + + it('should return a maximum of 2 transactions with limit = 2', async () => { + const safeAddress = '0xCa2f5A815b642c79FC530B60BC15Aee4eF6252b3' // Safe with pending transaction + const transactionList = await safeApiKit.getPendingTransactions(safeAddress, { + limit: 2 + }) + + chai.expect(transactionList).to.have.property('count').greaterThan(1) + chai.expect(transactionList).to.have.property('results').to.be.an('array') + chai.expect(transactionList.results.length).to.be.equal(2) + }) + + it('should return all pending transactions excluding the first one with offset = 1', async () => { + const safeAddress = '0xCa2f5A815b642c79FC530B60BC15Aee4eF6252b3' // Safe with pending transaction + const transactionList = await safeApiKit.getPendingTransactions(safeAddress, { + offset: 1 + }) + + chai.expect(transactionList).to.have.property('count').greaterThan(1) + chai.expect(transactionList).to.have.property('results').to.be.an('array') + chai.expect(transactionList.results.length).to.be.lessThanOrEqual(transactionList.count - 1) + }) }) diff --git a/packages/api-kit/tests/endpoint/index.test.ts b/packages/api-kit/tests/endpoint/index.test.ts index d0d59d0b8..229324ccd 100644 --- a/packages/api-kit/tests/endpoint/index.test.ts +++ b/packages/api-kit/tests/endpoint/index.test.ts @@ -512,7 +512,7 @@ describe('Endpoint tests', () => { it('getPendingTransactions', async () => { const currentNonce = 1 await chai - .expect(safeApiKit.getPendingTransactions(safeAddress, currentNonce)) + .expect(safeApiKit.getPendingTransactions(safeAddress, { currentNonce })) .to.be.eventually.deep.equals({ data: { success: true } }) chai.expect(fetchData).to.have.been.calledWith({ url: `${txServiceBaseUrl}/v1/safes/${safeAddress}/multisig-transactions/?executed=false&nonce__gte=${currentNonce}`, @@ -523,7 +523,7 @@ describe('Endpoint tests', () => { it('getPendingTransactions EIP-3770', async () => { const currentNonce = 1 await chai - .expect(safeApiKit.getPendingTransactions(eip3770SafeAddress, currentNonce)) + .expect(safeApiKit.getPendingTransactions(eip3770SafeAddress, { currentNonce })) .to.be.eventually.deep.equals({ data: { success: true } }) chai.expect(fetchData).to.have.been.calledWith({ url: `${txServiceBaseUrl}/v1/safes/${safeAddress}/multisig-transactions/?executed=false&nonce__gte=${currentNonce}`, diff --git a/packages/protocol-kit/package.json b/packages/protocol-kit/package.json index 18b3322af..bef46bbdd 100644 --- a/packages/protocol-kit/package.json +++ b/packages/protocol-kit/package.json @@ -51,7 +51,6 @@ ], "homepage": "https://github.com/safe-global/safe-core-sdk#readme", "devDependencies": { - "@safe-global/safe-passkey": "0.2.0-alpha.1", "@safe-global/testing-kit": "^0.1.0", "@types/chai": "^4.3.19", "@types/chai-as-promised": "^7.1.8", diff --git a/packages/testing-kit/package.json b/packages/testing-kit/package.json index 6027d2f41..35a90d9c4 100644 --- a/packages/testing-kit/package.json +++ b/packages/testing-kit/package.json @@ -39,6 +39,7 @@ "@nomicfoundation/hardhat-viem": "^2.0.4", "@openzeppelin/contracts": "^2.5.1", "@safe-global/safe-contracts-v1.4.1": "npm:@safe-global/safe-contracts@1.4.1", + "@safe-global/safe-passkey": "0.2.0-alpha.1", "@safe-global/types-kit": "^1.0.0", "@types/semver": "^7.5.8", "hardhat": "^2.19.3",