From 44ff4efa11ec918c135c93f74934ca0989659e40 Mon Sep 17 00:00:00 2001 From: Miguel Angel Rojo Fernandez Date: Mon, 21 Oct 2024 16:36:12 +0100 Subject: [PATCH 01/35] feat: first commit --- packages/aws-kms-adapter/src/KMSVeChainProvider.ts | 4 +--- .../vechain-private-key-signer/vechain-private-key-signer.ts | 1 - 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/packages/aws-kms-adapter/src/KMSVeChainProvider.ts b/packages/aws-kms-adapter/src/KMSVeChainProvider.ts index 51ae37287..65ea833e6 100644 --- a/packages/aws-kms-adapter/src/KMSVeChainProvider.ts +++ b/packages/aws-kms-adapter/src/KMSVeChainProvider.ts @@ -15,7 +15,6 @@ import { KMSVeChainSigner } from './KMSVeChainSigner'; class KMSVeChainProvider extends VeChainProvider { private readonly kmsClient: KMSClient; - private readonly keyId: string; private signer?: KMSVeChainSigner; /** @@ -27,7 +26,7 @@ class KMSVeChainProvider extends VeChainProvider { **/ public constructor( thorClient: ThorClient, - keyId: string, + readonly keyId: string, region: string, credentials?: { accessKeyId: string; @@ -37,7 +36,6 @@ class KMSVeChainProvider extends VeChainProvider { endpoint?: string ) { super(thorClient); - this.keyId = keyId; this.kmsClient = endpoint !== undefined ? new KMSClient({ diff --git a/packages/network/src/signer/signers/vechain-private-key-signer/vechain-private-key-signer.ts b/packages/network/src/signer/signers/vechain-private-key-signer/vechain-private-key-signer.ts index fc1a47744..5385973c0 100644 --- a/packages/network/src/signer/signers/vechain-private-key-signer/vechain-private-key-signer.ts +++ b/packages/network/src/signer/signers/vechain-private-key-signer/vechain-private-key-signer.ts @@ -271,7 +271,6 @@ class VeChainPrivateKeySigner extends VeChainAbstractSigner { * * @param unsignedTransactionBody - The unsigned transaction body to sign. * @param originPrivateKey - The private key of the origin account. - * @param - (Optional) The private key of the delegator account. * @param thorClient - The ThorClient instance. * @param delegatorOptions - Optional parameters for the request. Includes the `delegatorUrl` and `delegatorPrivateKey` fields. * Only one of the following options can be specified: `delegatorUrl`, `delegatorPrivateKey`. From 706c68e00a343d96901c930bc9364f280ec6e4b9 Mon Sep 17 00:00:00 2001 From: Miguel Angel Rojo Fernandez Date: Mon, 21 Oct 2024 16:45:35 +0100 Subject: [PATCH 02/35] feat: second commit --- .../aws-kms-adapter/src/KMSVeChainSigner.ts | 30 +++++++++++++------ 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/packages/aws-kms-adapter/src/KMSVeChainSigner.ts b/packages/aws-kms-adapter/src/KMSVeChainSigner.ts index eedd231ea..62d61ce32 100644 --- a/packages/aws-kms-adapter/src/KMSVeChainSigner.ts +++ b/packages/aws-kms-adapter/src/KMSVeChainSigner.ts @@ -22,19 +22,31 @@ import { KMSVeChainProvider } from './KMSVeChainProvider'; class KMSVeChainSigner extends VeChainAbstractSigner { private readonly kmsVeChainProvider?: KMSVeChainProvider; + private readonly kmsVeChainDelegatorProvider?: KMSVeChainProvider; - public constructor(provider?: AvailableVeChainProviders) { + public constructor(provider: AvailableVeChainProviders); + public constructor( + provider: AvailableVeChainProviders, + delegatorProvider: AvailableVeChainProviders + ); + + public constructor( + provider?: AvailableVeChainProviders, + readonly delegatorProvider?: AvailableVeChainProviders + ) { super(provider); - if (this.provider !== undefined) { - if (!(this.provider instanceof KMSVeChainProvider)) { - throw new JSONRPCInvalidParams( - 'KMSVeChainSigner.constructor', - 'The provider must be an instance of KMSVeChainProvider.', - { provider } - ); - } + if ( + this.provider !== undefined && + this.provider instanceof KMSVeChainProvider + ) { this.kmsVeChainProvider = this.provider; } + if ( + this.delegatorProvider !== undefined && + this.delegatorProvider instanceof KMSVeChainProvider + ) { + this.kmsVeChainDelegatorProvider = this.delegatorProvider; + } } /** From d45caaf5bcd23503da95acdb3753930ebf3883a4 Mon Sep 17 00:00:00 2001 From: Miguel Angel Rojo Fernandez Date: Mon, 21 Oct 2024 16:46:48 +0100 Subject: [PATCH 03/35] feat: second commit --- packages/aws-kms-adapter/src/KMSVeChainSigner.ts | 6 ------ 1 file changed, 6 deletions(-) diff --git a/packages/aws-kms-adapter/src/KMSVeChainSigner.ts b/packages/aws-kms-adapter/src/KMSVeChainSigner.ts index 62d61ce32..2d223d03b 100644 --- a/packages/aws-kms-adapter/src/KMSVeChainSigner.ts +++ b/packages/aws-kms-adapter/src/KMSVeChainSigner.ts @@ -24,12 +24,6 @@ class KMSVeChainSigner extends VeChainAbstractSigner { private readonly kmsVeChainProvider?: KMSVeChainProvider; private readonly kmsVeChainDelegatorProvider?: KMSVeChainProvider; - public constructor(provider: AvailableVeChainProviders); - public constructor( - provider: AvailableVeChainProviders, - delegatorProvider: AvailableVeChainProviders - ); - public constructor( provider?: AvailableVeChainProviders, readonly delegatorProvider?: AvailableVeChainProviders From 694079834da36d8e8072d7bd7af10c7633b4c20a Mon Sep 17 00:00:00 2001 From: Miguel Angel Rojo Fernandez Date: Mon, 21 Oct 2024 16:51:18 +0100 Subject: [PATCH 04/35] feat: second commit --- .../tests/KMSVeChainSigner.unit.test.ts | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/packages/aws-kms-adapter/tests/KMSVeChainSigner.unit.test.ts b/packages/aws-kms-adapter/tests/KMSVeChainSigner.unit.test.ts index bb6313b88..6a0272700 100644 --- a/packages/aws-kms-adapter/tests/KMSVeChainSigner.unit.test.ts +++ b/packages/aws-kms-adapter/tests/KMSVeChainSigner.unit.test.ts @@ -1,5 +1,5 @@ import { Hex, Txt, type vechain_sdk_core_ethers } from '@vechain/sdk-core'; -import { JSONRPCInvalidParams, SignerMethodError } from '@vechain/sdk-errors'; +import { SignerMethodError } from '@vechain/sdk-errors'; import { VeChainProvider, type ThorClient, @@ -23,21 +23,20 @@ jest.mock('asn1js', () => ({ */ describe('KMSVeChainSigner', () => { describe('constructor', () => { - it('should break if the provider is not a KMSVeChainProvider', () => { + it('should instantiate a KMSVeChainSigner even though it is not a KMSVeChainProvider', () => { expect( - () => - new KMSVeChainSigner( - new VeChainProvider({} as unknown as ThorClient) - ) - ).toThrow(JSONRPCInvalidParams); + new KMSVeChainSigner( + new VeChainProvider({} as unknown as ThorClient) + ) + ).toBeInstanceOf(KMSVeChainSigner); }); }); describe('connect', () => { - it('should break if the provider is not a KMSVeChainProvider', () => { + it('should return a KMSVeChainSigner even though it is not a KMSVeChainProvider', () => { const signer = new KMSVeChainSigner(); - expect(() => + expect( signer.connect(new VeChainProvider({} as unknown as ThorClient)) - ).toThrow(SignerMethodError); + ).toBeInstanceOf(KMSVeChainSigner); }); }); describe('getAddress', () => { From 64b375f94ab07a9861bce8aef895c77365af9799 Mon Sep 17 00:00:00 2001 From: Miguel Angel Rojo Fernandez Date: Mon, 21 Oct 2024 16:57:12 +0100 Subject: [PATCH 05/35] feat: second commit --- packages/aws-kms-adapter/src/KMSVeChainSigner.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/aws-kms-adapter/src/KMSVeChainSigner.ts b/packages/aws-kms-adapter/src/KMSVeChainSigner.ts index 2d223d03b..ecf51d03b 100644 --- a/packages/aws-kms-adapter/src/KMSVeChainSigner.ts +++ b/packages/aws-kms-adapter/src/KMSVeChainSigner.ts @@ -133,6 +133,10 @@ class KMSVeChainSigner extends VeChainAbstractSigner { private async buildVeChainSignatureFromPayload( payload: Uint8Array ): Promise { + if (this.kmsVeChainDelegatorProvider !== undefined) { + // TODO: Implement the delegation signature + } + if (this.kmsVeChainProvider === undefined) { throw new JSONRPCInvalidParams( 'KMSVeChainSigner.buildVeChainSignatureFromPayload', From fbf7a6baee0318f9ad31f1a6c16fb7933efc2766 Mon Sep 17 00:00:00 2001 From: Miguel Angel Rojo Fernandez Date: Mon, 21 Oct 2024 18:00:18 +0100 Subject: [PATCH 06/35] feat: second commit --- packages/aws-kms-adapter/src/KMSVeChainSigner.ts | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/packages/aws-kms-adapter/src/KMSVeChainSigner.ts b/packages/aws-kms-adapter/src/KMSVeChainSigner.ts index ecf51d03b..1ba2fcc4c 100644 --- a/packages/aws-kms-adapter/src/KMSVeChainSigner.ts +++ b/packages/aws-kms-adapter/src/KMSVeChainSigner.ts @@ -26,7 +26,10 @@ class KMSVeChainSigner extends VeChainAbstractSigner { public constructor( provider?: AvailableVeChainProviders, - readonly delegatorProvider?: AvailableVeChainProviders + readonly delegator?: { + provider?: AvailableVeChainProviders; + url?: string; + } ) { super(provider); if ( @@ -36,10 +39,10 @@ class KMSVeChainSigner extends VeChainAbstractSigner { this.kmsVeChainProvider = this.provider; } if ( - this.delegatorProvider !== undefined && - this.delegatorProvider instanceof KMSVeChainProvider + this.delegator !== undefined && + this.delegator.provider instanceof KMSVeChainProvider ) { - this.kmsVeChainDelegatorProvider = this.delegatorProvider; + this.kmsVeChainDelegatorProvider = this.delegator.provider; } } From b2a10d91b139bb5dfe25dea6956a4e96f7141bca Mon Sep 17 00:00:00 2001 From: Miguel Angel Rojo Fernandez Date: Tue, 22 Oct 2024 10:09:44 +0100 Subject: [PATCH 07/35] feat: more changes --- .../aws-kms-adapter/src/KMSVeChainSigner.ts | 64 +++++++++++++++---- 1 file changed, 51 insertions(+), 13 deletions(-) diff --git a/packages/aws-kms-adapter/src/KMSVeChainSigner.ts b/packages/aws-kms-adapter/src/KMSVeChainSigner.ts index 1ba2fcc4c..4814b2fc6 100644 --- a/packages/aws-kms-adapter/src/KMSVeChainSigner.ts +++ b/packages/aws-kms-adapter/src/KMSVeChainSigner.ts @@ -12,7 +12,9 @@ import { import { JSONRPCInvalidParams, SignerMethodError } from '@vechain/sdk-errors'; import { type AvailableVeChainProviders, + DelegationHandler, RPC_METHODS, + type ThorClient, type TransactionRequestInput, VeChainAbstractSigner } from '@vechain/sdk-network'; @@ -23,6 +25,7 @@ import { KMSVeChainProvider } from './KMSVeChainProvider'; class KMSVeChainSigner extends VeChainAbstractSigner { private readonly kmsVeChainProvider?: KMSVeChainProvider; private readonly kmsVeChainDelegatorProvider?: KMSVeChainProvider; + private readonly kmsVeChainDelegatorUrl?: string; public constructor( provider?: AvailableVeChainProviders, @@ -38,11 +41,21 @@ class KMSVeChainSigner extends VeChainAbstractSigner { ) { this.kmsVeChainProvider = this.provider; } - if ( - this.delegator !== undefined && - this.delegator.provider instanceof KMSVeChainProvider - ) { - this.kmsVeChainDelegatorProvider = this.delegator.provider; + if (this.delegator !== undefined) { + if ( + this.delegator.provider !== undefined && + this.delegator.provider instanceof KMSVeChainProvider + ) { + this.kmsVeChainDelegatorProvider = this.delegator.provider; + } else if (this.delegator.url !== undefined) { + this.kmsVeChainDelegatorUrl = this.delegator.url; + } else { + throw new JSONRPCInvalidParams( + 'KMSVeChainSigner.constructor', + 'The delegator object is not well formed, either provider or url should be provided.', + { delegator: this.delegator } + ); + } } } @@ -136,10 +149,6 @@ class KMSVeChainSigner extends VeChainAbstractSigner { private async buildVeChainSignatureFromPayload( payload: Uint8Array ): Promise { - if (this.kmsVeChainDelegatorProvider !== undefined) { - // TODO: Implement the delegation signature - } - if (this.kmsVeChainProvider === undefined) { throw new JSONRPCInvalidParams( 'KMSVeChainSigner.buildVeChainSignatureFromPayload', @@ -203,6 +212,26 @@ class KMSVeChainSigner extends VeChainAbstractSigner { ); } + private async appendSignatureIfDelegationUrl( + transaction: Transaction, + originSignature: Uint8Array + ): Promise { + if (this.kmsVeChainDelegatorUrl !== undefined) { + const originAddress = await this.getAddress(); + const delegatorSignature = await DelegationHandler({ + delegatorUrl: this.kmsVeChainDelegatorUrl + }).getDelegationSignatureUsingUrl( + transaction, + originAddress, + (this.kmsVeChainProvider?.thorClient as ThorClient).httpClient + ); + + return concatBytes(originSignature, delegatorSignature); + } + + return originSignature; + } + /** * It signs a transaction. * @param transactionToSign Transaction body to sign in plain format. @@ -213,18 +242,27 @@ class KMSVeChainSigner extends VeChainAbstractSigner { ): Promise { try { // Populate the call, to get proper from and to address (compatible with multi-clause transactions) - const populatedTransaction = + const transactionBody = await this.populateTransaction(transactionToSign); + // Get the transaction object + const transaction = Transaction.of(transactionBody); + // Get the transaction hash - const transactionHash = - Transaction.of(populatedTransaction).getTransactionHash().bytes; + const transactionHash = transaction.getTransactionHash().bytes; + // Sign the transaction hash using origin key const veChainSignature = await this.buildVeChainSignatureFromPayload(transactionHash); + // Sign the transaction hash using the delegation key if needed and append the result + const signature = await this.appendSignatureIfDelegationUrl( + transaction, + veChainSignature + ); + return Hex.of( - Transaction.of(populatedTransaction, veChainSignature).encoded + Transaction.of(transactionBody, signature).encoded ).toString(); } catch (error) { throw new SignerMethodError( From 987f0e4676fd28a9b5845bf71b9a3a9fff3897e6 Mon Sep 17 00:00:00 2001 From: Miguel Angel Rojo Fernandez Date: Tue, 22 Oct 2024 10:11:21 +0100 Subject: [PATCH 08/35] feat: more changes --- packages/aws-kms-adapter/src/KMSVeChainSigner.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/aws-kms-adapter/src/KMSVeChainSigner.ts b/packages/aws-kms-adapter/src/KMSVeChainSigner.ts index 4814b2fc6..169f4d56e 100644 --- a/packages/aws-kms-adapter/src/KMSVeChainSigner.ts +++ b/packages/aws-kms-adapter/src/KMSVeChainSigner.ts @@ -212,6 +212,12 @@ class KMSVeChainSigner extends VeChainAbstractSigner { ); } + /** + * Append the delegator signature to the origin signature if the delegator URL is set. + * @param transaction Transaction to sign. + * @param originSignature Origin signature. + * @returns Both signatures concatenated if the delegator URL is set, the origin signature otherwise. + */ private async appendSignatureIfDelegationUrl( transaction: Transaction, originSignature: Uint8Array From 9c1864b117762cafbd12b0fda344665d05adf0fd Mon Sep 17 00:00:00 2001 From: Miguel Angel Rojo Fernandez Date: Tue, 22 Oct 2024 10:12:14 +0100 Subject: [PATCH 09/35] feat: more changes --- packages/aws-kms-adapter/src/KMSVeChainSigner.ts | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/packages/aws-kms-adapter/src/KMSVeChainSigner.ts b/packages/aws-kms-adapter/src/KMSVeChainSigner.ts index 169f4d56e..0bf4f7a69 100644 --- a/packages/aws-kms-adapter/src/KMSVeChainSigner.ts +++ b/packages/aws-kms-adapter/src/KMSVeChainSigner.ts @@ -14,7 +14,6 @@ import { type AvailableVeChainProviders, DelegationHandler, RPC_METHODS, - type ThorClient, type TransactionRequestInput, VeChainAbstractSigner } from '@vechain/sdk-network'; @@ -214,22 +213,25 @@ class KMSVeChainSigner extends VeChainAbstractSigner { /** * Append the delegator signature to the origin signature if the delegator URL is set. - * @param transaction Transaction to sign. - * @param originSignature Origin signature. + * @param {Transaction} transaction Transaction to sign. + * @param {Uint8Array} originSignature Origin signature. * @returns Both signatures concatenated if the delegator URL is set, the origin signature otherwise. */ private async appendSignatureIfDelegationUrl( transaction: Transaction, originSignature: Uint8Array ): Promise { - if (this.kmsVeChainDelegatorUrl !== undefined) { + if ( + this.kmsVeChainDelegatorUrl !== undefined && + this.provider !== undefined + ) { const originAddress = await this.getAddress(); const delegatorSignature = await DelegationHandler({ delegatorUrl: this.kmsVeChainDelegatorUrl }).getDelegationSignatureUsingUrl( transaction, originAddress, - (this.kmsVeChainProvider?.thorClient as ThorClient).httpClient + this.provider.thorClient.httpClient ); return concatBytes(originSignature, delegatorSignature); From e981f814622c02c642972b4b9d9a3b8b91cb9cc0 Mon Sep 17 00:00:00 2001 From: Miguel Angel Rojo Fernandez Date: Tue, 22 Oct 2024 10:14:41 +0100 Subject: [PATCH 10/35] feat: more changes --- packages/aws-kms-adapter/src/KMSVeChainSigner.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/aws-kms-adapter/src/KMSVeChainSigner.ts b/packages/aws-kms-adapter/src/KMSVeChainSigner.ts index 0bf4f7a69..3b0d1bbaf 100644 --- a/packages/aws-kms-adapter/src/KMSVeChainSigner.ts +++ b/packages/aws-kms-adapter/src/KMSVeChainSigner.ts @@ -212,12 +212,12 @@ class KMSVeChainSigner extends VeChainAbstractSigner { } /** - * Append the delegator signature to the origin signature if the delegator URL is set. + * Prepend the origin signature to the delegator signature if the delegator URL is set. * @param {Transaction} transaction Transaction to sign. * @param {Uint8Array} originSignature Origin signature. * @returns Both signatures concatenated if the delegator URL is set, the origin signature otherwise. */ - private async appendSignatureIfDelegationUrl( + private async prependSignatureIfDelegationUrl( transaction: Transaction, originSignature: Uint8Array ): Promise { @@ -263,8 +263,8 @@ class KMSVeChainSigner extends VeChainAbstractSigner { const veChainSignature = await this.buildVeChainSignatureFromPayload(transactionHash); - // Sign the transaction hash using the delegation key if needed and append the result - const signature = await this.appendSignatureIfDelegationUrl( + // Sign the transaction hash using the delegation key if needed + const signature = await this.prependSignatureIfDelegationUrl( transaction, veChainSignature ); From e445381d04eb43b49523bab3c8dfb743c5b04828 Mon Sep 17 00:00:00 2001 From: Miguel Angel Rojo Fernandez Date: Tue, 22 Oct 2024 10:17:05 +0100 Subject: [PATCH 11/35] feat: more changes --- packages/aws-kms-adapter/src/KMSVeChainSigner.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/aws-kms-adapter/src/KMSVeChainSigner.ts b/packages/aws-kms-adapter/src/KMSVeChainSigner.ts index 3b0d1bbaf..30cf56173 100644 --- a/packages/aws-kms-adapter/src/KMSVeChainSigner.ts +++ b/packages/aws-kms-adapter/src/KMSVeChainSigner.ts @@ -212,12 +212,12 @@ class KMSVeChainSigner extends VeChainAbstractSigner { } /** - * Prepend the origin signature to the delegator signature if the delegator URL is set. + * Prepend the origin signature to the delegator signature if the delegator is set. * @param {Transaction} transaction Transaction to sign. * @param {Uint8Array} originSignature Origin signature. - * @returns Both signatures concatenated if the delegator URL is set, the origin signature otherwise. + * @returns Both signatures concatenated if the delegator is set, the origin signature otherwise. */ - private async prependSignatureIfDelegationUrl( + private async prependSignatureIfDelegation( transaction: Transaction, originSignature: Uint8Array ): Promise { @@ -263,8 +263,8 @@ class KMSVeChainSigner extends VeChainAbstractSigner { const veChainSignature = await this.buildVeChainSignatureFromPayload(transactionHash); - // Sign the transaction hash using the delegation key if needed - const signature = await this.prependSignatureIfDelegationUrl( + // Sign the transaction hash using delegation if needed + const signature = await this.prependSignatureIfDelegation( transaction, veChainSignature ); From c0dd18587af574157dd8d376c1de6e9fdbcbc701 Mon Sep 17 00:00:00 2001 From: Miguel Angel Rojo Fernandez Date: Tue, 22 Oct 2024 10:27:10 +0100 Subject: [PATCH 12/35] feat: more changes --- .../aws-kms-adapter/src/KMSVeChainSigner.ts | 45 ++++++++++--------- 1 file changed, 25 insertions(+), 20 deletions(-) diff --git a/packages/aws-kms-adapter/src/KMSVeChainSigner.ts b/packages/aws-kms-adapter/src/KMSVeChainSigner.ts index 30cf56173..e76474448 100644 --- a/packages/aws-kms-adapter/src/KMSVeChainSigner.ts +++ b/packages/aws-kms-adapter/src/KMSVeChainSigner.ts @@ -143,12 +143,14 @@ class KMSVeChainSigner extends VeChainAbstractSigner { /** * It builds a VeChain signature from a bytes payload. * @param {Uint8Array} payload to sign. + * @param {KMSVeChainProvider} kmsProvider The provider to sign the payload. * @returns {Uint8Array} The signature following the VeChain format. */ private async buildVeChainSignatureFromPayload( - payload: Uint8Array + payload: Uint8Array, + kmsProvider: KMSVeChainProvider | undefined = this.kmsVeChainProvider ): Promise { - if (this.kmsVeChainProvider === undefined) { + if (kmsProvider === undefined) { throw new JSONRPCInvalidParams( 'KMSVeChainSigner.buildVeChainSignatureFromPayload', 'Thor provider is not found into the signer. Please attach a Provider to your signer instance.', @@ -157,7 +159,7 @@ class KMSVeChainSigner extends VeChainAbstractSigner { } // Sign the transaction hash - const signature = await this.kmsVeChainProvider.sign(payload); + const signature = await kmsProvider.sign(payload); // Build the VeChain signature using the r, s and v components const hexSignature = bytesToHex(signature); @@ -212,16 +214,28 @@ class KMSVeChainSigner extends VeChainAbstractSigner { } /** - * Prepend the origin signature to the delegator signature if the delegator is set. + * Concat the origin signature to the delegator signature if the delegator is set. * @param {Transaction} transaction Transaction to sign. - * @param {Uint8Array} originSignature Origin signature. * @returns Both signatures concatenated if the delegator is set, the origin signature otherwise. */ - private async prependSignatureIfDelegation( - transaction: Transaction, - originSignature: Uint8Array + private async concatSignatureIfDelegation( + transaction: Transaction ): Promise { - if ( + // Get the transaction hash + const transactionHash = transaction.getTransactionHash().bytes; + + // Sign the transaction hash using origin key + const originSignature = + await this.buildVeChainSignatureFromPayload(transactionHash); + + if (this.kmsVeChainDelegatorProvider !== undefined) { + const delegatorSignature = + await this.buildVeChainSignatureFromPayload( + transactionHash, + this.kmsVeChainDelegatorProvider + ); + return concatBytes(originSignature, delegatorSignature); + } else if ( this.kmsVeChainDelegatorUrl !== undefined && this.provider !== undefined ) { @@ -256,18 +270,9 @@ class KMSVeChainSigner extends VeChainAbstractSigner { // Get the transaction object const transaction = Transaction.of(transactionBody); - // Get the transaction hash - const transactionHash = transaction.getTransactionHash().bytes; - - // Sign the transaction hash using origin key - const veChainSignature = - await this.buildVeChainSignatureFromPayload(transactionHash); - // Sign the transaction hash using delegation if needed - const signature = await this.prependSignatureIfDelegation( - transaction, - veChainSignature - ); + const signature = + await this.concatSignatureIfDelegation(transaction); return Hex.of( Transaction.of(transactionBody, signature).encoded From e6fe9291cfa2c7f4f170fc017b57f11da6f6e8dc Mon Sep 17 00:00:00 2001 From: Miguel Angel Rojo Fernandez Date: Tue, 22 Oct 2024 12:11:40 +0100 Subject: [PATCH 13/35] feat: more changes --- .../aws-kms-adapter/src/KMSVeChainSigner.ts | 49 +++++++++++++------ .../tests/KMSVeChainSigner.unit.test.ts | 19 +++---- 2 files changed, 44 insertions(+), 24 deletions(-) diff --git a/packages/aws-kms-adapter/src/KMSVeChainSigner.ts b/packages/aws-kms-adapter/src/KMSVeChainSigner.ts index e76474448..cc19417ed 100644 --- a/packages/aws-kms-adapter/src/KMSVeChainSigner.ts +++ b/packages/aws-kms-adapter/src/KMSVeChainSigner.ts @@ -33,13 +33,21 @@ class KMSVeChainSigner extends VeChainAbstractSigner { url?: string; } ) { + // Origin provider super(provider); - if ( - this.provider !== undefined && - this.provider instanceof KMSVeChainProvider - ) { - this.kmsVeChainProvider = this.provider; + if (this.provider !== undefined) { + if (this.provider instanceof KMSVeChainProvider) { + this.kmsVeChainProvider = this.provider; + } else { + throw new JSONRPCInvalidParams( + 'KMSVeChainSigner.constructor', + 'The provider object is not well formed, it should be an instance of KMSVeChainProvider.', + { provider: this.provider } + ); + } } + + // Delegator provider, if any if (this.delegator !== undefined) { if ( this.delegator.provider !== undefined && @@ -110,25 +118,31 @@ class KMSVeChainSigner extends VeChainAbstractSigner { * Gets the DER-encoded public key from KMS and decodes it. * @returns {Uint8Array} The decoded public key. */ - private async getDecodedPublicKey(): Promise { - if (this.kmsVeChainProvider === undefined) { + private async getDecodedPublicKey( + kmsProvider: KMSVeChainProvider | undefined = this.kmsVeChainProvider + ): Promise { + if (kmsProvider === undefined) { throw new JSONRPCInvalidParams( 'KMSVeChainSigner.getDecodedPublicKey', 'Thor provider is not found into the signer. Please attach a Provider to your signer instance.', {} ); } - const publicKey = await this.kmsVeChainProvider.getPublicKey(); + const publicKey = await kmsProvider.getPublicKey(); return this.decodePublicKey(publicKey); } /** * It returns the address associated with the signer. + * @param {KMSVeChainProvider} kmsProvider (Optional) The provider to get the address from. * @returns The address associated with the signer. */ - public async getAddress(): Promise { + public async getAddress( + kmsProvider: KMSVeChainProvider | undefined = this.kmsVeChainProvider + ): Promise { try { - const publicKeyDecoded = await this.getDecodedPublicKey(); + const publicKeyDecoded = + await this.getDecodedPublicKey(kmsProvider); return Address.ofPublicKey(publicKeyDecoded).toString(); } catch (error) { throw new SignerMethodError( @@ -168,7 +182,8 @@ class KMSVeChainSigner extends VeChainAbstractSigner { const recoveryBit = await this.getRecoveryBit( decodedSignatureWithoutRecoveryBit, - payload + payload, + kmsProvider ); const decodedSignature = concatBytes( @@ -181,15 +196,17 @@ class KMSVeChainSigner extends VeChainAbstractSigner { /** * Returns the recovery bit of a signature. - * @param decodedSignatureWithoutRecoveryBit Signature with the R and S components only. - * @param transactionHash Raw transaction hash. + * @param {SignatureType} decodedSignatureWithoutRecoveryBit Signature with the R and S components only. + * @param {Uint8Array} transactionHash Raw transaction hash. + * @param {KMSVeChainProvider} kmsProvider The provider to sign the payload. * @returns {number} The V component of the signature (either 0 or 1). */ private async getRecoveryBit( decodedSignatureWithoutRecoveryBit: SignatureType, - transactionHash: Uint8Array + transactionHash: Uint8Array, + kmsProvider: KMSVeChainProvider | undefined = this.kmsVeChainProvider ): Promise { - const publicKey = await this.getDecodedPublicKey(); + const publicKey = await this.getDecodedPublicKey(kmsProvider); const publicKeyHex = toHex(publicKey); for (let i = 0n; i < 2n; i++) { @@ -228,6 +245,7 @@ class KMSVeChainSigner extends VeChainAbstractSigner { const originSignature = await this.buildVeChainSignatureFromPayload(transactionHash); + // We try first in case there is a delegator provider if (this.kmsVeChainDelegatorProvider !== undefined) { const delegatorSignature = await this.buildVeChainSignatureFromPayload( @@ -236,6 +254,7 @@ class KMSVeChainSigner extends VeChainAbstractSigner { ); return concatBytes(originSignature, delegatorSignature); } else if ( + // If not, we try with the delegator URL this.kmsVeChainDelegatorUrl !== undefined && this.provider !== undefined ) { diff --git a/packages/aws-kms-adapter/tests/KMSVeChainSigner.unit.test.ts b/packages/aws-kms-adapter/tests/KMSVeChainSigner.unit.test.ts index 6a0272700..bb6313b88 100644 --- a/packages/aws-kms-adapter/tests/KMSVeChainSigner.unit.test.ts +++ b/packages/aws-kms-adapter/tests/KMSVeChainSigner.unit.test.ts @@ -1,5 +1,5 @@ import { Hex, Txt, type vechain_sdk_core_ethers } from '@vechain/sdk-core'; -import { SignerMethodError } from '@vechain/sdk-errors'; +import { JSONRPCInvalidParams, SignerMethodError } from '@vechain/sdk-errors'; import { VeChainProvider, type ThorClient, @@ -23,20 +23,21 @@ jest.mock('asn1js', () => ({ */ describe('KMSVeChainSigner', () => { describe('constructor', () => { - it('should instantiate a KMSVeChainSigner even though it is not a KMSVeChainProvider', () => { + it('should break if the provider is not a KMSVeChainProvider', () => { expect( - new KMSVeChainSigner( - new VeChainProvider({} as unknown as ThorClient) - ) - ).toBeInstanceOf(KMSVeChainSigner); + () => + new KMSVeChainSigner( + new VeChainProvider({} as unknown as ThorClient) + ) + ).toThrow(JSONRPCInvalidParams); }); }); describe('connect', () => { - it('should return a KMSVeChainSigner even though it is not a KMSVeChainProvider', () => { + it('should break if the provider is not a KMSVeChainProvider', () => { const signer = new KMSVeChainSigner(); - expect( + expect(() => signer.connect(new VeChainProvider({} as unknown as ThorClient)) - ).toBeInstanceOf(KMSVeChainSigner); + ).toThrow(SignerMethodError); }); }); describe('getAddress', () => { From 465a9c6b265ec49015fd7ff641506905cb93811c Mon Sep 17 00:00:00 2001 From: Miguel Angel Rojo Fernandez Date: Tue, 22 Oct 2024 12:23:55 +0100 Subject: [PATCH 14/35] feat: more changes --- docker-compose.localstack.yml | 2 +- localstack/init/kms.sh | 10 ++++- packages/aws-kms-adapter/README.md | 38 ++++++++++--------- .../tests/KMSVeChainSigner.solo.test.ts | 8 ++-- .../tests/test-aws-credentials.json | 28 ++++++++++---- 5 files changed, 53 insertions(+), 33 deletions(-) diff --git a/docker-compose.localstack.yml b/docker-compose.localstack.yml index c011b62a9..f4d6c91a1 100644 --- a/docker-compose.localstack.yml +++ b/docker-compose.localstack.yml @@ -27,7 +27,7 @@ services: - CMD - bash - -c - - $$(awslocal kms list-keys | jq '.Keys | length | . == 1') || exit 1; # There is 1 key at the moment + - $$(awslocal kms list-keys | jq '.Keys | length | . == 2') || exit 1; # There are 2 keys at the moment interval: 5s timeout: 20s start_period: 2s diff --git a/localstack/init/kms.sh b/localstack/init/kms.sh index 77f7b995a..5db2db6bd 100755 --- a/localstack/init/kms.sh +++ b/localstack/init/kms.sh @@ -1,8 +1,14 @@ #!/bin/bash CUSTOM_KEY_MATERIAL="f5KQzETF/SuV/iHWrW/l+pwXfhzW87TJapexPgnqoVg=" -CUSTOM_ID="bffb20d8-35ca-4408-9d54-f775b929b38d" +CUSTOM_ORIGIN_ID="bffb20d8-35ca-4408-9d54-f775b929b38d" +CUSTOM_DELEGATOR_ID="3e47cac8-de37-4f50-b591-57f525c1b05c" # The command succeeds but the key is not created with the custom key material (should be fixed once this is clarified: https://github.com/localstack/localstack/issues/11678) # awslocal kms create-key --key-usage SIGN_VERIFY --key-spec ECC_SECG_P256K1 --tags "[{\"TagKey\":\"_custom_key_material_\",\"TagValue\":\"$CUSTOM_KEY_MATERIAL\"},{\"TagKey\":\"_custom_id_\",\"TagValue\":\"$CUSTOM_ID\"}]" -awslocal kms create-key --key-usage SIGN_VERIFY --key-spec ECC_SECG_P256K1 --tags "[{\"TagKey\":\"_custom_id_\",\"TagValue\":\"$CUSTOM_ID\"}]" \ No newline at end of file + +# Origin key +awslocal kms create-key --key-usage SIGN_VERIFY --key-spec ECC_SECG_P256K1 --tags "[{\"TagKey\":\"_custom_id_\",\"TagValue\":\"$CUSTOM_ORIGIN_ID\"}]" + +# Delegator key +awslocal kms create-key --key-usage SIGN_VERIFY --key-spec ECC_SECG_P256K1 --tags "[{\"TagKey\":\"_custom_id_\",\"TagValue\":\"$CUSTOM_DELEGATOR_ID\"}]" \ No newline at end of file diff --git a/packages/aws-kms-adapter/README.md b/packages/aws-kms-adapter/README.md index 606d2e642..97140ba5d 100644 --- a/packages/aws-kms-adapter/README.md +++ b/packages/aws-kms-adapter/README.md @@ -29,26 +29,28 @@ yarn test:solo To integrate this into your code, depending on how you plan to manage your AWS credentials, you can choose one of the following examples. -Within this repo, you can create a credentials file called `aws-credentials.json` with your custom credentials under the `tests` folder in case you want to give it a try before integrating with your project. A valid format would be as follows: +Within this repo, you can create a credentials file called `aws-credentials.json` with your custom credentials under the `tests` folder in case you want to give it a try before integrating with your project. A valid format would be as follows (it is an array in case you want to include a delegator key): ```json -{ - // AWS KMS keyId (mandatory) - "keyId": "00000000-0000-0000-0000-000000000000", - // AWS region (mandatory) - "region": "eu-west-1", - // AWS credentials (optional) - "credentials": { - // AWS access key id (mandatory if credentials) - "accessKeyId": "test", - // AWS secret access key (mandatory if credentials) - "secretAccessKey": "test", - // AWS session token if SSO is configured (optional) - "sessionToken": "test" - }, - // AWS endpoint (optional, to be used locally along with LocalStack) - "endpoint": "http://localhost:4599" -} +[ + { + // AWS KMS keyId (mandatory) + "keyId": "00000000-0000-0000-0000-000000000000", + // AWS region (mandatory) + "region": "eu-west-1", + // AWS credentials (optional) + "credentials": { + // AWS access key id (mandatory if credentials) + "accessKeyId": "test", + // AWS secret access key (mandatory if credentials) + "secretAccessKey": "test", + // AWS session token if SSO is configured (optional) + "sessionToken": "test" + }, + // AWS endpoint (optional, to be used locally along with LocalStack) + "endpoint": "http://localhost:4599" + } +] ``` ### IAM roles diff --git a/packages/aws-kms-adapter/tests/KMSVeChainSigner.solo.test.ts b/packages/aws-kms-adapter/tests/KMSVeChainSigner.solo.test.ts index e75127a3b..c2394a6d7 100644 --- a/packages/aws-kms-adapter/tests/KMSVeChainSigner.solo.test.ts +++ b/packages/aws-kms-adapter/tests/KMSVeChainSigner.solo.test.ts @@ -109,9 +109,9 @@ describe('KMSVeChainSigner - Thor Solo', () => { ); let awsClientParameters: AwsClientParameters; try { - awsClientParameters = JSON.parse( + [awsClientParameters] = JSON.parse( fs.readFileSync(awsCredentialsPath, 'utf8') - ) as AwsClientParameters; + ) as AwsClientParameters[]; // eslint-disable-next-line @typescript-eslint/no-unused-vars } catch (error) { console.log('Loading test credentials'); @@ -119,9 +119,9 @@ describe('KMSVeChainSigner - Thor Solo', () => { __dirname, './test-aws-credentials.json' ); - awsClientParameters = JSON.parse( + [awsClientParameters] = JSON.parse( fs.readFileSync(testAwsCredentialsPath, 'utf8') - ) as AwsClientParameters; + ) as AwsClientParameters[]; } thorClient = ThorClient.fromUrl(THOR_SOLO_URL); const provider = new KMSVeChainProvider( diff --git a/packages/aws-kms-adapter/tests/test-aws-credentials.json b/packages/aws-kms-adapter/tests/test-aws-credentials.json index 5a01f1ca2..be703653b 100644 --- a/packages/aws-kms-adapter/tests/test-aws-credentials.json +++ b/packages/aws-kms-adapter/tests/test-aws-credentials.json @@ -1,9 +1,21 @@ -{ - "keyId": "bffb20d8-35ca-4408-9d54-f775b929b38d", - "region": "eu-west-1", - "credentials": { - "accessKeyId": "test", - "secretAccessKey": "test" +[ + { + "keyId": "bffb20d8-35ca-4408-9d54-f775b929b38d", + "region": "eu-west-1", + "credentials": { + "accessKeyId": "test", + "secretAccessKey": "test" + }, + "endpoint": "http://localhost:4599" }, - "endpoint": "http://localhost:4599" -} + { + "keyId": "3e47cac8-de37-4f50-b591-57f525c1b05c", + "region": "eu-west-1", + "credentials": { + "accessKeyId": "test", + "secretAccessKey": "test" + }, + "endpoint": "http://localhost:4599" + } +] + From 929df4e4c52a323a5b71a7ffb37898ea5d5a9ad2 Mon Sep 17 00:00:00 2001 From: Miguel Angel Rojo Fernandez Date: Tue, 22 Oct 2024 12:40:01 +0100 Subject: [PATCH 15/35] feat: scaffolding for testing --- packages/aws-kms-adapter/src/KMSVeChainSigner.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/aws-kms-adapter/src/KMSVeChainSigner.ts b/packages/aws-kms-adapter/src/KMSVeChainSigner.ts index cc19417ed..cf3bcd95e 100644 --- a/packages/aws-kms-adapter/src/KMSVeChainSigner.ts +++ b/packages/aws-kms-adapter/src/KMSVeChainSigner.ts @@ -116,6 +116,7 @@ class KMSVeChainSigner extends VeChainAbstractSigner { /** * Gets the DER-encoded public key from KMS and decodes it. + * @param {KMSVeChainProvider} kmsProvider (Optional) The provider to get the public key from. * @returns {Uint8Array} The decoded public key. */ private async getDecodedPublicKey( From fd293727a07423928426456e3849f38079a73a28 Mon Sep 17 00:00:00 2001 From: Miguel Angel Rojo Fernandez Date: Tue, 22 Oct 2024 14:19:00 +0100 Subject: [PATCH 16/35] feat: scaffolding for testing --- .../tests/KMSVeChainSigner.solo.test.ts | 33 ++++++++++++++++--- 1 file changed, 28 insertions(+), 5 deletions(-) diff --git a/packages/aws-kms-adapter/tests/KMSVeChainSigner.solo.test.ts b/packages/aws-kms-adapter/tests/KMSVeChainSigner.solo.test.ts index c2394a6d7..f95d90672 100644 --- a/packages/aws-kms-adapter/tests/KMSVeChainSigner.solo.test.ts +++ b/packages/aws-kms-adapter/tests/KMSVeChainSigner.solo.test.ts @@ -45,7 +45,7 @@ let expectedAddress: string; const fundVTHO = async ( thorClient: ThorClient, - kmsSigner: KMSVeChainSigner + receiverAddress: string ): Promise => { const signer = new VeChainPrivateKeySigner( HexUInt.of(THOR_SOLO_ACCOUNTS[0].privateKey).bytes, @@ -58,7 +58,6 @@ const fundVTHO = async ( // Load the ERC20 contract const contract = thorClient.contracts.load(VTHO_ADDRESS, ERC20_ABI, signer); - const receiverAddress = await kmsSigner.getAddress(); expectedAddress = receiverAddress; const expectedVTHO = 200000000000000000000n; @@ -99,6 +98,11 @@ describe('KMSVeChainSigner - Thor Solo', () => { */ let signer: KMSVeChainSigner; + /** + * KMSVeChainSigner with delegator instance + */ + let signerWithDelegator: KMSVeChainSigner; + /** * Init thor client and provider before each test */ @@ -108,8 +112,9 @@ describe('KMSVeChainSigner - Thor Solo', () => { './aws-credentials.json' ); let awsClientParameters: AwsClientParameters; + let delegatorAwsClientParameters: AwsClientParameters; try { - [awsClientParameters] = JSON.parse( + [awsClientParameters, delegatorAwsClientParameters] = JSON.parse( fs.readFileSync(awsCredentialsPath, 'utf8') ) as AwsClientParameters[]; // eslint-disable-next-line @typescript-eslint/no-unused-vars @@ -119,7 +124,7 @@ describe('KMSVeChainSigner - Thor Solo', () => { __dirname, './test-aws-credentials.json' ); - [awsClientParameters] = JSON.parse( + [awsClientParameters, delegatorAwsClientParameters] = JSON.parse( fs.readFileSync(testAwsCredentialsPath, 'utf8') ) as AwsClientParameters[]; } @@ -132,9 +137,27 @@ describe('KMSVeChainSigner - Thor Solo', () => { awsClientParameters.endpoint ); expect(provider).toBeInstanceOf(KMSVeChainProvider); + + if (delegatorAwsClientParameters !== undefined) { + const delegatorProvider = new KMSVeChainProvider( + thorClient, + delegatorAwsClientParameters.keyId, + delegatorAwsClientParameters.region, + delegatorAwsClientParameters.credentials, + delegatorAwsClientParameters.endpoint + ); + expect(delegatorProvider).toBeInstanceOf(KMSVeChainProvider); + signerWithDelegator = new KMSVeChainSigner(provider, { + provider: delegatorProvider + }); + await fundVTHO( + thorClient, + await signerWithDelegator.getAddress(delegatorProvider) + ); + } signer = new KMSVeChainSigner(provider); // This step should be removed once this is clarified https://github.com/localstack/localstack/issues/11678 - await fundVTHO(thorClient, signer); + await fundVTHO(thorClient, await signer.getAddress()); }); describe('getAddress', () => { From efa694661980780a0f15bab9d1a9669d79ba1e4f Mon Sep 17 00:00:00 2001 From: Miguel Angel Rojo Fernandez Date: Tue, 22 Oct 2024 14:26:36 +0100 Subject: [PATCH 17/35] feat: scaffolding for testing --- .../aws-kms-adapter/src/KMSVeChainSigner.ts | 7 +- .../tests/KMSVeChainSigner.solo.test.ts | 175 ++++++++++-------- 2 files changed, 101 insertions(+), 81 deletions(-) diff --git a/packages/aws-kms-adapter/src/KMSVeChainSigner.ts b/packages/aws-kms-adapter/src/KMSVeChainSigner.ts index cf3bcd95e..d7da7875d 100644 --- a/packages/aws-kms-adapter/src/KMSVeChainSigner.ts +++ b/packages/aws-kms-adapter/src/KMSVeChainSigner.ts @@ -135,13 +135,16 @@ class KMSVeChainSigner extends VeChainAbstractSigner { /** * It returns the address associated with the signer. - * @param {KMSVeChainProvider} kmsProvider (Optional) The provider to get the address from. + * @param {boolean} fromDelegator (Optional) If true, the provider will be the delegator. * @returns The address associated with the signer. */ public async getAddress( - kmsProvider: KMSVeChainProvider | undefined = this.kmsVeChainProvider + fromDelegator: boolean | undefined = false ): Promise { try { + const kmsProvider = fromDelegator + ? this.kmsVeChainDelegatorProvider + : this.kmsVeChainProvider; const publicKeyDecoded = await this.getDecodedPublicKey(kmsProvider); return Address.ofPublicKey(publicKeyDecoded).toString(); diff --git a/packages/aws-kms-adapter/tests/KMSVeChainSigner.solo.test.ts b/packages/aws-kms-adapter/tests/KMSVeChainSigner.solo.test.ts index f95d90672..44233b0e1 100644 --- a/packages/aws-kms-adapter/tests/KMSVeChainSigner.solo.test.ts +++ b/packages/aws-kms-adapter/tests/KMSVeChainSigner.solo.test.ts @@ -29,6 +29,8 @@ import { TESTING_CONTRACT_ADDRESS } from './fixture'; +const timeout = 8000; // 8 seconds + interface AwsClientParameters { keyId: string; region: string; @@ -150,15 +152,16 @@ describe('KMSVeChainSigner - Thor Solo', () => { signerWithDelegator = new KMSVeChainSigner(provider, { provider: delegatorProvider }); + // This step should be removed once this is clarified https://github.com/localstack/localstack/issues/11678 await fundVTHO( thorClient, - await signerWithDelegator.getAddress(delegatorProvider) + await signerWithDelegator.getAddress(true) ); } signer = new KMSVeChainSigner(provider); // This step should be removed once this is clarified https://github.com/localstack/localstack/issues/11678 await fundVTHO(thorClient, await signer.getAddress()); - }); + }, timeout); describe('getAddress', () => { test('should get the address from the public key', async () => { @@ -171,99 +174,113 @@ describe('KMSVeChainSigner - Thor Solo', () => { * Test suite for signTransaction method */ describe('signTransaction', () => { - test('should sign a transaction successfully', async () => { - const sampleClause = Clause.callFunction( - Address.of(TESTING_CONTRACT_ADDRESS), - ABIContract.ofAbi(TESTING_CONTRACT_ABI).getFunction('deposit'), - [123] - ) as TransactionClause; + test( + 'should sign a transaction successfully', + async () => { + const sampleClause = Clause.callFunction( + Address.of(TESTING_CONTRACT_ADDRESS), + ABIContract.ofAbi(TESTING_CONTRACT_ABI).getFunction( + 'deposit' + ), + [123] + ) as TransactionClause; - const originAddress = await signer.getAddress(); + const originAddress = await signer.getAddress(); - const gasResult = await thorClient.gas.estimateGas( - [sampleClause], - originAddress - ); + const gasResult = await thorClient.gas.estimateGas( + [sampleClause], + originAddress + ); - const txBody = await thorClient.transactions.buildTransactionBody( - [sampleClause], - gasResult.totalGas, - { - isDelegated: false - } - ); + const txBody = + await thorClient.transactions.buildTransactionBody( + [sampleClause], + gasResult.totalGas, + { + isDelegated: false + } + ); - const signedRawTx = await signer.signTransaction( - signerUtils.transactionBodyToTransactionRequestInput( - txBody, - originAddress - ) - ); - const signedTx = Transaction.decode( - HexUInt.of(signedRawTx.slice(2)).bytes, - true - ); + const signedRawTx = await signer.signTransaction( + signerUtils.transactionBodyToTransactionRequestInput( + txBody, + originAddress + ) + ); + const signedTx = Transaction.decode( + HexUInt.of(signedRawTx.slice(2)).bytes, + true + ); - expect(signedTx).toBeDefined(); - const expectedBody = { - chainTag: 246, - clauses: [ - { - data: '0xb6b55f25000000000000000000000000000000000000000000000000000000000000007b', - to: '0xb2c20a6de401003a671659b10629eb82ff254fb8', - value: 0 - } - ], - dependsOn: null, - expiration: 32, - gas: 57491, - gasPriceCoef: 0 - }; - expect(signedTx.body).toMatchObject(expectedBody); - expect(signedTx.origin.toString()).toBe( - Address.checksum(HexUInt.of(originAddress)) - ); - expect(signedTx.isDelegated).toBe(false); - expect(signedTx.isSigned).toBe(true); - expect(signedTx.signature).toBeDefined(); - }, 8000); + expect(signedTx).toBeDefined(); + const expectedBody = { + chainTag: 246, + clauses: [ + { + data: '0xb6b55f25000000000000000000000000000000000000000000000000000000000000007b', + to: '0xb2c20a6de401003a671659b10629eb82ff254fb8', + value: 0 + } + ], + dependsOn: null, + expiration: 32, + gas: 57491, + gasPriceCoef: 0 + }; + expect(signedTx.body).toMatchObject(expectedBody); + expect(signedTx.origin.toString()).toBe( + Address.checksum(HexUInt.of(originAddress)) + ); + expect(signedTx.isDelegated).toBe(false); + expect(signedTx.isSigned).toBe(true); + expect(signedTx.signature).toBeDefined(); + }, + timeout + ); }); /** * Test suite for sendTransaction method */ describe('sendTransaction', () => { - test('should send a transaction successfully', async () => { - const sampleClause = Clause.callFunction( - Address.of(TESTING_CONTRACT_ADDRESS), - ABIContract.ofAbi(TESTING_CONTRACT_ABI).getFunction('deposit'), - [123] - ) as TransactionClause; + test( + 'should send a transaction successfully', + async () => { + const sampleClause = Clause.callFunction( + Address.of(TESTING_CONTRACT_ADDRESS), + ABIContract.ofAbi(TESTING_CONTRACT_ABI).getFunction( + 'deposit' + ), + [123] + ) as TransactionClause; - const originAddress = await signer.getAddress(); + const originAddress = await signer.getAddress(); - const gasResult = await thorClient.gas.estimateGas( - [sampleClause], - originAddress - ); + const gasResult = await thorClient.gas.estimateGas( + [sampleClause], + originAddress + ); - const txBody = await thorClient.transactions.buildTransactionBody( - [sampleClause], - gasResult.totalGas, - { - isDelegated: false - } - ); + const txBody = + await thorClient.transactions.buildTransactionBody( + [sampleClause], + gasResult.totalGas, + { + isDelegated: false + } + ); - const receipt = await signer.sendTransaction( - signerUtils.transactionBodyToTransactionRequestInput( - txBody, - originAddress - ) - ); + const receipt = await signer.sendTransaction( + signerUtils.transactionBodyToTransactionRequestInput( + txBody, + originAddress + ) + ); - expect(receipt.match(/^0x([A-Fa-f0-9]{64})$/)).toBeTruthy(); - }, 8000); + expect(receipt.match(/^0x([A-Fa-f0-9]{64})$/)).toBeTruthy(); + }, + timeout + ); }); /** From 2393dd638a3e13fe98f541593b2f9c476f586ec3 Mon Sep 17 00:00:00 2001 From: Miguel Angel Rojo Fernandez Date: Tue, 22 Oct 2024 14:31:27 +0100 Subject: [PATCH 18/35] feat: added gitleaks exceptions --- .gitleaksignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitleaksignore b/.gitleaksignore index 0363fe9f5..5eb5f2812 100644 --- a/.gitleaksignore +++ b/.gitleaksignore @@ -1 +1,2 @@ -# Exceptions for gitleaks to be placed here \ No newline at end of file +465a9c6b265ec49015fd7ff641506905cb93811c:packages/aws-kms-adapter/tests/test-aws-credentials.json:generic-api-key:3 +465a9c6b265ec49015fd7ff641506905cb93811c:packages/aws-kms-adapter/tests/test-aws-credentials.json:generic-api-key:12 From 129554fd746bc51a40d8b1e38e2dfb2e58bc4a71 Mon Sep 17 00:00:00 2001 From: Miguel Angel Rojo Fernandez Date: Tue, 22 Oct 2024 14:38:10 +0100 Subject: [PATCH 19/35] feat: some more changes --- .../aws-kms-adapter/src/KMSVeChainSigner.ts | 21 +++++++++---------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/packages/aws-kms-adapter/src/KMSVeChainSigner.ts b/packages/aws-kms-adapter/src/KMSVeChainSigner.ts index d7da7875d..0caf8ee18 100644 --- a/packages/aws-kms-adapter/src/KMSVeChainSigner.ts +++ b/packages/aws-kms-adapter/src/KMSVeChainSigner.ts @@ -36,31 +36,30 @@ class KMSVeChainSigner extends VeChainAbstractSigner { // Origin provider super(provider); if (this.provider !== undefined) { - if (this.provider instanceof KMSVeChainProvider) { - this.kmsVeChainProvider = this.provider; - } else { + if (!(this.provider instanceof KMSVeChainProvider)) { throw new JSONRPCInvalidParams( 'KMSVeChainSigner.constructor', 'The provider object is not well formed, it should be an instance of KMSVeChainProvider.', - { provider: this.provider } + { provider } ); } + this.kmsVeChainProvider = this.provider; } // Delegator provider, if any - if (this.delegator !== undefined) { + if (delegator !== undefined) { if ( - this.delegator.provider !== undefined && - this.delegator.provider instanceof KMSVeChainProvider + delegator.provider !== undefined && + delegator.provider instanceof KMSVeChainProvider ) { - this.kmsVeChainDelegatorProvider = this.delegator.provider; - } else if (this.delegator.url !== undefined) { - this.kmsVeChainDelegatorUrl = this.delegator.url; + this.kmsVeChainDelegatorProvider = delegator.provider; + } else if (delegator.url !== undefined) { + this.kmsVeChainDelegatorUrl = delegator.url; } else { throw new JSONRPCInvalidParams( 'KMSVeChainSigner.constructor', 'The delegator object is not well formed, either provider or url should be provided.', - { delegator: this.delegator } + { delegator } ); } } From e0339661a6fa685a14ff0e95ebb93ce39bf38e83 Mon Sep 17 00:00:00 2001 From: Miguel Angel Rojo Fernandez Date: Tue, 22 Oct 2024 14:46:42 +0100 Subject: [PATCH 20/35] feat: some more changes --- localstack/init/kms.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/localstack/init/kms.sh b/localstack/init/kms.sh index 5db2db6bd..635974feb 100755 --- a/localstack/init/kms.sh +++ b/localstack/init/kms.sh @@ -1,11 +1,11 @@ #!/bin/bash -CUSTOM_KEY_MATERIAL="f5KQzETF/SuV/iHWrW/l+pwXfhzW87TJapexPgnqoVg=" +CUSTOM_ORIGIN_KEY_MATERIAL="f5KQzETF/SuV/iHWrW/l+pwXfhzW87TJapexPgnqoVg=" CUSTOM_ORIGIN_ID="bffb20d8-35ca-4408-9d54-f775b929b38d" CUSTOM_DELEGATOR_ID="3e47cac8-de37-4f50-b591-57f525c1b05c" # The command succeeds but the key is not created with the custom key material (should be fixed once this is clarified: https://github.com/localstack/localstack/issues/11678) -# awslocal kms create-key --key-usage SIGN_VERIFY --key-spec ECC_SECG_P256K1 --tags "[{\"TagKey\":\"_custom_key_material_\",\"TagValue\":\"$CUSTOM_KEY_MATERIAL\"},{\"TagKey\":\"_custom_id_\",\"TagValue\":\"$CUSTOM_ID\"}]" +# awslocal kms create-key --key-usage SIGN_VERIFY --key-spec ECC_SECG_P256K1 --tags "[{\"TagKey\":\"_custom_key_material_\",\"TagValue\":\"$CUSTOM_ORIGIN_KEY_MATERIAL\"},{\"TagKey\":\"_custom_id_\",\"TagValue\":\"$CUSTOM_ORIGIN_ID\"}]" # Origin key awslocal kms create-key --key-usage SIGN_VERIFY --key-spec ECC_SECG_P256K1 --tags "[{\"TagKey\":\"_custom_id_\",\"TagValue\":\"$CUSTOM_ORIGIN_ID\"}]" From c727a5478d94db38cd0403455909e4c5a80f8f94 Mon Sep 17 00:00:00 2001 From: Miguel Angel Rojo Fernandez Date: Tue, 22 Oct 2024 15:59:58 +0100 Subject: [PATCH 21/35] feat: solo tests not working --- .../tests/KMSVeChainSigner.solo.test.ts | 116 +++++++++--------- packages/aws-kms-adapter/tests/fixture.ts | 61 ++++++++- 2 files changed, 117 insertions(+), 60 deletions(-) diff --git a/packages/aws-kms-adapter/tests/KMSVeChainSigner.solo.test.ts b/packages/aws-kms-adapter/tests/KMSVeChainSigner.solo.test.ts index 44233b0e1..7be99fd6b 100644 --- a/packages/aws-kms-adapter/tests/KMSVeChainSigner.solo.test.ts +++ b/packages/aws-kms-adapter/tests/KMSVeChainSigner.solo.test.ts @@ -25,6 +25,7 @@ import { EIP712_CONTRACT, EIP712_FROM, EIP712_TO, + signTransactionTestCases, TESTING_CONTRACT_ABI, TESTING_CONTRACT_ADDRESS } from './fixture'; @@ -60,8 +61,6 @@ const fundVTHO = async ( // Load the ERC20 contract const contract = thorClient.contracts.load(VTHO_ADDRESS, ERC20_ABI, signer); - expectedAddress = receiverAddress; - const expectedVTHO = 200000000000000000000n; // Execute a 'transfer' transaction on the deployed contract, @@ -159,8 +158,9 @@ describe('KMSVeChainSigner - Thor Solo', () => { ); } signer = new KMSVeChainSigner(provider); + expectedAddress = await signer.getAddress(); // This step should be removed once this is clarified https://github.com/localstack/localstack/issues/11678 - await fundVTHO(thorClient, await signer.getAddress()); + await fundVTHO(thorClient, expectedAddress); }, timeout); describe('getAddress', () => { @@ -174,68 +174,66 @@ describe('KMSVeChainSigner - Thor Solo', () => { * Test suite for signTransaction method */ describe('signTransaction', () => { - test( - 'should sign a transaction successfully', - async () => { - const sampleClause = Clause.callFunction( - Address.of(TESTING_CONTRACT_ADDRESS), - ABIContract.ofAbi(TESTING_CONTRACT_ABI).getFunction( - 'deposit' - ), - [123] - ) as TransactionClause; + /** + * signTransaction test cases with different options + */ + signTransactionTestCases.solo.correct.forEach( + ({ description, isDelegated, expected }) => { + test( + description, + async () => { + const signTransactionSigner = isDelegated + ? signerWithDelegator + : signer; + const sampleClause = Clause.callFunction( + Address.of(TESTING_CONTRACT_ADDRESS), + ABIContract.ofAbi(TESTING_CONTRACT_ABI).getFunction( + 'deposit' + ), + [123] + ) as TransactionClause; - const originAddress = await signer.getAddress(); + const originAddress = + await signTransactionSigner.getAddress(); - const gasResult = await thorClient.gas.estimateGas( - [sampleClause], - originAddress - ); + const gasResult = await thorClient.gas.estimateGas( + [sampleClause], + originAddress + ); - const txBody = - await thorClient.transactions.buildTransactionBody( - [sampleClause], - gasResult.totalGas, - { - isDelegated: false - } - ); + const txBody = + await thorClient.transactions.buildTransactionBody( + [sampleClause], + gasResult.totalGas, + { + isDelegated + } + ); - const signedRawTx = await signer.signTransaction( - signerUtils.transactionBodyToTransactionRequestInput( - txBody, - originAddress - ) - ); - const signedTx = Transaction.decode( - HexUInt.of(signedRawTx.slice(2)).bytes, - true - ); + const signedRawTx = + await signTransactionSigner.signTransaction( + signerUtils.transactionBodyToTransactionRequestInput( + txBody, + originAddress + ) + ); + const signedTx = Transaction.decode( + HexUInt.of(signedRawTx.slice(2)).bytes, + true + ); - expect(signedTx).toBeDefined(); - const expectedBody = { - chainTag: 246, - clauses: [ - { - data: '0xb6b55f25000000000000000000000000000000000000000000000000000000000000007b', - to: '0xb2c20a6de401003a671659b10629eb82ff254fb8', - value: 0 - } - ], - dependsOn: null, - expiration: 32, - gas: 57491, - gasPriceCoef: 0 - }; - expect(signedTx.body).toMatchObject(expectedBody); - expect(signedTx.origin.toString()).toBe( - Address.checksum(HexUInt.of(originAddress)) + expect(signedTx).toBeDefined(); + expect(signedTx.body).toMatchObject(expected.body); + expect(signedTx.origin.toString()).toBe( + Address.checksum(HexUInt.of(originAddress)) + ); + expect(signedTx.isDelegated).toBe(isDelegated); + expect(signedTx.isSigned).toBe(true); + expect(signedTx.signature).toBeDefined(); + }, + timeout ); - expect(signedTx.isDelegated).toBe(false); - expect(signedTx.isSigned).toBe(true); - expect(signedTx.signature).toBeDefined(); - }, - timeout + } ); }); diff --git a/packages/aws-kms-adapter/tests/fixture.ts b/packages/aws-kms-adapter/tests/fixture.ts index b24f085ed..d00df9e56 100644 --- a/packages/aws-kms-adapter/tests/fixture.ts +++ b/packages/aws-kms-adapter/tests/fixture.ts @@ -785,10 +785,69 @@ const EIP712_FROM = '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826'; // This is private for EIP-712 unit test case only. Dummy address. const EIP712_TO = '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB'; +/** + * SignTransaction test cases + * Has both correct and incorrect for solo and an example of using delegatorUrl on testnet + */ +const signTransactionTestCases = { + solo: { + /** + * Correct test cases + */ + correct: [ + { + description: 'Should sign a transaction without delegation', + isDelegated: false, + expected: { + body: { + chainTag: 246, + clauses: [ + { + data: '0xb6b55f25000000000000000000000000000000000000000000000000000000000000007b', + to: '0xb2c20a6de401003a671659b10629eb82ff254fb8', + value: 0 + } + ], + dependsOn: null, + expiration: 32, + gas: 57491, + gasPriceCoef: 0 + } + } + }, + { + description: + 'Should sign a transaction with private key delegation', + isDelegated: true, + expected: { + body: { + chainTag: 246, + clauses: [ + { + data: '0xb6b55f25000000000000000000000000000000000000000000000000000000000000007b', + to: '0xb2c20a6de401003a671659b10629eb82ff254fb8', + value: 0 + } + ], + dependsOn: null, + expiration: 32, + gas: 57491, + gasPriceCoef: 0, + reserved: { + features: 1 + } + } + } + } + ] + } +}; + export { EIP712_CONTRACT, EIP712_FROM, EIP712_TO, TESTING_CONTRACT_ABI, - TESTING_CONTRACT_ADDRESS + TESTING_CONTRACT_ADDRESS, + signTransactionTestCases }; From 0334d16f3e9c22b1ef8253c9a4378697d5f6ba2c Mon Sep 17 00:00:00 2001 From: Miguel Angel Rojo Fernandez Date: Tue, 22 Oct 2024 17:01:46 +0100 Subject: [PATCH 22/35] feat: first tests working --- .../aws-kms-adapter/src/KMSVeChainProvider.ts | 3 +- .../tests/KMSVeChainProvider.unit.test.ts | 1 + .../tests/KMSVeChainSigner.solo.test.ts | 63 +++++++++++-------- .../vechain-provider/vechain-provider.ts | 14 +---- 4 files changed, 41 insertions(+), 40 deletions(-) diff --git a/packages/aws-kms-adapter/src/KMSVeChainProvider.ts b/packages/aws-kms-adapter/src/KMSVeChainProvider.ts index 65ea833e6..8b33d4401 100644 --- a/packages/aws-kms-adapter/src/KMSVeChainProvider.ts +++ b/packages/aws-kms-adapter/src/KMSVeChainProvider.ts @@ -28,6 +28,7 @@ class KMSVeChainProvider extends VeChainProvider { thorClient: ThorClient, readonly keyId: string, region: string, + enableDelegation: boolean = false, credentials?: { accessKeyId: string; secretAccessKey: string; @@ -35,7 +36,7 @@ class KMSVeChainProvider extends VeChainProvider { }, endpoint?: string ) { - super(thorClient); + super(thorClient, undefined, enableDelegation); this.kmsClient = endpoint !== undefined ? new KMSClient({ diff --git a/packages/aws-kms-adapter/tests/KMSVeChainProvider.unit.test.ts b/packages/aws-kms-adapter/tests/KMSVeChainProvider.unit.test.ts index e10ab0be3..3be221c16 100644 --- a/packages/aws-kms-adapter/tests/KMSVeChainProvider.unit.test.ts +++ b/packages/aws-kms-adapter/tests/KMSVeChainProvider.unit.test.ts @@ -48,6 +48,7 @@ describe('KMSVeChainProvider', () => { {} as unknown as ThorClient, 'keyId', 'region', + false, { accessKeyId: 'accessKeyId', secretAccessKey: 'secretAccess' diff --git a/packages/aws-kms-adapter/tests/KMSVeChainSigner.solo.test.ts b/packages/aws-kms-adapter/tests/KMSVeChainSigner.solo.test.ts index 7be99fd6b..335d51ffc 100644 --- a/packages/aws-kms-adapter/tests/KMSVeChainSigner.solo.test.ts +++ b/packages/aws-kms-adapter/tests/KMSVeChainSigner.solo.test.ts @@ -35,6 +35,7 @@ const timeout = 8000; // 8 seconds interface AwsClientParameters { keyId: string; region: string; + enableDelegation?: boolean; credentials: { accessKeyId: string; secretAccessKey: string; @@ -130,37 +131,47 @@ describe('KMSVeChainSigner - Thor Solo', () => { ) as AwsClientParameters[]; } thorClient = ThorClient.fromUrl(THOR_SOLO_URL); - const provider = new KMSVeChainProvider( - thorClient, - awsClientParameters.keyId, - awsClientParameters.region, - awsClientParameters.credentials, - awsClientParameters.endpoint - ); - expect(provider).toBeInstanceOf(KMSVeChainProvider); - if (delegatorAwsClientParameters !== undefined) { - const delegatorProvider = new KMSVeChainProvider( - thorClient, - delegatorAwsClientParameters.keyId, - delegatorAwsClientParameters.region, - delegatorAwsClientParameters.credentials, - delegatorAwsClientParameters.endpoint - ); - expect(delegatorProvider).toBeInstanceOf(KMSVeChainProvider); - signerWithDelegator = new KMSVeChainSigner(provider, { - provider: delegatorProvider - }); - // This step should be removed once this is clarified https://github.com/localstack/localstack/issues/11678 - await fundVTHO( + // Signer with delegator disabled + signer = new KMSVeChainSigner( + new KMSVeChainProvider( thorClient, - await signerWithDelegator.getAddress(true) - ); - } - signer = new KMSVeChainSigner(provider); + awsClientParameters.keyId, + awsClientParameters.region, + undefined, + awsClientParameters.credentials, + awsClientParameters.endpoint + ) + ); expectedAddress = await signer.getAddress(); // This step should be removed once this is clarified https://github.com/localstack/localstack/issues/11678 await fundVTHO(thorClient, expectedAddress); + + // Signer with delegator enabled + const delegatorProvider = new KMSVeChainProvider( + thorClient, + delegatorAwsClientParameters.keyId, + delegatorAwsClientParameters.region, + undefined, + delegatorAwsClientParameters.credentials, + delegatorAwsClientParameters.endpoint + ); + expect(delegatorProvider).toBeInstanceOf(KMSVeChainProvider); + signerWithDelegator = new KMSVeChainSigner( + new KMSVeChainProvider( + thorClient, + awsClientParameters.keyId, + awsClientParameters.region, + true, + awsClientParameters.credentials, + awsClientParameters.endpoint + ), + { + provider: delegatorProvider + } + ); + // This step should be removed once this is clarified https://github.com/localstack/localstack/issues/11678 + await fundVTHO(thorClient, await signerWithDelegator.getAddress(true)); }, timeout); describe('getAddress', () => { diff --git a/packages/network/src/provider/providers/vechain-provider/vechain-provider.ts b/packages/network/src/provider/providers/vechain-provider/vechain-provider.ts index aadc14c66..c5bc3263e 100644 --- a/packages/network/src/provider/providers/vechain-provider/vechain-provider.ts +++ b/packages/network/src/provider/providers/vechain-provider/vechain-provider.ts @@ -1,8 +1,5 @@ import { HexInt } from '@vechain/sdk-core'; -import { - JSONRPCInvalidParams, - JSONRPCMethodNotFound -} from '@vechain/sdk-errors'; +import { JSONRPCMethodNotFound } from '@vechain/sdk-errors'; import { EventEmitter } from 'events'; import { type VeChainSigner } from '../../../signer'; import { @@ -58,15 +55,6 @@ class VeChainProvider extends EventEmitter implements EIP1193ProviderMessage { readonly enableDelegation: boolean = false ) { super(); - - // Throw an error if delegation is enabled but the delegator is not defined - if (enableDelegation && wallet?.delegator === undefined) { - throw new JSONRPCInvalidParams( - 'VechainProvider constructor', - 'Delegation is enabled but the delegator is not defined. Ensure that the delegator is defined and connected to the network.', - { wallet } - ); - } } /** From 4a2d74a0bac92b2dd04efd7a44ebe3b1f7aed8ab Mon Sep 17 00:00:00 2001 From: Miguel Angel Rojo Fernandez Date: Tue, 22 Oct 2024 17:31:14 +0100 Subject: [PATCH 23/35] feat: more changes --- .../aws-kms-adapter/src/KMSVeChainProvider.ts | 52 ++++---- packages/aws-kms-adapter/src/index.ts | 5 +- .../tests/KMSVeChainProvider.unit.test.ts | 21 ++-- .../tests/KMSVeChainSigner.solo.test.ts | 111 ++++-------------- .../tests/KMSVeChainSigner.unit.test.ts | 15 +-- packages/aws-kms-adapter/tests/fixture.ts | 80 ++++++++++++- 6 files changed, 147 insertions(+), 137 deletions(-) diff --git a/packages/aws-kms-adapter/src/KMSVeChainProvider.ts b/packages/aws-kms-adapter/src/KMSVeChainProvider.ts index 8b33d4401..b5f338707 100644 --- a/packages/aws-kms-adapter/src/KMSVeChainProvider.ts +++ b/packages/aws-kms-adapter/src/KMSVeChainProvider.ts @@ -13,40 +13,44 @@ import { } from '@vechain/sdk-network'; import { KMSVeChainSigner } from './KMSVeChainSigner'; +interface KMSClientParameters { + keyId: string; + region: string; + enableDelegation?: boolean; + credentials?: { + accessKeyId: string; + secretAccessKey: string; + sessionToken?: string; + }; + endpoint?: string; +} + class KMSVeChainProvider extends VeChainProvider { private readonly kmsClient: KMSClient; + private readonly keyId: string; private signer?: KMSVeChainSigner; /** * Creates a new instance of KMSVeChainProvider. * @param thorClient The thor client instance to use. - * @param keyId The AWS keyId to use for signing operations locally. - * @param region The AWS region to use. - * @param credentials The AWS credentials to connect to the KMS service. + * @param params The parameters to configure the KMS client and the keyId. **/ - public constructor( - thorClient: ThorClient, - readonly keyId: string, - region: string, - enableDelegation: boolean = false, - credentials?: { - accessKeyId: string; - secretAccessKey: string; - sessionToken?: string; - }, - endpoint?: string - ) { - super(thorClient, undefined, enableDelegation); + public constructor(thorClient: ThorClient, params: KMSClientParameters) { + super(thorClient, undefined, params.enableDelegation); + this.keyId = params.keyId; this.kmsClient = - endpoint !== undefined + params.endpoint !== undefined ? new KMSClient({ - region, - endpoint, - credentials + region: params.region, + endpoint: params.endpoint, + credentials: params.credentials }) - : credentials !== undefined - ? new KMSClient({ region, credentials }) - : new KMSClient({ region }); + : params.credentials !== undefined + ? new KMSClient({ + region: params.region, + credentials: params.credentials + }) + : new KMSClient({ region: params.region }); } /** @@ -112,4 +116,4 @@ class KMSVeChainProvider extends VeChainProvider { } } -export { KMSVeChainProvider }; +export { KMSVeChainProvider, type KMSClientParameters }; diff --git a/packages/aws-kms-adapter/src/index.ts b/packages/aws-kms-adapter/src/index.ts index abbbd3cf1..bc5be7721 100644 --- a/packages/aws-kms-adapter/src/index.ts +++ b/packages/aws-kms-adapter/src/index.ts @@ -1,2 +1,5 @@ -export { KMSVeChainProvider } from './KMSVeChainProvider'; +export { + KMSVeChainProvider, + type KMSClientParameters +} from './KMSVeChainProvider'; export { KMSVeChainSigner } from './KMSVeChainSigner'; diff --git a/packages/aws-kms-adapter/tests/KMSVeChainProvider.unit.test.ts b/packages/aws-kms-adapter/tests/KMSVeChainProvider.unit.test.ts index 3be221c16..9a0685f0d 100644 --- a/packages/aws-kms-adapter/tests/KMSVeChainProvider.unit.test.ts +++ b/packages/aws-kms-adapter/tests/KMSVeChainProvider.unit.test.ts @@ -33,11 +33,10 @@ describe('KMSVeChainProvider', () => { let instance: KMSVeChainProvider; beforeEach(() => { jest.clearAllMocks(); - instance = new KMSVeChainProvider( - {} as unknown as ThorClient, - 'keyId', - 'region' - ); + instance = new KMSVeChainProvider({} as unknown as ThorClient, { + keyId: 'keyId', + region: 'region' + }); }); describe('constructor', () => { it('should return the instance of the client', () => { @@ -46,12 +45,14 @@ describe('KMSVeChainProvider', () => { it('should return an instance when credentials and no endpoint', () => { const instance = new KMSVeChainProvider( {} as unknown as ThorClient, - 'keyId', - 'region', - false, { - accessKeyId: 'accessKeyId', - secretAccessKey: 'secretAccess' + keyId: 'keyId', + region: 'region', + enableDelegation: false, + credentials: { + accessKeyId: 'accessKeyId', + secretAccessKey: 'secretAccess' + } } ); expect(instance).toBeInstanceOf(KMSVeChainProvider); diff --git a/packages/aws-kms-adapter/tests/KMSVeChainSigner.solo.test.ts b/packages/aws-kms-adapter/tests/KMSVeChainSigner.solo.test.ts index 335d51ffc..96137a1fa 100644 --- a/packages/aws-kms-adapter/tests/KMSVeChainSigner.solo.test.ts +++ b/packages/aws-kms-adapter/tests/KMSVeChainSigner.solo.test.ts @@ -2,88 +2,32 @@ import { ABIContract, Address, Clause, - ERC20_ABI, HexUInt, Transaction, - VTHO_ADDRESS, type TransactionClause } from '@vechain/sdk-core'; -import { - ProviderInternalBaseWallet, - signerUtils, - THOR_SOLO_ACCOUNTS, - THOR_SOLO_URL, - ThorClient, - VeChainPrivateKeySigner, - VeChainProvider, - type TransactionReceipt -} from '@vechain/sdk-network'; +import { signerUtils, THOR_SOLO_URL, ThorClient } from '@vechain/sdk-network'; import fs from 'fs'; import path from 'path'; -import { KMSVeChainProvider, KMSVeChainSigner } from '../src'; +import { + type KMSClientParameters, + KMSVeChainProvider, + KMSVeChainSigner +} from '../src'; import { EIP712_CONTRACT, EIP712_FROM, EIP712_TO, + fundVTHO, signTransactionTestCases, TESTING_CONTRACT_ABI, - TESTING_CONTRACT_ADDRESS + TESTING_CONTRACT_ADDRESS, + timeout } from './fixture'; -const timeout = 8000; // 8 seconds - -interface AwsClientParameters { - keyId: string; - region: string; - enableDelegation?: boolean; - credentials: { - accessKeyId: string; - secretAccessKey: string; - sessionToken?: string; - }; - endpoint: string; -} - // This variable should be replaced once this is clarified https://github.com/localstack/localstack/issues/11678 let expectedAddress: string; -const fundVTHO = async ( - thorClient: ThorClient, - receiverAddress: string -): Promise => { - const signer = new VeChainPrivateKeySigner( - HexUInt.of(THOR_SOLO_ACCOUNTS[0].privateKey).bytes, - new VeChainProvider( - thorClient, - new ProviderInternalBaseWallet([]), - false - ) - ); - // Load the ERC20 contract - const contract = thorClient.contracts.load(VTHO_ADDRESS, ERC20_ABI, signer); - - const expectedVTHO = 200000000000000000000n; - - // Execute a 'transfer' transaction on the deployed contract, - // transferring a specified amount of tokens - const transferResult = await contract.transact.transfer( - { value: 0, comment: 'Transferring tokens' }, - receiverAddress, - expectedVTHO - ); - - // Wait for the transfer transaction to complete and obtain its receipt - const transactionReceiptTransfer = - (await transferResult.wait()) as TransactionReceipt; - - // Verify that the transfer transaction did not revert - expect(transactionReceiptTransfer.reverted).toBe(false); - - // Execute a 'balanceOf' call on the contract to check the balance of the receiver - const balanceOfResult = await contract.read.balanceOf(receiverAddress); - expect(balanceOfResult).toStrictEqual([expectedVTHO]); -}; - /** * AWS KMS VeChain signer tests - solo * @@ -106,19 +50,19 @@ describe('KMSVeChainSigner - Thor Solo', () => { let signerWithDelegator: KMSVeChainSigner; /** - * Init thor client and provider before each test + * Init thor client and provider before all tests */ beforeAll(async () => { const awsCredentialsPath = path.resolve( __dirname, './aws-credentials.json' ); - let awsClientParameters: AwsClientParameters; - let delegatorAwsClientParameters: AwsClientParameters; + let awsClientParameters: KMSClientParameters; + let delegatorAwsClientParameters: KMSClientParameters; try { [awsClientParameters, delegatorAwsClientParameters] = JSON.parse( fs.readFileSync(awsCredentialsPath, 'utf8') - ) as AwsClientParameters[]; + ) as KMSClientParameters[]; // eslint-disable-next-line @typescript-eslint/no-unused-vars } catch (error) { console.log('Loading test credentials'); @@ -128,20 +72,13 @@ describe('KMSVeChainSigner - Thor Solo', () => { ); [awsClientParameters, delegatorAwsClientParameters] = JSON.parse( fs.readFileSync(testAwsCredentialsPath, 'utf8') - ) as AwsClientParameters[]; + ) as KMSClientParameters[]; } thorClient = ThorClient.fromUrl(THOR_SOLO_URL); // Signer with delegator disabled signer = new KMSVeChainSigner( - new KMSVeChainProvider( - thorClient, - awsClientParameters.keyId, - awsClientParameters.region, - undefined, - awsClientParameters.credentials, - awsClientParameters.endpoint - ) + new KMSVeChainProvider(thorClient, awsClientParameters) ); expectedAddress = await signer.getAddress(); // This step should be removed once this is clarified https://github.com/localstack/localstack/issues/11678 @@ -150,22 +87,14 @@ describe('KMSVeChainSigner - Thor Solo', () => { // Signer with delegator enabled const delegatorProvider = new KMSVeChainProvider( thorClient, - delegatorAwsClientParameters.keyId, - delegatorAwsClientParameters.region, - undefined, - delegatorAwsClientParameters.credentials, - delegatorAwsClientParameters.endpoint + delegatorAwsClientParameters ); expect(delegatorProvider).toBeInstanceOf(KMSVeChainProvider); signerWithDelegator = new KMSVeChainSigner( - new KMSVeChainProvider( - thorClient, - awsClientParameters.keyId, - awsClientParameters.region, - true, - awsClientParameters.credentials, - awsClientParameters.endpoint - ), + new KMSVeChainProvider(thorClient, { + ...awsClientParameters, + enableDelegation: true + }), { provider: delegatorProvider } diff --git a/packages/aws-kms-adapter/tests/KMSVeChainSigner.unit.test.ts b/packages/aws-kms-adapter/tests/KMSVeChainSigner.unit.test.ts index bb6313b88..ea316ae1a 100644 --- a/packages/aws-kms-adapter/tests/KMSVeChainSigner.unit.test.ts +++ b/packages/aws-kms-adapter/tests/KMSVeChainSigner.unit.test.ts @@ -50,8 +50,7 @@ describe('KMSVeChainSigner', () => { it('should break if asn1 decoding fails', async () => { const provider = new KMSVeChainProvider( {} as unknown as ThorClient, - 'keyId', - 'region' + { keyId: 'keyId', region: 'region' } ); jest.spyOn(provider, 'getPublicKey').mockResolvedValue( Txt.of('publicKey').bytes @@ -66,8 +65,7 @@ describe('KMSVeChainSigner', () => { it('should throw an error if there is an error in the body of the method', async () => { const provider = new KMSVeChainProvider( {} as unknown as ThorClient, - 'keyId', - 'region' + { keyId: 'keyId', region: 'region' } ); const signer = new KMSVeChainSigner(provider); await expect( @@ -79,8 +77,7 @@ describe('KMSVeChainSigner', () => { it('should throw an error if there is an error in the body of the method', async () => { const provider = new KMSVeChainProvider( {} as unknown as ThorClient, - 'keyId', - 'region' + { keyId: 'keyId', region: 'region' } ); const signer = new KMSVeChainSigner(provider); await expect( @@ -92,8 +89,7 @@ describe('KMSVeChainSigner', () => { it('should throw an error if there is an error in the body of the method', async () => { const provider = new KMSVeChainProvider( {} as unknown as ThorClient, - 'keyId', - 'region' + { keyId: 'keyId', region: 'region' } ); const signer = new KMSVeChainSigner(provider); await expect( @@ -156,8 +152,7 @@ describe('KMSVeChainSigner', () => { it('should throw an error if there is an error in the body of the method', async () => { const provider = new KMSVeChainProvider( {} as unknown as ThorClient, - 'keyId', - 'region' + { keyId: 'keyId', region: 'region' } ); const signer = new KMSVeChainSigner(provider); await expect( diff --git a/packages/aws-kms-adapter/tests/fixture.ts b/packages/aws-kms-adapter/tests/fixture.ts index d00df9e56..f13bf1ba0 100644 --- a/packages/aws-kms-adapter/tests/fixture.ts +++ b/packages/aws-kms-adapter/tests/fixture.ts @@ -1,3 +1,15 @@ +import { ERC20_ABI, HexUInt, VTHO_ADDRESS } from '@vechain/sdk-core'; +import { + ProviderInternalBaseWallet, + THOR_SOLO_ACCOUNTS, + type ThorClient, + type TransactionReceipt, + VeChainPrivateKeySigner, + VeChainProvider +} from '@vechain/sdk-network'; + +const timeout = 8000; // 8 seconds + /** * `TestingContract.sol` deployed contract address on thor-solo snapshot. */ @@ -840,14 +852,80 @@ const signTransactionTestCases = { } } ] + }, + testnet: { + correct: [ + { + description: 'Should sign a transaction with delegation url', + isDelegated: true, + expected: { + body: { + chainTag: 39, + clauses: [ + { + data: '0x01cb08c5000000000000000000000000000000000000000000000000000000000000007b', + to: '0xb2c20a6de401003a671659b10629eb82ff254fb8', + value: 0 + } + ], + dependsOn: null, + expiration: 32, + gas: 21464, + gasPriceCoef: 0, + reserved: { + features: 1 + } + } + } + } + ] } }; +const fundVTHO = async ( + thorClient: ThorClient, + receiverAddress: string +): Promise => { + const signer = new VeChainPrivateKeySigner( + HexUInt.of(THOR_SOLO_ACCOUNTS[0].privateKey).bytes, + new VeChainProvider( + thorClient, + new ProviderInternalBaseWallet([]), + false + ) + ); + // Load the ERC20 contract + const contract = thorClient.contracts.load(VTHO_ADDRESS, ERC20_ABI, signer); + + const expectedVTHO = 200000000000000000000n; + + // Execute a 'transfer' transaction on the deployed contract, + // transferring a specified amount of tokens + const transferResult = await contract.transact.transfer( + { value: 0, comment: 'Transferring tokens' }, + receiverAddress, + expectedVTHO + ); + + // Wait for the transfer transaction to complete and obtain its receipt + const transactionReceiptTransfer = + (await transferResult.wait()) as TransactionReceipt; + + // Verify that the transfer transaction did not revert + expect(transactionReceiptTransfer.reverted).toBe(false); + + // Execute a 'balanceOf' call on the contract to check the balance of the receiver + const balanceOfResult = await contract.read.balanceOf(receiverAddress); + expect(balanceOfResult).toStrictEqual([expectedVTHO]); +}; + export { EIP712_CONTRACT, EIP712_FROM, EIP712_TO, + fundVTHO, + signTransactionTestCases, TESTING_CONTRACT_ABI, TESTING_CONTRACT_ADDRESS, - signTransactionTestCases + timeout }; From 8dcce930a184a8ec593b041e484bdfa446346df7 Mon Sep 17 00:00:00 2001 From: Miguel Angel Rojo Fernandez Date: Tue, 22 Oct 2024 17:32:20 +0100 Subject: [PATCH 24/35] feat: still delegation url to test --- .../vechain/vechain-provider.testnet.test.ts | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/packages/network/tests/provider/providers/vechain/vechain-provider.testnet.test.ts b/packages/network/tests/provider/providers/vechain/vechain-provider.testnet.test.ts index 794ac8b7a..31c1ac9be 100644 --- a/packages/network/tests/provider/providers/vechain/vechain-provider.testnet.test.ts +++ b/packages/network/tests/provider/providers/vechain/vechain-provider.testnet.test.ts @@ -1,12 +1,9 @@ import { afterEach, beforeEach, describe, expect, test } from '@jest/globals'; -import { - JSONRPCInvalidParams, - JSONRPCMethodNotFound -} from '@vechain/sdk-errors'; +import { JSONRPCMethodNotFound } from '@vechain/sdk-errors'; +import { TESTNET_URL, ThorClient, VeChainProvider } from '../../../../src'; import { providerMethodsTestCasesTestnet } from '../fixture'; import { waitForMessage } from '../helpers'; -import { TESTNET_URL, ThorClient, VeChainProvider } from '../../../../src'; /** *VeChain provider tests @@ -111,16 +108,6 @@ describe('VeChain provider tests - testnet', () => { ).rejects.toThrowError(JSONRPCMethodNotFound); }); - /** - * Invalid delegation - */ - test('Should throw an error if delegation is enabled and delegator is not defined', () => { - expect(() => { - // eslint-disable-next-line no-new - new VeChainProvider(thorClient, undefined, true); - }).toThrowError(JSONRPCInvalidParams); - }); - /** * Return null signer if wallet is not defined */ From ad36cf21659af9826a40f068310402d12b4f4e17 Mon Sep 17 00:00:00 2001 From: Miguel Angel Rojo Fernandez Date: Tue, 22 Oct 2024 17:36:45 +0100 Subject: [PATCH 25/35] feat: still delegation url to test --- packages/aws-kms-adapter/src/KMSVeChainProvider.ts | 10 +++++++--- .../tests/KMSVeChainProvider.unit.test.ts | 1 - .../tests/KMSVeChainSigner.solo.test.ts | 5 +---- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/aws-kms-adapter/src/KMSVeChainProvider.ts b/packages/aws-kms-adapter/src/KMSVeChainProvider.ts index b5f338707..2e23419ce 100644 --- a/packages/aws-kms-adapter/src/KMSVeChainProvider.ts +++ b/packages/aws-kms-adapter/src/KMSVeChainProvider.ts @@ -16,7 +16,6 @@ import { KMSVeChainSigner } from './KMSVeChainSigner'; interface KMSClientParameters { keyId: string; region: string; - enableDelegation?: boolean; credentials?: { accessKeyId: string; secretAccessKey: string; @@ -34,9 +33,14 @@ class KMSVeChainProvider extends VeChainProvider { * Creates a new instance of KMSVeChainProvider. * @param thorClient The thor client instance to use. * @param params The parameters to configure the KMS client and the keyId. + * @param enableDelegation Whether to enable delegation or not. **/ - public constructor(thorClient: ThorClient, params: KMSClientParameters) { - super(thorClient, undefined, params.enableDelegation); + public constructor( + thorClient: ThorClient, + params: KMSClientParameters, + enableDelegation: boolean = false + ) { + super(thorClient, undefined, enableDelegation); this.keyId = params.keyId; this.kmsClient = params.endpoint !== undefined diff --git a/packages/aws-kms-adapter/tests/KMSVeChainProvider.unit.test.ts b/packages/aws-kms-adapter/tests/KMSVeChainProvider.unit.test.ts index 9a0685f0d..25b29712a 100644 --- a/packages/aws-kms-adapter/tests/KMSVeChainProvider.unit.test.ts +++ b/packages/aws-kms-adapter/tests/KMSVeChainProvider.unit.test.ts @@ -48,7 +48,6 @@ describe('KMSVeChainProvider', () => { { keyId: 'keyId', region: 'region', - enableDelegation: false, credentials: { accessKeyId: 'accessKeyId', secretAccessKey: 'secretAccess' diff --git a/packages/aws-kms-adapter/tests/KMSVeChainSigner.solo.test.ts b/packages/aws-kms-adapter/tests/KMSVeChainSigner.solo.test.ts index 96137a1fa..26a6001e4 100644 --- a/packages/aws-kms-adapter/tests/KMSVeChainSigner.solo.test.ts +++ b/packages/aws-kms-adapter/tests/KMSVeChainSigner.solo.test.ts @@ -91,10 +91,7 @@ describe('KMSVeChainSigner - Thor Solo', () => { ); expect(delegatorProvider).toBeInstanceOf(KMSVeChainProvider); signerWithDelegator = new KMSVeChainSigner( - new KMSVeChainProvider(thorClient, { - ...awsClientParameters, - enableDelegation: true - }), + new KMSVeChainProvider(thorClient, awsClientParameters, true), { provider: delegatorProvider } From e348ea5b7471a679aab757749f9c11f3a56016ee Mon Sep 17 00:00:00 2001 From: Miguel Angel Rojo Fernandez Date: Tue, 22 Oct 2024 17:38:05 +0100 Subject: [PATCH 26/35] feat: still delegation url to test --- packages/aws-kms-adapter/src/KMSVeChainSigner.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/aws-kms-adapter/src/KMSVeChainSigner.ts b/packages/aws-kms-adapter/src/KMSVeChainSigner.ts index 0caf8ee18..864fc4512 100644 --- a/packages/aws-kms-adapter/src/KMSVeChainSigner.ts +++ b/packages/aws-kms-adapter/src/KMSVeChainSigner.ts @@ -39,7 +39,7 @@ class KMSVeChainSigner extends VeChainAbstractSigner { if (!(this.provider instanceof KMSVeChainProvider)) { throw new JSONRPCInvalidParams( 'KMSVeChainSigner.constructor', - 'The provider object is not well formed, it should be an instance of KMSVeChainProvider.', + 'The provider must be an instance of KMSVeChainProvider.', { provider } ); } From 015343815c385868d80c1b2509442f6050b860fd Mon Sep 17 00:00:00 2001 From: Miguel Angel Rojo Fernandez Date: Tue, 22 Oct 2024 17:46:48 +0100 Subject: [PATCH 27/35] feat: still delegation url to test --- packages/aws-kms-adapter/src/KMSVeChainSigner.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/aws-kms-adapter/src/KMSVeChainSigner.ts b/packages/aws-kms-adapter/src/KMSVeChainSigner.ts index 864fc4512..c0f4f0c4c 100644 --- a/packages/aws-kms-adapter/src/KMSVeChainSigner.ts +++ b/packages/aws-kms-adapter/src/KMSVeChainSigner.ts @@ -207,7 +207,7 @@ class KMSVeChainSigner extends VeChainAbstractSigner { private async getRecoveryBit( decodedSignatureWithoutRecoveryBit: SignatureType, transactionHash: Uint8Array, - kmsProvider: KMSVeChainProvider | undefined = this.kmsVeChainProvider + kmsProvider: KMSVeChainProvider ): Promise { const publicKey = await this.getDecodedPublicKey(kmsProvider); const publicKeyHex = toHex(publicKey); From 969cf55833b7756286f44e31d6fec6c04b03faeb Mon Sep 17 00:00:00 2001 From: Miguel Angel Rojo Fernandez Date: Tue, 22 Oct 2024 17:49:48 +0100 Subject: [PATCH 28/35] feat: still delegation url to test --- packages/aws-kms-adapter/src/KMSVeChainSigner.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/aws-kms-adapter/src/KMSVeChainSigner.ts b/packages/aws-kms-adapter/src/KMSVeChainSigner.ts index c0f4f0c4c..cbc3a6d9c 100644 --- a/packages/aws-kms-adapter/src/KMSVeChainSigner.ts +++ b/packages/aws-kms-adapter/src/KMSVeChainSigner.ts @@ -28,7 +28,7 @@ class KMSVeChainSigner extends VeChainAbstractSigner { public constructor( provider?: AvailableVeChainProviders, - readonly delegator?: { + delegator?: { provider?: AvailableVeChainProviders; url?: string; } From 0b3e99bd705446f0d3b3f45981a5d562cf29e2bd Mon Sep 17 00:00:00 2001 From: Miguel Angel Rojo Fernandez Date: Wed, 23 Oct 2024 11:04:32 +0100 Subject: [PATCH 29/35] feat: fixed delegated hash --- packages/aws-kms-adapter/src/KMSVeChainSigner.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/aws-kms-adapter/src/KMSVeChainSigner.ts b/packages/aws-kms-adapter/src/KMSVeChainSigner.ts index cbc3a6d9c..3884dce99 100644 --- a/packages/aws-kms-adapter/src/KMSVeChainSigner.ts +++ b/packages/aws-kms-adapter/src/KMSVeChainSigner.ts @@ -250,9 +250,13 @@ class KMSVeChainSigner extends VeChainAbstractSigner { // We try first in case there is a delegator provider if (this.kmsVeChainDelegatorProvider !== undefined) { + const publicKeyDecoded = await this.getDecodedPublicKey(); + const originAddress = Address.ofPublicKey(publicKeyDecoded); + const delegatedHash = + transaction.getTransactionHash(originAddress).bytes; const delegatorSignature = await this.buildVeChainSignatureFromPayload( - transactionHash, + delegatedHash, this.kmsVeChainDelegatorProvider ); return concatBytes(originSignature, delegatorSignature); From 4f5b430ab486f4268fdeeae78bb932910f2729b1 Mon Sep 17 00:00:00 2001 From: Miguel Angel Rojo Fernandez Date: Wed, 23 Oct 2024 11:12:47 +0100 Subject: [PATCH 30/35] feat: more tests --- .../tests/KMSVeChainSigner.solo.test.ts | 79 +++++++++++-------- 1 file changed, 47 insertions(+), 32 deletions(-) diff --git a/packages/aws-kms-adapter/tests/KMSVeChainSigner.solo.test.ts b/packages/aws-kms-adapter/tests/KMSVeChainSigner.solo.test.ts index 26a6001e4..8241fe332 100644 --- a/packages/aws-kms-adapter/tests/KMSVeChainSigner.solo.test.ts +++ b/packages/aws-kms-adapter/tests/KMSVeChainSigner.solo.test.ts @@ -19,6 +19,7 @@ import { EIP712_FROM, EIP712_TO, fundVTHO, + signTransactionTestCases as sendTransactionTestCases, signTransactionTestCases, TESTING_CONTRACT_ABI, TESTING_CONTRACT_ADDRESS, @@ -178,43 +179,57 @@ describe('KMSVeChainSigner - Thor Solo', () => { * Test suite for sendTransaction method */ describe('sendTransaction', () => { - test( - 'should send a transaction successfully', - async () => { - const sampleClause = Clause.callFunction( - Address.of(TESTING_CONTRACT_ADDRESS), - ABIContract.ofAbi(TESTING_CONTRACT_ABI).getFunction( - 'deposit' - ), - [123] - ) as TransactionClause; + /** + * sendTransaction test cases with different options + */ + sendTransactionTestCases.solo.correct.forEach( + ({ description, isDelegated }) => { + test( + description, + async () => { + const signTransactionSigner = isDelegated + ? signerWithDelegator + : signer; + const sampleClause = Clause.callFunction( + Address.of(TESTING_CONTRACT_ADDRESS), + ABIContract.ofAbi(TESTING_CONTRACT_ABI).getFunction( + 'deposit' + ), + [123] + ) as TransactionClause; - const originAddress = await signer.getAddress(); + const originAddress = + await signTransactionSigner.getAddress(); - const gasResult = await thorClient.gas.estimateGas( - [sampleClause], - originAddress - ); + const gasResult = await thorClient.gas.estimateGas( + [sampleClause], + originAddress + ); - const txBody = - await thorClient.transactions.buildTransactionBody( - [sampleClause], - gasResult.totalGas, - { - isDelegated: false - } - ); + const txBody = + await thorClient.transactions.buildTransactionBody( + [sampleClause], + gasResult.totalGas, + { + isDelegated + } + ); - const receipt = await signer.sendTransaction( - signerUtils.transactionBodyToTransactionRequestInput( - txBody, - originAddress - ) - ); + const receipt = + await signTransactionSigner.sendTransaction( + signerUtils.transactionBodyToTransactionRequestInput( + txBody, + originAddress + ) + ); - expect(receipt.match(/^0x([A-Fa-f0-9]{64})$/)).toBeTruthy(); - }, - timeout + expect( + receipt.match(/^0x([A-Fa-f0-9]{64})$/) + ).toBeTruthy(); + }, + timeout + ); + } ); }); From 7ff51f6701e149f938c15c8427b74a536b6f810a Mon Sep 17 00:00:00 2001 From: Miguel Angel Rojo Fernandez Date: Wed, 23 Oct 2024 18:06:15 +0100 Subject: [PATCH 31/35] feat: added testnet tests --- packages/aws-kms-adapter/package.json | 2 +- .../tests/KMSVeChainSigner.testnet.test.ts | 165 +++++++ packages/aws-kms-adapter/tests/fixture.ts | 458 +++++++++++++++++- 3 files changed, 622 insertions(+), 3 deletions(-) create mode 100644 packages/aws-kms-adapter/tests/KMSVeChainSigner.testnet.test.ts diff --git a/packages/aws-kms-adapter/package.json b/packages/aws-kms-adapter/package.json index 223ac149d..9f9ceb6de 100644 --- a/packages/aws-kms-adapter/package.json +++ b/packages/aws-kms-adapter/package.json @@ -22,7 +22,7 @@ "stop-thor-solo": "echo 'Stopping thor solo node ...' && docker compose -f ../../docker-compose.thor.yml -f ../../docker-compose.localstack.yml --profile thor-solo down && echo 'Thor solo node and localstack stopped ...'", "test": "docker compose -f ../../docker-compose.localstack.yml up -d && sleep 10 && yarn test:all; ret=$?; docker compose -f ../../docker-compose.localstack.yml down; exit $ret", "test:all": "rm -rf ./coverage && jest --coverage --coverageDirectory=coverage --group=integration --group=unit", - "test:solo": "(yarn start-thor-solo && yarn test:all && yarn stop-thor-solo) || yarn stop-thor-solo", + "test:integration": "(yarn start-thor-solo && yarn test:all && yarn stop-thor-solo) || yarn stop-thor-solo", "test:unit": "rm -rf ./coverageUnit && UNIT=true jest --coverage --coverageDirectory=coverageUnit --group=unit" }, "dependencies": { diff --git a/packages/aws-kms-adapter/tests/KMSVeChainSigner.testnet.test.ts b/packages/aws-kms-adapter/tests/KMSVeChainSigner.testnet.test.ts new file mode 100644 index 000000000..bf9126f60 --- /dev/null +++ b/packages/aws-kms-adapter/tests/KMSVeChainSigner.testnet.test.ts @@ -0,0 +1,165 @@ +import { + ABIContract, + Address, + Clause, + HexUInt, + Transaction, + type TransactionClause +} from '@vechain/sdk-core'; +import { signerUtils, TESTNET_URL, ThorClient } from '@vechain/sdk-network'; +import fs from 'fs'; +import path from 'path'; +import { + type KMSClientParameters, + KMSVeChainProvider, + KMSVeChainSigner +} from '../src'; +import { + addAddressToFeeDelegationWhitelist, + removeAddressFromFeeDelegationWhitelist, + signTransactionTestCases, + TESTING_CONTRACT_ABI, + TESTING_CONTRACT_ADDRESS, + TESTNET_DELEGATE_URL, + timeout +} from './fixture'; + +/** + * AWS KMS VeChain signer tests - testnet + * + * @group integration/signers/vechain-aws-kms-signer-testnet + */ +describe('KMSVeChainSigner - Testnet', () => { + /** + * ThorClient and provider instances + */ + let thorClient: ThorClient; + + /** + * KMSVeChainSigner with delegator instance + */ + let signerWithDelegator: KMSVeChainSigner; + + /** + * Init thor client and provider before all tests + */ + beforeAll(async () => { + const awsCredentialsPath = path.resolve( + __dirname, + './aws-credentials.json' + ); + let awsClientParameters: KMSClientParameters; + let delegatorAwsClientParameters: KMSClientParameters; + try { + [awsClientParameters, delegatorAwsClientParameters] = JSON.parse( + fs.readFileSync(awsCredentialsPath, 'utf8') + ) as KMSClientParameters[]; + // eslint-disable-next-line @typescript-eslint/no-unused-vars + } catch (error) { + console.log('Loading test credentials'); + const testAwsCredentialsPath = path.resolve( + __dirname, + './test-aws-credentials.json' + ); + [awsClientParameters, delegatorAwsClientParameters] = JSON.parse( + fs.readFileSync(testAwsCredentialsPath, 'utf8') + ) as KMSClientParameters[]; + } + thorClient = ThorClient.fromUrl(TESTNET_URL); + + // Signer with delegator enabled + const delegatorProvider = new KMSVeChainProvider( + thorClient, + delegatorAwsClientParameters + ); + expect(delegatorProvider).toBeInstanceOf(KMSVeChainProvider); + signerWithDelegator = new KMSVeChainSigner( + new KMSVeChainProvider(thorClient, awsClientParameters, true), + { + url: TESTNET_DELEGATE_URL + } + ); + + await addAddressToFeeDelegationWhitelist( + thorClient, + await signerWithDelegator.getAddress() + ); + }, 4 * timeout); + + afterAll(async () => { + await removeAddressFromFeeDelegationWhitelist( + thorClient, + await signerWithDelegator.getAddress() + ); + }, 4 * timeout); + + describe('constructor', () => { + test('should create a new instance of KMSVeChainSigner', () => { + expect(() => new KMSVeChainSigner(undefined, {})).toThrow(); + }); + }); + + /** + * Test suite for signTransaction method + */ + describe('signTransaction', () => { + /** + * signTransaction test cases with different options + */ + signTransactionTestCases.testnet.correct.forEach( + ({ description, isDelegated, expected }) => { + test( + description, + async () => { + const sampleClause = Clause.callFunction( + Address.of(TESTING_CONTRACT_ADDRESS), + ABIContract.ofAbi(TESTING_CONTRACT_ABI).getFunction( + 'deposit' + ), + [123] + ) as TransactionClause; + + const originAddress = + await signerWithDelegator.getAddress(); + + const gasResult = await thorClient.gas.estimateGas( + [sampleClause], + originAddress + ); + + const txBody = + await thorClient.transactions.buildTransactionBody( + [sampleClause], + gasResult.totalGas, + { + isDelegated + } + ); + + const signedRawTx = + await signerWithDelegator.signTransaction( + signerUtils.transactionBodyToTransactionRequestInput( + txBody, + originAddress + ) + ); + const signedTx = Transaction.decode( + HexUInt.of(signedRawTx.slice(2)).bytes, + true + ); + + expect(signedTx).toBeDefined(); + expect(signedTx.body).toMatchObject(expected.body); + expect(signedTx.origin.toString()).toBe( + Address.checksum(HexUInt.of(originAddress)) + ); + expect(signedTx.isDelegated).toBe(isDelegated); + expect(signedTx.isSigned).toBe(true); + expect(signedTx.signature).toBeDefined(); + }, + timeout + ); + } + ); + }); +}); diff --git a/packages/aws-kms-adapter/tests/fixture.ts b/packages/aws-kms-adapter/tests/fixture.ts index f13bf1ba0..6b7767dbe 100644 --- a/packages/aws-kms-adapter/tests/fixture.ts +++ b/packages/aws-kms-adapter/tests/fixture.ts @@ -1,4 +1,4 @@ -import { ERC20_ABI, HexUInt, VTHO_ADDRESS } from '@vechain/sdk-core'; +import { ERC20_ABI, HexUInt, Mnemonic, VTHO_ADDRESS } from '@vechain/sdk-core'; import { ProviderInternalBaseWallet, THOR_SOLO_ACCOUNTS, @@ -863,7 +863,7 @@ const signTransactionTestCases = { chainTag: 39, clauses: [ { - data: '0x01cb08c5000000000000000000000000000000000000000000000000000000000000007b', + data: '0xb6b55f25000000000000000000000000000000000000000000000000000000000000007b', to: '0xb2c20a6de401003a671659b10629eb82ff254fb8', value: 0 } @@ -919,13 +919,467 @@ const fundVTHO = async ( expect(balanceOfResult).toStrictEqual([expectedVTHO]); }; +/** + * Delegate url fixture to test signing transactions with delegation by URL + */ +const TESTNET_DELEGATE_URL = 'https://sponsor-testnet.vechain.energy/by/705'; + +const FEE_DELEGATION_ABI = [ + { + inputs: [ + { + internalType: 'address', + name: '_address', + type: 'address' + }, + { + internalType: 'uint256', + name: 'tokenId', + type: 'uint256' + } + ], + name: 'addAllowedRecipientFor', + outputs: [], + stateMutability: 'nonpayable', + type: 'function' + }, + { + inputs: [ + { + internalType: 'bytes32', + name: '_title', + type: 'bytes32' + } + ], + name: 'mintSponsorship', + outputs: [], + stateMutability: 'nonpayable', + type: 'function' + }, + { + inputs: [ + { + internalType: 'address', + name: '_address', + type: 'address' + }, + { + internalType: 'uint256', + name: 'tokenId', + type: 'uint256' + } + ], + name: 'addAllowedSenderFor', + outputs: [], + stateMutability: 'nonpayable', + type: 'function' + }, + { + inputs: [ + { + internalType: 'address', + name: '_address', + type: 'address' + }, + { + internalType: 'uint256', + name: 'tokenId', + type: 'uint256' + } + ], + name: 'addMaintainerFor', + outputs: [], + stateMutability: 'nonpayable', + type: 'function' + }, + { + inputs: [ + { + internalType: 'uint256', + name: 'tokenId', + type: 'uint256' + } + ], + name: 'signerOf', + outputs: [ + { + internalType: 'address', + name: 'signer', + type: 'address' + } + ], + stateMutability: 'view', + type: 'function' + }, + { + inputs: [ + { + internalType: 'uint256', + name: 'tokenId', + type: 'uint256' + } + ], + name: 'contractOf', + outputs: [ + { + internalType: 'address', + name: '', + type: 'address' + } + ], + stateMutability: 'view', + type: 'function' + }, + { + inputs: [ + { + internalType: 'uint256', + name: 'tokenId', + type: 'uint256' + } + ], + name: 'ownerOf', + outputs: [ + { + internalType: 'address', + name: 'owner', + type: 'address' + } + ], + stateMutability: 'view', + type: 'function' + }, + { + inputs: [ + { + internalType: 'bytes32[]', + name: '_keys', + type: 'bytes32[]' + }, + { + internalType: 'uint256', + name: 'tokenId', + type: 'uint256' + } + ], + name: 'getDataFor', + outputs: [ + { + internalType: 'bytes32[]', + name: '_values', + type: 'bytes32[]' + } + ], + stateMutability: 'view', + type: 'function' + }, + { + inputs: [ + { + internalType: 'uint256', + name: '_tokenId', + type: 'uint256' + } + ], + name: 'requestWithdrawBalanceFor', + outputs: [], + stateMutability: 'view', + type: 'function' + }, + { + inputs: [ + { + internalType: 'uint256', + name: 'tokenId', + type: 'uint256' + } + ], + name: 'burn', + outputs: [], + stateMutability: 'view', + type: 'function' + }, + { + inputs: [ + { + internalType: 'uint256', + name: 'tokenId', + type: 'uint256' + } + ], + name: 'maintainersFor', + outputs: [ + { + internalType: 'address[]', + name: '', + type: 'address[]' + } + ], + stateMutability: 'view', + type: 'function' + }, + { + inputs: [ + { + internalType: 'uint256', + name: 'tokenId', + type: 'uint256' + } + ], + name: 'allowedRecipientsFor', + outputs: [ + { + internalType: 'address[]', + name: '', + type: 'address[]' + } + ], + stateMutability: 'view', + type: 'function' + }, + { + inputs: [ + { + internalType: 'uint256', + name: 'tokenId', + type: 'uint256' + } + ], + name: 'allowedSendersFor', + outputs: [ + { + internalType: 'address[]', + name: '', + type: 'address[]' + } + ], + stateMutability: 'view', + type: 'function' + }, + { + inputs: [ + { + internalType: 'address', + name: '_address', + type: 'address' + }, + { + internalType: 'uint256', + name: 'tokenId', + type: 'uint256' + } + ], + name: 'removeAllowedRecipientFor', + outputs: [], + stateMutability: 'nonpayable', + type: 'function' + }, + { + inputs: [ + { + internalType: 'address', + name: '_address', + type: 'address' + }, + { + internalType: 'uint256', + name: 'tokenId', + type: 'uint256' + } + ], + name: 'removeAllowedSenderFor', + outputs: [], + stateMutability: 'nonpayable', + type: 'function' + }, + { + inputs: [ + { + internalType: 'address', + name: '_address', + type: 'address' + }, + { + internalType: 'uint256', + name: 'tokenId', + type: 'uint256' + } + ], + name: 'removeMaintainerFor', + outputs: [], + stateMutability: 'nonpayable', + type: 'function' + }, + { + inputs: [ + { + internalType: 'uint256', + name: 'tokenId', + type: 'uint256' + } + ], + name: 'maintainersFor', + outputs: [ + { + internalType: 'address[]', + name: '', + type: 'address[]' + } + ], + stateMutability: 'view', + type: 'function' + }, + { + inputs: [ + { + internalType: 'address', + name: '_address', + type: 'address' + }, + { + internalType: 'uint256', + name: 'tokenId', + type: 'uint256' + } + ], + name: 'setContractFor', + outputs: [], + stateMutability: 'nonpayable', + type: 'function' + }, + { + inputs: [ + { + internalType: 'uint256', + name: 'tokenId', + type: 'uint256' + } + ], + name: 'contractOf', + outputs: [ + { + internalType: 'address', + name: '', + type: 'address' + } + ], + stateMutability: 'view', + type: 'function' + } +] as const; + +const FEE_DELEGATION_ADDRESS = '0x0bc7cc67d618a9b5054183faa3b58a25bd5bb928'; + +const FEE_DELEGATION_PRIVATE_KEY = Mnemonic.toPrivateKey( + 'tone life garage donkey panic female night scout cram chair fade fork'.split( + ' ' + ) +); + +const addAddressToFeeDelegationWhitelist = async ( + thorClient: ThorClient, + address: string +): Promise => { + const signer = new VeChainPrivateKeySigner( + FEE_DELEGATION_PRIVATE_KEY, + new VeChainProvider( + thorClient, + new ProviderInternalBaseWallet([]), + false + ) + ); + // Load the FeeDelegation contract + const contract = thorClient.contracts.load( + FEE_DELEGATION_ADDRESS, + FEE_DELEGATION_ABI, + signer + ); + + // Execute a 'addAllowedSenderFor' transaction on the loaded contract + const whitelistResult = await contract.transact.addAllowedSenderFor( + address, + 705n + ); + + // Wait for the transfer transaction to complete and obtain its receipt + const whitelistTransactionReceipt = + (await whitelistResult.wait()) as TransactionReceipt; + + // Verify that the transfer transaction did not revert + expect(whitelistTransactionReceipt.reverted).toBe(false); + + // Execute a 'addAllowedRecipientFor' transaction on the loaded contract + const whitelistRecipientResult = + await contract.transact.addAllowedRecipientFor( + TESTING_CONTRACT_ADDRESS, + 705n + ); + + // Wait for the transfer transaction to complete and obtain its receipt + const whitelistRecipientTransactionReceipt = + (await whitelistRecipientResult.wait()) as TransactionReceipt; + + // Verify that the transfer transaction did not revert + expect(whitelistRecipientTransactionReceipt.reverted).toBe(false); +}; + +const removeAddressFromFeeDelegationWhitelist = async ( + thorClient: ThorClient, + address: string +): Promise => { + const signer = new VeChainPrivateKeySigner( + FEE_DELEGATION_PRIVATE_KEY, + new VeChainProvider( + thorClient, + new ProviderInternalBaseWallet([]), + false + ) + ); + // Load the FeeDelegation contract + const contract = thorClient.contracts.load( + FEE_DELEGATION_ADDRESS, + FEE_DELEGATION_ABI, + signer + ); + + // Execute a 'removeAllowedSenderFor' transaction on the loaded contract + const whitelistResult = await contract.transact.removeAllowedSenderFor( + address, + 705n + ); + + // Wait for the transfer transaction to complete and obtain its receipt + const whitelistTransactionReceipt = + (await whitelistResult.wait()) as TransactionReceipt; + + // Verify that the transfer transaction did not revert + expect(whitelistTransactionReceipt.reverted).toBe(false); + + // Execute a 'addAllowedRecipientFor' transaction on the loaded contract + const whitelistRecipientResult = + await contract.transact.removeAllowedRecipientFor( + TESTING_CONTRACT_ADDRESS, + 705n + ); + + // Wait for the transfer transaction to complete and obtain its receipt + const whitelistRecipientTransactionReceipt = + (await whitelistRecipientResult.wait()) as TransactionReceipt; + + // Verify that the transfer transaction did not revert + expect(whitelistRecipientTransactionReceipt.reverted).toBe(false); +}; + export { + addAddressToFeeDelegationWhitelist, EIP712_CONTRACT, EIP712_FROM, EIP712_TO, fundVTHO, + removeAddressFromFeeDelegationWhitelist, signTransactionTestCases, TESTING_CONTRACT_ABI, TESTING_CONTRACT_ADDRESS, + TESTNET_DELEGATE_URL, timeout }; From cddbed529e309c0b14dd878058e6750ecfd032ee Mon Sep 17 00:00:00 2001 From: Miguel Angel Rojo Fernandez Date: Wed, 23 Oct 2024 18:19:36 +0100 Subject: [PATCH 32/35] feat: modified readme --- packages/aws-kms-adapter/README.md | 78 +++++++++++------------------- 1 file changed, 29 insertions(+), 49 deletions(-) diff --git a/packages/aws-kms-adapter/README.md b/packages/aws-kms-adapter/README.md index 97140ba5d..bcf86c7dc 100644 --- a/packages/aws-kms-adapter/README.md +++ b/packages/aws-kms-adapter/README.md @@ -7,7 +7,7 @@ The AWS KMS Adapter for VeChain SDK provides a secure way to sign transactions u - **Secure Key Management**: Use AWS KMS to securely manage and protect your private keys. - **Transaction Signing**: Sign VeChain transactions using keys stored in AWS KMS. - **Integration with VeChain SDK**: Seamlessly integrate with the VeChain SDK for blockchain interactions. -- **[WIP] Sign and send transactions using a delegator key**: You can specify the key ID of a delegator key to leverage this VeChain feature for signing and sending transactions. +- **Sign and send transactions using a delegator key**: You can specify the key ID of a delegator key to leverage this VeChain feature for signing and sending transactions. ## Installation @@ -29,7 +29,7 @@ yarn test:solo To integrate this into your code, depending on how you plan to manage your AWS credentials, you can choose one of the following examples. -Within this repo, you can create a credentials file called `aws-credentials.json` with your custom credentials under the `tests` folder in case you want to give it a try before integrating with your project. A valid format would be as follows (it is an array in case you want to include a delegator key): +Within this repo, you can create a credentials file called `aws-credentials.json` with your custom credentials under the `tests` folder in case you want to give it a try before integrating with your project. A valid format would be as follows (it is an array in case you want to include a delegator key, assumed to be the second one): ```json [ @@ -58,31 +58,22 @@ Within this repo, you can create a credentials file called `aws-credentials.json This is the preferred way. If you integrate this library in an app deployed in AWS following with IAM roles, you can just do as follows: ```ts -import { KMSVeChainProvider, KMSVeChainSigner } from '@vechain/sdk-aws-kms-adapter'; +import { type KMSClientParameters, KMSVeChainProvider, KMSVeChainSigner } from '@vechain/sdk-aws-kms-adapter'; import { THOR_SOLO_URL, ThorClient } from '@vechain/sdk-network'; ... - - interface AwsClientParameters { - keyId: string; - region: string; - credentials?: { - accessKeyId: string; - secretAccessKey: string; - sessionToken?: string; - }; - endpoint?: string; - } - + const awsClientParameters: KMSClientParameters = { + keyId: 'keyId', + region: 'region' + }; ... const thorClient = ThorClient.fromUrl(THOR_SOLO_URL); const provider = new KMSVeChainProvider( thorClient, - awsClientParameters.keyId, - awsClientParameters.region + awsClientParameters ); const signer = new KMSVeChainSigner(provider); // Signing typed data as per EIP712 @@ -98,33 +89,27 @@ import { This way you can connect to your AWS account by using `accessKeyId`, `secretAccessKey` and `sessionToken` if SSO is enabled. ```ts -import { KMSVeChainProvider, KMSVeChainSigner } from '@vechain/sdk-aws-kms-adapter'; +import { type KMSClientParameters, KMSVeChainProvider, KMSVeChainSigner } from '@vechain/sdk-aws-kms-adapter'; import { signerUtils, THOR_SOLO_URL, ThorClient } from '@vechain/sdk-network'; ... - - interface AwsClientParameters { - keyId: string; - region: string; - credentials?: { - accessKeyId: string; - secretAccessKey: string; - sessionToken?: string; - }; - endpoint?: string; - } - + const awsClientParameters: KMSClientParameters = { + keyId: 'keyId', + region: 'region', + credentials: { + accessKeyId: 'accessKeyId', + secretAccessKey: 'secretAccessKey' + } + }; ... const thorClient = ThorClient.fromUrl(THOR_SOLO_URL); const provider = new KMSVeChainProvider( thorClient, - awsClientParameters.keyId, - awsClientParameters.region - awsClientParameters.credentials + awsClientParameters ); const signer = new KMSVeChainSigner(provider); // Signing and sending a transaction @@ -141,32 +126,27 @@ import { You can also leverage LocalStack so you can try the library locally. Sample values are included in the file `tests/test-aws-credentials.json`. ```ts -import { KMSVeChainProvider, KMSVeChainSigner } from '@vechain/sdk-aws-kms-adapter'; +import { type KMSClientParameters, KMSVeChainProvider, KMSVeChainSigner } from '@vechain/sdk-aws-kms-adapter'; import { THOR_SOLO_URL, ThorClient } from '@vechain/sdk-network'; ... - - interface AwsClientParameters { - keyId: string; - region: string; - credentials?: { - accessKeyId: string; - secretAccessKey: string; - sessionToken?: string; - }; - endpoint?: string; - } - + const awsClientParameters: KMSClientParameters = { + keyId: 'keyId', + region: 'region', + credentials: { + accessKeyId: 'accessKeyId', + secretAccessKey: 'secretAccessKey' + }, + endpoint: 'localstackEndpoint' + }; ... const thorClient = ThorClient.fromUrl(THOR_SOLO_URL); const provider = new KMSVeChainProvider( thorClient, - awsClientParameters.keyId, - awsClientParameters.region - awsClientParameters.credentials + awsClientParameters ); const signer = new KMSVeChainSigner(provider); // Returns the address related to the KMS key From 6d066686166b745ada6740689f81a1277f97d29a Mon Sep 17 00:00:00 2001 From: Miguel Angel Rojo Fernandez Date: Wed, 23 Oct 2024 18:21:21 +0100 Subject: [PATCH 33/35] feat: modified readme --- packages/aws-kms-adapter/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/aws-kms-adapter/README.md b/packages/aws-kms-adapter/README.md index bcf86c7dc..a0c3a96f3 100644 --- a/packages/aws-kms-adapter/README.md +++ b/packages/aws-kms-adapter/README.md @@ -19,10 +19,10 @@ yarn add @vechain/sdk-aws-kms-adapter ## Test -To run all the tests, including the ones relying on a local instance of Thor Solo + LocalStack, please run: +To run all the tests, including the ones relying on a local instance of Thor Solo + LocalStack and Testnet, please run: ```bash -yarn test:solo +yarn test:integration ``` ## Usage From f6fde332fd5155afc52bccbdef9c83a02a494c88 Mon Sep 17 00:00:00 2001 From: Miguel Angel Rojo Fernandez Date: Thu, 24 Oct 2024 09:41:26 +0100 Subject: [PATCH 34/35] feat: modified readme --- packages/aws-kms-adapter/README.md | 94 +++++++++++++++++++ .../aws-kms-adapter/src/KMSVeChainSigner.ts | 2 +- .../tests/KMSVeChainSigner.testnet.test.ts | 11 +-- 3 files changed, 97 insertions(+), 10 deletions(-) diff --git a/packages/aws-kms-adapter/README.md b/packages/aws-kms-adapter/README.md index a0c3a96f3..c18b78bb0 100644 --- a/packages/aws-kms-adapter/README.md +++ b/packages/aws-kms-adapter/README.md @@ -152,3 +152,97 @@ import { // Returns the address related to the KMS key const address = await signer.getAddress(); ``` + +### Delegation (provider) + +You can also use delegation to sign your transactions. In this example the source of the delegation is a delegator which key is in KMS so requires a `KMSVeChainProvider`. + +```ts +import { type KMSClientParameters, KMSVeChainProvider, KMSVeChainSigner } from '@vechain/sdk-aws-kms-adapter'; +import { + THOR_SOLO_URL, + ThorClient +} from '@vechain/sdk-network'; + ... + const awsClientParameters: KMSClientParameters = { + keyId: 'keyId', + region: 'region', + credentials: { + accessKeyId: 'accessKeyId', + secretAccessKey: 'secretAccessKey' + }, + endpoint: 'localstackEndpoint' + }; + + const delegatorAwsClientParameters: KMSClientParameters = { + // Same format as awsClientParameters, changing values so we can connect + // to something different to LocalStack if we want (see examples above) + } + ... + + const thorClient = ThorClient.fromUrl(THOR_SOLO_URL); + const provider = new KMSVeChainProvider( + thorClient, + awsClientParameters + ); + + // Signer with delegator enabled + const delegatorProvider = new KMSVeChainProvider( + thorClient, + delegatorAwsClientParameters + ); + signerWithDelegator = new KMSVeChainSigner( + provider, + { + provider: delegatorProvider + } + ); + + // Returns the address related to the origin KMS key + const address = await signerWithDelegator.getAddress(); + // Returns the address related to the delegator KMS key + const address = await signerWithDelegator.getAddress(true); +``` + +### Delegation (url) + +You can also use delegation to sign your transactions. In this example the source of the delegation is a URL that returns the signature (for instance, `https://sponsor-testnet.vechain.energy/by/705`, more details on how to get yours [here](https://learn.vechain.energy/vechain.energy/FeeDelegation/Setup/)). + +```ts +import { type KMSClientParameters, KMSVeChainProvider, KMSVeChainSigner } from '@vechain/sdk-aws-kms-adapter'; +import { + THOR_SOLO_URL, + ThorClient +} from '@vechain/sdk-network'; + ... + const awsClientParameters: KMSClientParameters = { + keyId: 'keyId', + region: 'region', + credentials: { + accessKeyId: 'accessKeyId', + secretAccessKey: 'secretAccessKey' + }, + endpoint: 'localstackEndpoint' + }; + ... + + const thorClient = ThorClient.fromUrl(THOR_SOLO_URL); + + // Signer with delegator enabled + const provider = new KMSVeChainProvider( + thorClient, + awsClientParameters + ); + signerWithDelegator = new KMSVeChainSigner( + provider, + { + url: 'https://sponsor-testnet.vechain.energy/by/705' + } + ); + + // Returns the address related to the origin KMS key + const address = await signerWithDelegator.getAddress(); + + // See /tests folder for more examples. This time we wont get the address + // of the delegator since there is no provider +``` diff --git a/packages/aws-kms-adapter/src/KMSVeChainSigner.ts b/packages/aws-kms-adapter/src/KMSVeChainSigner.ts index 3884dce99..a537ffc00 100644 --- a/packages/aws-kms-adapter/src/KMSVeChainSigner.ts +++ b/packages/aws-kms-adapter/src/KMSVeChainSigner.ts @@ -151,7 +151,7 @@ class KMSVeChainSigner extends VeChainAbstractSigner { throw new SignerMethodError( 'KMSVeChainSigner.getAddress', 'The address could not be retrieved.', - {}, + { fromDelegator }, error ); } diff --git a/packages/aws-kms-adapter/tests/KMSVeChainSigner.testnet.test.ts b/packages/aws-kms-adapter/tests/KMSVeChainSigner.testnet.test.ts index bf9126f60..e2aaba8c1 100644 --- a/packages/aws-kms-adapter/tests/KMSVeChainSigner.testnet.test.ts +++ b/packages/aws-kms-adapter/tests/KMSVeChainSigner.testnet.test.ts @@ -49,9 +49,8 @@ describe('KMSVeChainSigner - Testnet', () => { './aws-credentials.json' ); let awsClientParameters: KMSClientParameters; - let delegatorAwsClientParameters: KMSClientParameters; try { - [awsClientParameters, delegatorAwsClientParameters] = JSON.parse( + [awsClientParameters] = JSON.parse( fs.readFileSync(awsCredentialsPath, 'utf8') ) as KMSClientParameters[]; // eslint-disable-next-line @typescript-eslint/no-unused-vars @@ -61,18 +60,12 @@ describe('KMSVeChainSigner - Testnet', () => { __dirname, './test-aws-credentials.json' ); - [awsClientParameters, delegatorAwsClientParameters] = JSON.parse( + [awsClientParameters] = JSON.parse( fs.readFileSync(testAwsCredentialsPath, 'utf8') ) as KMSClientParameters[]; } thorClient = ThorClient.fromUrl(TESTNET_URL); - // Signer with delegator enabled - const delegatorProvider = new KMSVeChainProvider( - thorClient, - delegatorAwsClientParameters - ); - expect(delegatorProvider).toBeInstanceOf(KMSVeChainProvider); signerWithDelegator = new KMSVeChainSigner( new KMSVeChainProvider(thorClient, awsClientParameters, true), { From 1ef2d71102483829a18c7d34821304ae7617e69d Mon Sep 17 00:00:00 2001 From: Miguel Angel Rojo Fernandez Date: Thu, 24 Oct 2024 09:54:06 +0100 Subject: [PATCH 35/35] feat: modified readme --- packages/aws-kms-adapter/README.md | 4 ++-- packages/aws-kms-adapter/src/KMSVeChainSigner.ts | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/aws-kms-adapter/README.md b/packages/aws-kms-adapter/README.md index c18b78bb0..8a00b2290 100644 --- a/packages/aws-kms-adapter/README.md +++ b/packages/aws-kms-adapter/README.md @@ -191,7 +191,7 @@ import { thorClient, delegatorAwsClientParameters ); - signerWithDelegator = new KMSVeChainSigner( + const signerWithDelegator = new KMSVeChainSigner( provider, { provider: delegatorProvider @@ -233,7 +233,7 @@ import { thorClient, awsClientParameters ); - signerWithDelegator = new KMSVeChainSigner( + const signerWithDelegator = new KMSVeChainSigner( provider, { url: 'https://sponsor-testnet.vechain.energy/by/705' diff --git a/packages/aws-kms-adapter/src/KMSVeChainSigner.ts b/packages/aws-kms-adapter/src/KMSVeChainSigner.ts index a537ffc00..a716eae93 100644 --- a/packages/aws-kms-adapter/src/KMSVeChainSigner.ts +++ b/packages/aws-kms-adapter/src/KMSVeChainSigner.ts @@ -134,14 +134,14 @@ class KMSVeChainSigner extends VeChainAbstractSigner { /** * It returns the address associated with the signer. - * @param {boolean} fromDelegator (Optional) If true, the provider will be the delegator. + * @param {boolean} fromDelegatorProvider (Optional) If true, the provider will be the delegator. * @returns The address associated with the signer. */ public async getAddress( - fromDelegator: boolean | undefined = false + fromDelegatorProvider: boolean | undefined = false ): Promise { try { - const kmsProvider = fromDelegator + const kmsProvider = fromDelegatorProvider ? this.kmsVeChainDelegatorProvider : this.kmsVeChainProvider; const publicKeyDecoded = @@ -151,7 +151,7 @@ class KMSVeChainSigner extends VeChainAbstractSigner { throw new SignerMethodError( 'KMSVeChainSigner.getAddress', 'The address could not be retrieved.', - { fromDelegator }, + { fromDelegatorProvider }, error ); }