diff --git a/apps/account-api/src/controllers/v1/delegation-v1.controller.ts b/apps/account-api/src/controllers/v1/delegation-v1.controller.ts index a3911d8a..4921af4e 100644 --- a/apps/account-api/src/controllers/v1/delegation-v1.controller.ts +++ b/apps/account-api/src/controllers/v1/delegation-v1.controller.ts @@ -33,7 +33,7 @@ export class DelegationControllerV1 { @Get(':msaId') @HttpCode(HttpStatus.OK) @ApiOperation({ summary: 'Get the delegation information associated with an MSA Id' }) - @ApiOkResponse({ description: 'Found delegation information' }) + @ApiOkResponse({ description: 'Found delegation information', type: DelegationResponse }) /** * Retrieves the delegation for a given MSA ID. * @@ -54,7 +54,10 @@ export class DelegationControllerV1 { @Get('revokeDelegation/:accountId/:providerId') @HttpCode(HttpStatus.OK) @ApiOperation({ summary: 'Get a properly encoded RevokeDelegationPayload that can be signed' }) - @ApiOkResponse({ description: 'Returned an encoded RevokeDelegationPayload for signing' }) + @ApiOkResponse({ + description: 'Returned an encoded RevokeDelegationPayload for signing', + type: RevokeDelegationPayloadResponseDto, + }) /** * Retrieves the revoke delegation payload for a given provider ID. * This encoded payload can be signed by the user to revoke the delegation to the given provider id. @@ -83,7 +86,7 @@ export class DelegationControllerV1 { @Post('revokeDelegation') @HttpCode(HttpStatus.CREATED) @ApiOperation({ summary: 'Request to revoke a delegation' }) - @ApiCreatedResponse({ description: 'Created and queued request to revoke a delegation' }) + @ApiCreatedResponse({ description: 'Created and queued request to revoke a delegation', type: TransactionResponse }) @ApiBody({ type: RevokeDelegationPayloadRequestDto }) async postRevokeDelegation( @Body() diff --git a/apps/account-api/test/setup/package.json b/apps/account-api/test/setup/package.json index 00f90e92..5d8a52aa 100644 --- a/apps/account-api/test/setup/package.json +++ b/apps/account-api/test/setup/package.json @@ -5,7 +5,6 @@ "main": "index.ts", "scripts": { "main": "tsx index.ts", - "test-revoke": "tsx test-revoke.ts", "test-revoke-e2e": "tsx test-revoke-e2e.ts", "test": "echo \"Error: no test specified\" && exit 1" }, diff --git a/apps/account-api/test/setup/test-revoke.ts b/apps/account-api/test/setup/test-revoke.ts deleted file mode 100644 index 8e675b1c..00000000 --- a/apps/account-api/test/setup/test-revoke.ts +++ /dev/null @@ -1,150 +0,0 @@ -import { ExtrinsicHelper, initialize } from '@projectlibertylabs/frequency-scenario-template'; -import log from 'loglevel'; -import { cryptoWaitReady } from '@polkadot/util-crypto'; -import Keyring from '@polkadot/keyring'; -import { hexToU8a, u8aToHex } from '@polkadot/util'; -import { SignerResult, Signer, SignerPayloadRaw, ISubmittableResult } from '@polkadot/types/types'; -import { SubmittableExtrinsic } from '@polkadot/api/types'; - -const FREQUENCY_URL = process.env.FREQUENCY_URL || 'ws://127.0.0.1:9944'; - -async function main() { - await cryptoWaitReady(); - log.setLevel('trace'); - console.log('Connecting...'); - await initialize(FREQUENCY_URL); - - // eslint-disable-next-line no-use-before-define - await revokeDelegation(); -} - -async function revokeDelegation() { - await cryptoWaitReady(); - const bobKeys = new Keyring({ type: 'sr25519' }).createFromUri('//Bob'); - - /** - * Retrieves the raw payload for signing a transaction. - * Use signAsync to properly encode the payload for signing. - * In this case we want the encoded payload for retireMsa, which does not take any arguments. - * - * @param tx - The transaction object. - * @param signerAddress - The address of the signer. - * @returns A promise that resolves to the raw payload for signing. - */ - const getRawPayloadForSigning = async ( - tx: SubmittableExtrinsic<'promise', ISubmittableResult>, - signerAddress: string, - ): Promise => { - const fakeError = '*** Interrupt signing for payload collection ***'; - let signRaw: SignerPayloadRaw; - try { - await tx.signAsync(signerAddress, { - signer: { - signRaw: (raw) => { - console.log('signRaw called with [raw]:', raw); - signRaw = raw; - // Interrupt the signing process to get the raw payload, as encoded by polkadot-js - throw new Error(fakeError); - }, - }, - }); - } catch (e: any) { - // If we encountered an actual error, re-throw it; otherwise - // ignore the fake error we threw above - if (e?.message !== fakeError) { - throw e; - } - } - return signRaw; - }; - - /** - * Returns a signer function for a given SignerResult. - * Signer will be used to pass our verified signature to the transaction without any mutation. - * - * @param result - The SignerResult object. - * @returns A Signer function that will pass the signature to the transaction without mutation. - */ - const getSignerForRawSignature = (result: SignerResult): Signer => ({ - signRaw: (raw) => { - console.log('signRaw function called with [raw]:', raw); - return Promise.resolve(result); - }, - }); - - // Get the transaction for retireMsa, will be used to get the raw payload for signing - const providerId: number = 1; - const tx = ExtrinsicHelper.apiPromise.tx.msa.revokeDelegationByDelegator(providerId); - - const signerPayload: SignerPayloadRaw = await getRawPayloadForSigning(tx, bobKeys.address); - // payload contains the signer address, the encoded data/payload for retireMsa, and the type of the payload - console.log('payload: SignerPayloadRaw: ', signerPayload); - - const { data } = signerPayload; - - // From github:https://github.com/polkadot-js/tools/issues/175 - // Use the withType option to sign the payload to get the prefix 0x01 - // which specifies the SR25519 type of the signature and avoids getting and error about an enum in the next signAsync step - const signature: Uint8Array = bobKeys.sign(data, { withType: true }); - // Confirmed: this signature is correct and can be verified with polkadot-js, if you remove the prefix 0x01 - console.log('signature:', u8aToHex(signature)); - - // Construct the SignerResult object - // SignerResult is used to get the Signer.signRaw function that will be used to pass the signature to the transaction - const prefixedSignature: SignerResult = { id: 1, signature: u8aToHex(signature) }; - console.log('prefixedSignature:', prefixedSignature); - - const signer: Signer = getSignerForRawSignature(prefixedSignature); - console.log('signer:', signer); - - const { nonce } = await ExtrinsicHelper.apiPromise.query.system.account(bobKeys.address); - console.log('nonce:', nonce.toHuman()); - - // Here submittableExtrinsic is the retireMsa transaction - // signer uses signRaw to pass the original signature to the transaction - // This makes sure that the signature is not mutated in any way - // Avoiding tx.addSignature() because it seems to be mutating the signature and causing the transaction to fail - // tx.addSignature(bobKeys.address, prefixedSignature.signature, signer); - - // 1. Attempt to sign the transaction with the signature using addSignature() - // Result: 1010: Invalid Transaction: Transaction has a bad signature - // Reason: I think the payload does not match because ExtrinsicPayload is complex and not filled in correctly - // - // 2. Attempt to use api.createType() to build the ExtrinsicPayload - // Result: Too complicated to build the entire extrinsic manually. - - // const extrinsicPayload: ExtrinsicPayloadValue = { - // method: tx.toHex(), - // nonce, - // specVersion: - // genesisHash: tx.genesisHash, - // blockHash: tx.blockHash, - // }; - const dataUint8Array = hexToU8a(data); - console.log('dataUint8Array.length:', dataUint8Array.length); - tx.addSignature(bobKeys.address, signature, tx.toU8a()); - - const submittableExtrinsic = await tx.signAsync(bobKeys.address, { nonce, signer }); - console.log('tx.signature:', tx.signature.toHex()); - - await new Promise((resolve, reject) => { - submittableExtrinsic.send(({ status, dispatchError }) => { - if (dispatchError) { - console.error('ERROR: ', dispatchError.toHuman()); - reject(dispatchError.toJSON()); - } else if (status.isInBlock || status.isFinalized) { - console.log('SUCCESS!'); - resolve(); - } else { - console.log('STATUS: ', status.toHuman()); - } - }); - }); -} - -main() - .catch((r) => { - console.error(r); - process.exit(1); - }) - .finally(process.exit); diff --git a/docker-compose-e2e.account.yaml b/docker-compose-e2e.account.yaml index d24c62f9..83726e15 100644 --- a/docker-compose-e2e.account.yaml +++ b/docker-compose-e2e.account.yaml @@ -32,16 +32,13 @@ services: - e2e frequency: - image: dsnp/instant-seal-node-with-deployed-schemas:latest - # We need to specify the platform because it's the only image - # built by Frequency at the moment, and auto-pull won't work otherwise - platform: linux/amd64 - # SEALING_MODE set to insstant for e2e testing - environment: - - SEALING_MODE=interval - - SEALING_INTERVAL=1 - profiles: + profiles: - e2e + - local-node + + mock-webhook-server: + profiles: + - skip ipfs: profiles: diff --git a/libs/account-lib/src/blockchain/blockchain-constants.ts b/libs/account-lib/src/blockchain/blockchain-constants.ts index 1b29c95a..d2d8e6d3 100644 --- a/libs/account-lib/src/blockchain/blockchain-constants.ts +++ b/libs/account-lib/src/blockchain/blockchain-constants.ts @@ -31,9 +31,6 @@ export namespace BlockchainConstants { export const SECONDS_PER_BLOCK = 12; - // Default expiration time for a block, same as SIWF - export const BLOCK_EXPIRATION_SECS = 10 * 60; // 10 minutes - /** * The number of blocks to crawl for a given job * @type {number} diff --git a/openapi-specs/account.openapi.json b/openapi-specs/account.openapi.json index 96e8812d..41708c78 100644 --- a/openapi-specs/account.openapi.json +++ b/openapi-specs/account.openapi.json @@ -131,7 +131,14 @@ ], "responses": { "200": { - "description": "Found delegation information" + "description": "Found delegation information", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DelegationResponse" + } + } + } } }, "tags": [ @@ -163,7 +170,14 @@ ], "responses": { "200": { - "description": "Returned an encoded RevokeDelegationPayload for signing" + "description": "Returned an encoded RevokeDelegationPayload for signing", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RevokeDelegationPayloadResponseDto" + } + } + } } }, "tags": [ @@ -188,7 +202,14 @@ }, "responses": { "201": { - "description": "Created and queued request to revoke a delegation" + "description": "Created and queued request to revoke a delegation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TransactionResponse" + } + } + } } }, "tags": [ @@ -622,6 +643,48 @@ "referenceId" ] }, + "DelegationResponse": { + "type": "object", + "properties": { + "providerId": { + "type": "string" + }, + "schemaPermissions": { + "type": "object" + }, + "revokedAt": { + "type": "object" + } + }, + "required": [ + "providerId", + "schemaPermissions", + "revokedAt" + ] + }, + "RevokeDelegationPayloadResponseDto": { + "type": "object", + "properties": { + "accountId": { + "type": "string" + }, + "providerId": { + "type": "string" + }, + "encodedExtrinsic": { + "type": "object" + }, + "payloadToSign": { + "type": "object" + } + }, + "required": [ + "accountId", + "providerId", + "encodedExtrinsic", + "payloadToSign" + ] + }, "RevokeDelegationPayloadRequestDto": { "type": "object", "properties": { @@ -649,6 +712,17 @@ "signature" ] }, + "TransactionResponse": { + "type": "object", + "properties": { + "referenceId": { + "type": "string" + } + }, + "required": [ + "referenceId" + ] + }, "HandlePayloadDto": { "type": "object", "properties": {