From 327a153a721dc40b152057090f8cd0b0bfb3495b Mon Sep 17 00:00:00 2001 From: Reed Rosenbluth <331327+reedrosenbluth@users.noreply.github.com> Date: Thu, 12 Aug 2021 16:32:16 -0400 Subject: [PATCH] refactor!: change Authorization from a class to functional interface --- packages/transactions/src/authorization.ts | 268 ++++++++---------- packages/transactions/src/builders.ts | 16 +- packages/transactions/src/signer.ts | 4 +- packages/transactions/src/transaction.ts | 50 ++-- packages/transactions/tests/builder.test.ts | 12 +- .../transactions/tests/transaction.test.ts | 21 +- 6 files changed, 168 insertions(+), 203 deletions(-) diff --git a/packages/transactions/src/authorization.ts b/packages/transactions/src/authorization.ts index df0909b78..976711930 100644 --- a/packages/transactions/src/authorization.ts +++ b/packages/transactions/src/authorization.ts @@ -33,17 +33,7 @@ import { } from './keys'; import { BufferReader } from './bufferReader'; -import { DeserializationError, SerializationError, SigningError } from './errors'; - -abstract class Deserializable { - abstract serialize(): Buffer; - abstract deserialize(bufferReader: BufferReader): void; - static deserialize(this: new () => T, bufferReader: BufferReader): T { - const message = new this(); - message.deserialize(bufferReader); - return message; - } -} +import { DeserializationError, SigningError } from './errors'; export interface MessageSignature { readonly type: StacksMessageType.MessageSignature; @@ -503,177 +493,141 @@ function verifySingleSig( return nextSigHash; } -export class Authorization extends Deserializable { - authType?: AuthType; - spendingCondition?: SpendingCondition; - sponsorSpendingCondition?: SpendingCondition; - - constructor( - authType?: AuthType, - spendingConditions?: SpendingConditionOpts, - sponsorSpendingCondition?: SpendingConditionOpts - ) { - super(); - this.authType = authType; - if (spendingConditions) { - this.spendingCondition = { - ...spendingConditions, - nonce: intToBigInt(spendingConditions.nonce, false), - fee: intToBigInt(spendingConditions.fee, false), - }; - } - if (sponsorSpendingCondition) { - this.sponsorSpendingCondition = { - ...sponsorSpendingCondition, - nonce: intToBigInt(sponsorSpendingCondition.nonce, false), - fee: intToBigInt(sponsorSpendingCondition.fee, false), - }; - } - } +export type Authorization = StandardAuthorization | SponsoredAuthorization; - intoInitialSighashAuth(): Authorization { - if (this.spendingCondition) { - switch (this.authType) { - case AuthType.Standard: - return new Authorization(AuthType.Standard, clearCondition(this.spendingCondition)); - case AuthType.Sponsored: - return new Authorization( - AuthType.Sponsored, - clearCondition(this.spendingCondition), - newInitialSigHash() - ); - default: - throw new SigningError('Unexpected authorization type for signing'); - } - } +export interface StandardAuthorization { + authType: AuthType.Standard; + spendingCondition: SpendingCondition; +} - throw new Error('Authorization missing SpendingCondition'); - } +export interface SponsoredAuthorization { + authType: AuthType.Sponsored; + spendingCondition: SpendingCondition; + sponsorSpendingCondition: SpendingCondition; +} - setFee(amount: IntegerType) { - switch (this.authType) { - case AuthType.Standard: - this.spendingCondition!.fee = intToBigInt(amount, false); - break; - case AuthType.Sponsored: - this.sponsorSpendingCondition!.fee = intToBigInt(amount, false); - break; - } +export function createStandardAuth(spendingCondition: SpendingCondition): StandardAuthorization { + return { + authType: AuthType.Standard, + spendingCondition, + }; +} + +export function createSponsoredAuth( + spendingCondition: SpendingCondition, + sponsorSpendingCondition?: SpendingCondition +): Authorization { + if (!sponsorSpendingCondition) { + sponsorSpendingCondition = createSingleSigSpendingCondition( + AddressHashMode.SerializeP2PKH, + '0'.repeat(66), + 0, + 0 + ); } - getFee(): bigint { - switch (this.authType) { + return { + authType: AuthType.Sponsored, + spendingCondition, + sponsorSpendingCondition + }; +} + +export function intoInitialSighashAuth(auth: Authorization): Authorization { + if (auth.spendingCondition) { + switch (auth.authType) { case AuthType.Standard: - return this.spendingCondition!.fee; + return createStandardAuth(clearCondition(auth.spendingCondition)); case AuthType.Sponsored: - return this.sponsorSpendingCondition!.fee; + return createSponsoredAuth( + clearCondition(auth.spendingCondition), + newInitialSigHash() + ); default: - return BigInt(0); + throw new SigningError('Unexpected authorization type for signing'); } } - setNonce(nonce: IntegerType) { - this.spendingCondition!.nonce = intToBigInt(nonce, false); - } + throw new Error('Authorization missing SpendingCondition'); +} - setSponsorNonce(nonce: IntegerType) { - this.sponsorSpendingCondition!.nonce = intToBigInt(nonce, false); +export function verifyOrigin(auth: Authorization, initialSigHash: string): string { + switch (auth.authType) { + case AuthType.Standard: + return verify(auth.spendingCondition, initialSigHash, AuthType.Standard); + case AuthType.Sponsored: + return verify(auth.spendingCondition, initialSigHash, AuthType.Standard); + default: + throw new SigningError('Invalid origin auth type'); } +} - setSponsor(sponsorSpendingCondition: SpendingConditionOpts) { - this.sponsorSpendingCondition = { - ...sponsorSpendingCondition, - nonce: intToBigInt(sponsorSpendingCondition.nonce, false), - fee: intToBigInt(sponsorSpendingCondition.fee, false), - }; +export function setFee(auth: Authorization, amount: IntegerType) { + switch (auth.authType) { + case AuthType.Standard: + auth.spendingCondition.fee = intToBigInt(amount, false); + break; + case AuthType.Sponsored: + auth.sponsorSpendingCondition.fee = intToBigInt(amount, false); + break; } +} - verifyOrigin(initialSigHash: string): string { - switch (this.authType) { - case AuthType.Standard: - return verify(this.spendingCondition!, initialSigHash, AuthType.Standard); - case AuthType.Sponsored: - return verify(this.spendingCondition!, initialSigHash, AuthType.Standard); - default: - throw new SigningError('Invalid origin auth type'); - } +export function getFee(auth: Authorization): bigint { + switch (auth.authType) { + case AuthType.Standard: + return auth.spendingCondition.fee; + case AuthType.Sponsored: + return auth.sponsorSpendingCondition.fee; } +} - serialize(): Buffer { - const bufferArray: BufferArray = new BufferArray(); - if (this.authType === undefined) { - throw new SerializationError('"authType" is undefined'); - } - bufferArray.appendByte(this.authType); +export function setNonce(auth: Authorization, nonce: IntegerType) { + auth.spendingCondition.nonce = intToBigInt(nonce, false); +} - switch (this.authType) { - case AuthType.Standard: - if (this.spendingCondition === undefined) { - throw new SerializationError('"spendingCondition" is undefined'); - } - bufferArray.push(serializeSpendingCondition(this.spendingCondition)); - break; - case AuthType.Sponsored: - if (this.spendingCondition === undefined) { - throw new SerializationError('"spendingCondition" is undefined'); - } - if (this.sponsorSpendingCondition === undefined) { - throw new SerializationError('"spendingCondition" is undefined'); - } - bufferArray.push(serializeSpendingCondition(this.spendingCondition)); - bufferArray.push(serializeSpendingCondition(this.sponsorSpendingCondition)); - break; - default: - throw new SerializationError( - `Unexpected transaction AuthType while serializing: ${JSON.stringify(this.authType)}` - ); - } +export function setSponsorNonce(auth: SponsoredAuthorization, nonce: IntegerType) { + auth.sponsorSpendingCondition.nonce = intToBigInt(nonce, false); +} - return bufferArray.concatBuffer(); - } +export function setSponsor(auth: SponsoredAuthorization, sponsorSpendingCondition: SpendingConditionOpts) { + auth.sponsorSpendingCondition = { + ...sponsorSpendingCondition, + nonce: intToBigInt(sponsorSpendingCondition.nonce, false), + fee: intToBigInt(sponsorSpendingCondition.fee, false), + }; +} - deserialize(bufferReader: BufferReader) { - this.authType = bufferReader.readUInt8Enum(AuthType, n => { - throw new DeserializationError(`Could not parse ${n} as AuthType`); - }); +export function serializeAuthorization(auth: Authorization): Buffer { + const bufferArray: BufferArray = new BufferArray(); + bufferArray.appendByte(auth.authType); - switch (this.authType) { - case AuthType.Standard: - this.spendingCondition = deserializeSpendingCondition(bufferReader); - break; - case AuthType.Sponsored: - this.spendingCondition = deserializeSpendingCondition(bufferReader); - this.sponsorSpendingCondition = deserializeSpendingCondition(bufferReader); - break; - // throw new DeserializationError('Not yet implemented: deserializing sponsored transactions'); - default: - throw new DeserializationError( - `Unexpected transaction AuthType while deserializing: ${JSON.stringify(this.authType)}` - ); - } + switch (auth.authType) { + case AuthType.Standard: + bufferArray.push(serializeSpendingCondition(auth.spendingCondition)); + break; + case AuthType.Sponsored: + bufferArray.push(serializeSpendingCondition(auth.spendingCondition)); + bufferArray.push(serializeSpendingCondition(auth.sponsorSpendingCondition)); + break; } -} -export class StandardAuthorization extends Authorization { - constructor(spendingCondition: SpendingConditionOpts) { - super(AuthType.Standard, spendingCondition); - } + return bufferArray.concatBuffer(); } -export class SponsoredAuthorization extends Authorization { - constructor( - originSpendingCondition: SpendingConditionOpts, - sponsorSpendingCondition?: SpendingConditionOpts - ) { - let sponsorSC = sponsorSpendingCondition; - if (!sponsorSC) { - sponsorSC = createSingleSigSpendingCondition( - AddressHashMode.SerializeP2PKH, - '0'.repeat(66), - 0, - 0 - ); - } - super(AuthType.Sponsored, originSpendingCondition, sponsorSC); +export function deserializeAuthorization(bufferReader: BufferReader) { + let authType = bufferReader.readUInt8Enum(AuthType, n => { + throw new DeserializationError(`Could not parse ${n} as AuthType`); + }); + + let spendingCondition; + switch (authType) { + case AuthType.Standard: + spendingCondition = deserializeSpendingCondition(bufferReader); + return createStandardAuth(spendingCondition); + case AuthType.Sponsored: + spendingCondition = deserializeSpendingCondition(bufferReader); + const sponsorSpendingCondition = deserializeSpendingCondition(bufferReader); + return createSponsoredAuth(spendingCondition, sponsorSpendingCondition); } } diff --git a/packages/transactions/src/builders.ts b/packages/transactions/src/builders.ts index b4a54ca7e..0f09d242c 100644 --- a/packages/transactions/src/builders.ts +++ b/packages/transactions/src/builders.ts @@ -10,10 +10,10 @@ import { } from './payload'; import { - StandardAuthorization, - SponsoredAuthorization, createSingleSigSpendingCondition, createMultiSigSpendingCondition, + createSponsoredAuth, + createStandardAuth, } from './authorization'; import { @@ -517,9 +517,9 @@ export async function makeUnsignedSTXTokenTransfer( } if (options.sponsored) { - authorization = new SponsoredAuthorization(spendingCondition); + authorization = createSponsoredAuth(spendingCondition); } else { - authorization = new StandardAuthorization(spendingCondition); + authorization = createStandardAuth(spendingCondition); } const postConditions: PostCondition[] = []; @@ -717,9 +717,9 @@ export async function makeContractDeploy( ); if (options.sponsored) { - authorization = new SponsoredAuthorization(spendingCondition); + authorization = createSponsoredAuth(spendingCondition); } else { - authorization = new StandardAuthorization(spendingCondition); + authorization = createStandardAuth(spendingCondition); } const postConditions: PostCondition[] = []; @@ -930,9 +930,9 @@ export async function makeUnsignedContractCall( } if (options.sponsored) { - authorization = new SponsoredAuthorization(spendingCondition); + authorization = createSponsoredAuth(spendingCondition); } else { - authorization = new StandardAuthorization(spendingCondition); + authorization = createStandardAuth(spendingCondition); } const postConditions: PostCondition[] = []; diff --git a/packages/transactions/src/signer.ts b/packages/transactions/src/signer.ts index 514e5ce3b..a483436f3 100644 --- a/packages/transactions/src/signer.ts +++ b/packages/transactions/src/signer.ts @@ -119,8 +119,8 @@ export class TransactionSigner { if (this.transaction.auth === undefined) { throw new SigningError('"transaction.auth" is undefined'); } - if (this.transaction.auth.sponsorSpendingCondition === undefined) { - throw new SigningError('"transaction.auth.spendingCondition" is undefined'); + if (this.transaction.auth.authType !== AuthType.Sponsored) { + throw new SigningError('"transaction.auth.authType" is not AuthType.Sponsored'); } const nextSighash = this.transaction.signNextSponsor(this.sigHash, privateKey); diff --git a/packages/transactions/src/transaction.ts b/packages/transactions/src/transaction.ts index 4c2676a11..fa7b2a811 100644 --- a/packages/transactions/src/transaction.ts +++ b/packages/transactions/src/transaction.ts @@ -15,10 +15,18 @@ import { Authorization, createMessageSignature, createTransactionAuthField, + deserializeAuthorization, + intoInitialSighashAuth, isSingleSig, nextSignature, + serializeAuthorization, + setFee, + setNonce, + setSponsor, + setSponsorNonce, SingleSigSpendingCondition, SpendingConditionOpts, + verifyOrigin, } from './authorization'; import { BufferArray, cloneDeep, txidFromData } from './utils'; @@ -86,13 +94,13 @@ export class StacksTransaction { signBegin() { const tx = cloneDeep(this); - tx.auth = tx.auth.intoInitialSighashAuth(); + tx.auth = intoInitialSighashAuth(tx.auth); return tx.txid(); } verifyBegin() { const tx = cloneDeep(this); - tx.auth = tx.auth.intoInitialSighashAuth(); + tx.auth = intoInitialSighashAuth(tx.auth); return tx.txid(); } @@ -108,7 +116,7 @@ export class StacksTransaction { } verifyOrigin(): string { - return this.auth.verifyOrigin(this.verifyBegin()); + return verifyOrigin(this.auth, this.verifyBegin()); } signNextOrigin(sigHash: string, privateKey: StacksPrivateKey): string { @@ -122,18 +130,16 @@ export class StacksTransaction { } signNextSponsor(sigHash: string, privateKey: StacksPrivateKey): string { - if (this.auth.sponsorSpendingCondition === undefined) { - throw new Error('"auth.spendingCondition" is undefined'); - } - if (this.auth.authType === undefined) { - throw new Error('"auth.authType" is undefined'); + if (this.auth.authType === AuthType.Sponsored) { + return this.signAndAppend( + this.auth.sponsorSpendingCondition, + sigHash, + AuthType.Sponsored, + privateKey + ); + } else { + throw new Error('"auth.sponsorSpendingCondition" is undefined'); } - return this.signAndAppend( - this.auth.sponsorSpendingCondition, - sigHash, - AuthType.Sponsored, - privateKey - ); } appendPubkey(publicKey: StacksPublicKey) { @@ -189,7 +195,7 @@ export class StacksTransaction { throw new SigningError('Cannot sponsor sign a non-sponsored transaction'); } - this.auth.setSponsor(sponsorSpendingCondition); + setSponsor(this.auth, sponsorSpendingCondition); } /** @@ -198,7 +204,7 @@ export class StacksTransaction { * @param fee - the fee amount in microstacks */ setFee(amount: IntegerType) { - this.auth.setFee(amount); + setFee(this.auth, amount); } /** @@ -207,7 +213,7 @@ export class StacksTransaction { * @param nonce - the nonce value */ setNonce(nonce: IntegerType) { - this.auth.setNonce(nonce); + setNonce(this.auth, nonce); } /** @@ -216,7 +222,11 @@ export class StacksTransaction { * @param nonce - the sponsor nonce value */ setSponsorNonce(nonce: IntegerType) { - this.auth.setSponsorNonce(nonce); + if (this.auth.authType != AuthType.Sponsored) { + throw new SigningError('Cannot sponsor sign a non-sponsored transaction'); + } + + setSponsorNonce(this.auth, nonce); } serialize(): Buffer { @@ -242,7 +252,7 @@ export class StacksTransaction { const chainIdBuffer = Buffer.alloc(4); chainIdBuffer.writeUInt32BE(this.chainId, 0); bufferArray.push(chainIdBuffer); - bufferArray.push(this.auth.serialize()); + bufferArray.push(serializeAuthorization(this.auth)); bufferArray.appendByte(this.anchorMode); bufferArray.appendByte(this.postConditionMode); bufferArray.push(serializeLPList(this.postConditions)); @@ -272,7 +282,7 @@ export function deserializeTransaction(data: BufferReader | Buffer | string) { throw new Error(`Could not parse ${n} as TransactionVersion`); }); const chainId = bufferReader.readUInt32BE(); - const auth = Authorization.deserialize(bufferReader); + const auth = deserializeAuthorization(bufferReader); const anchorMode = bufferReader.readUInt8Enum(AnchorMode, n => { throw new Error(`Could not parse ${n} as AnchorMode`); }); diff --git a/packages/transactions/tests/builder.test.ts b/packages/transactions/tests/builder.test.ts index b34fe7093..82639f369 100644 --- a/packages/transactions/tests/builder.test.ts +++ b/packages/transactions/tests/builder.test.ts @@ -30,7 +30,7 @@ import { BufferReader } from '../src/bufferReader'; import { createAssetInfo } from '../src/types'; -import { createTransactionAuthField, MultiSigSpendingCondition, nextSignature, SingleSigSpendingCondition } from '../src/authorization'; +import { createTransactionAuthField, MultiSigSpendingCondition, nextSignature, SingleSigSpendingCondition, SponsoredAuthorization } from '../src/authorization'; import { DEFAULT_CORE_NODE_API_URL, @@ -867,7 +867,7 @@ test('Make sponsored STX token transfer', async () => { expect(deserializedSponsorTx.auth.spendingCondition!.nonce!.toString()).toBe(nonce.toString()); expect(deserializedSponsorTx.auth.spendingCondition!.fee!.toString()).toBe(fee.toString()); - const deserializedSponsorSpendingCondition = deserializedSponsorTx.auth.sponsorSpendingCondition!; + const deserializedSponsorSpendingCondition = (deserializedSponsorTx.auth as SponsoredAuthorization).sponsorSpendingCondition!; expect(deserializedSponsorSpendingCondition.hashMode).toBe(addressHashMode); expect(deserializedSponsorSpendingCondition.nonce!.toString()).toBe(sponsorNonce.toString()); expect(deserializedSponsorSpendingCondition.fee!.toString()).toBe(sponsorFee.toString()); @@ -929,7 +929,7 @@ test('Make sponsored STX token transfer with sponsor fee estimate', async () => expect(deserializedSponsorTx.auth.spendingCondition!.nonce!.toString()).toBe(nonce.toString()); expect(deserializedSponsorTx.auth.spendingCondition!.fee!.toString()).toBe(fee.toString()); - const deserializedSponsorSpendingCondition = deserializedSponsorTx.auth.sponsorSpendingCondition!; + const deserializedSponsorSpendingCondition = (deserializedSponsorTx.auth as SponsoredAuthorization).sponsorSpendingCondition!; expect(deserializedSponsorSpendingCondition.hashMode).toBe(addressHashMode); expect(deserializedSponsorSpendingCondition.nonce!.toString()).toBe(sponsorNonce.toString()); expect(deserializedSponsorSpendingCondition.fee!.toString()).toBe(sponsorFee.toString()); @@ -981,7 +981,7 @@ test('Make sponsored STX token transfer with set tx fee', async () => { expect(deserializedSponsorTx.auth.spendingCondition!.nonce!.toString()).toBe(nonce.toString()); expect(deserializedSponsorTx.auth.spendingCondition!.fee!.toString()).toBe(fee.toString()); - const deserializedSponsorSpendingCondition = deserializedSponsorTx.auth.sponsorSpendingCondition!; + const deserializedSponsorSpendingCondition = (deserializedSponsorTx.auth as SponsoredAuthorization).sponsorSpendingCondition!; expect(deserializedSponsorSpendingCondition.nonce!.toString()).toBe(sponsorNonce.toString()); expect(deserializedSponsorSpendingCondition.fee!.toString()).toBe(sponsorFee.toString()); @@ -1038,7 +1038,7 @@ test('Make sponsored contract deploy with sponsor fee estimate', async () => { expect(deserializedSponsorTx.auth.spendingCondition!.nonce!.toString()).toBe(nonce.toString()); expect(deserializedSponsorTx.auth.spendingCondition!.fee!.toString()).toBe(fee.toString()); - const deserializedSponsorSpendingCondition = deserializedSponsorTx.auth.sponsorSpendingCondition!; + const deserializedSponsorSpendingCondition = (deserializedSponsorTx.auth as SponsoredAuthorization).sponsorSpendingCondition!; expect(deserializedSponsorSpendingCondition.hashMode).toBe(addressHashMode); expect(deserializedSponsorSpendingCondition.nonce!.toString()).toBe(sponsorNonce.toString()); expect(deserializedSponsorSpendingCondition.fee!.toString()).toBe(sponsorFee.toString()); @@ -1099,7 +1099,7 @@ test('Make sponsored contract call with sponsor nonce fetch', async () => { expect(deserializedSponsorTx.auth.spendingCondition!.nonce!.toString()).toBe(nonce.toString()); expect(deserializedSponsorTx.auth.spendingCondition!.fee!.toString()).toBe(fee.toString()); - const deserializedSponsorSpendingCondition = deserializedSponsorTx.auth.sponsorSpendingCondition!; + const deserializedSponsorSpendingCondition = (deserializedSponsorTx.auth as SponsoredAuthorization).sponsorSpendingCondition!; expect(deserializedSponsorSpendingCondition.hashMode).toBe(addressHashMode); expect(deserializedSponsorSpendingCondition.nonce!.toString()).toBe(sponsorNonce.toString()); expect(deserializedSponsorSpendingCondition.fee!.toString()).toBe(sponsorFee.toString()); diff --git a/packages/transactions/tests/transaction.test.ts b/packages/transactions/tests/transaction.test.ts index 858a54ab1..45d6d7ff8 100644 --- a/packages/transactions/tests/transaction.test.ts +++ b/packages/transactions/tests/transaction.test.ts @@ -1,12 +1,13 @@ import { StacksTransaction, deserializeTransaction } from '../src/transaction'; import { - StandardAuthorization, createSingleSigSpendingCondition, SingleSigSpendingCondition, createMultiSigSpendingCondition, MultiSigSpendingCondition, - SponsoredAuthorization + SponsoredAuthorization, + createStandardAuth, + createSponsoredAuth } from '../src/authorization'; import { TokenTransferPayload, createTokenTransferPayload } from '../src/payload'; @@ -66,7 +67,7 @@ test('STX token transfer transaction serialization and deserialization', () => { const secretKey = 'edf9aee84d9b7abc145504dde6726c64f369d37ee34ded868fabd876c26570bc01'; const spendingCondition = createSingleSigSpendingCondition(addressHashMode, pubKey, nonce, fee); const authType = AuthType.Standard; - const authorization = new StandardAuthorization(spendingCondition); + const authorization = createStandardAuth(spendingCondition); const postCondition = createSTXPostCondition( recipient, @@ -141,7 +142,7 @@ test('STX token transfer transaction fee setting', () => { const secretKey = 'edf9aee84d9b7abc145504dde6726c64f369d37ee34ded868fabd876c26570bc01'; const spendingCondition = createSingleSigSpendingCondition(addressHashMode, pubKey, nonce, fee); const authType = AuthType.Standard; - const authorization = new StandardAuthorization(spendingCondition); + const authorization = createStandardAuth(spendingCondition); const postCondition = createSTXPostCondition( recipient, @@ -219,7 +220,7 @@ test('STX token transfer transaction multi-sig serialization and deserialization fee ); const authType = AuthType.Standard; - const originAuth = new StandardAuthorization(spendingCondition); + const originAuth = createStandardAuth(spendingCondition); const originAddress = originAuth.spendingCondition?.signer; @@ -287,7 +288,7 @@ test('STX token transfer transaction multi-sig uncompressed keys serialization a fee ); const authType = AuthType.Standard; - const originAuth = new StandardAuthorization(spendingCondition); + const originAuth = createStandardAuth(spendingCondition); const originAddress = originAuth.spendingCondition?.signer; @@ -379,7 +380,7 @@ test('Sponsored STX token transfer transaction serialization and deserialization ); const authType = AuthType.Sponsored; - const authorization = new SponsoredAuthorization(spendingCondition, sponsorSpendingCondition); + const authorization = createSponsoredAuth(spendingCondition, sponsorSpendingCondition); const transaction = new StacksTransaction(transactionVersion, authorization, payload); @@ -395,11 +396,11 @@ test('Sponsored STX token transfer transaction serialization and deserialization expect(deserialized.auth.spendingCondition!.hashMode).toBe(addressHashMode); expect(deserialized.auth.spendingCondition!.nonce!.toString()).toBe(nonce.toString()); expect(deserialized.auth.spendingCondition!.fee!.toString()).toBe(fee.toString()); - expect(deserialized.auth.sponsorSpendingCondition!.hashMode).toBe(addressHashMode); - expect(deserialized.auth.sponsorSpendingCondition!.nonce!.toString()).toBe( + expect((deserialized.auth as SponsoredAuthorization).sponsorSpendingCondition!.hashMode).toBe(addressHashMode); + expect((deserialized.auth as SponsoredAuthorization).sponsorSpendingCondition!.nonce!.toString()).toBe( sponsorNonce.toString() ); - expect(deserialized.auth.sponsorSpendingCondition!.fee!.toString()).toBe(fee.toString()); + expect((deserialized.auth as SponsoredAuthorization).sponsorSpendingCondition!.fee!.toString()).toBe(fee.toString()); expect(deserialized.anchorMode).toBe(anchorMode); expect(deserialized.postConditionMode).toBe(postConditionMode);