Skip to content

Commit

Permalink
feat: add new transaction of Mint type (#604)
Browse files Browse the repository at this point in the history
  • Loading branch information
LuizAsFight authored Nov 17, 2022
1 parent 6a59b72 commit 90dc675
Show file tree
Hide file tree
Showing 8 changed files with 187 additions and 34 deletions.
6 changes: 6 additions & 0 deletions .changeset/brave-actors-burn.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@fuel-ts/providers": patch
"@fuel-ts/transactions": patch
---

Add support for Mint transaction
15 changes: 9 additions & 6 deletions packages/contract/src/contracts/functions/invocation-results.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,17 +50,20 @@ export class InvocationResult<T = any> {
}
}

export class FunctionInvocationResult<T = any> extends InvocationResult<T> {
export class FunctionInvocationResult<
T = any,
TTransactionType = void
> extends InvocationResult<T> {
readonly transactionId: string;
readonly transactionResponse: TransactionResponse;
readonly transactionResult: TransactionResult<any>;
readonly transactionResult: TransactionResult<any, TTransactionType>;
readonly contract: Contract;
readonly logs!: Array<any>;

constructor(
funcScopes: InvocationScopeLike | Array<InvocationScopeLike>,
transactionResponse: TransactionResponse,
transactionResult: TransactionResult<any>,
transactionResult: TransactionResult<any, TTransactionType>,
contract: Contract,
isMultiCall: boolean
) {
Expand All @@ -72,14 +75,14 @@ export class FunctionInvocationResult<T = any> extends InvocationResult<T> {
this.logs = this.getDecodedLogs(transactionResult.receipts);
}

static async build<T>(
static async build<T, TTransactionType = void>(
funcScope: InvocationScopeLike | Array<InvocationScopeLike>,
transactionResponse: TransactionResponse,
isMultiCall: boolean,
contract: Contract
) {
const txResult = await transactionResponse.waitForResult();
const fnResult = new FunctionInvocationResult<T>(
const txResult = await transactionResponse.waitForResult<TTransactionType>();
const fnResult = new FunctionInvocationResult<T, TTransactionType>(
funcScope,
transactionResponse,
txResult,
Expand Down
9 changes: 7 additions & 2 deletions packages/fuel-gauge/src/contract.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import {
FunctionInvocationResult,
Wallet,
} from 'fuels';
import type { BN, TransactionRequestLike, TransactionResponse } from 'fuels';
import type { BN, TransactionRequestLike, TransactionResponse, TransactionType } from 'fuels';
import { join } from 'path';

import abiJSON from '../test-projects/call-test-contract/out/debug/call-test-abi.json';
Expand Down Expand Up @@ -644,7 +644,12 @@ describe('Contract', () => {
value: [resultA, resultB],
transactionResult,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
} = await FunctionInvocationResult.build<any>(invocationScopes, response, true, contract);
} = await FunctionInvocationResult.build<any, TransactionType.Script>(
invocationScopes,
response,
true,
contract
);

expect(transactionResult.transaction.witnesses.length).toEqual(1);
expect(transactionResult.transaction.witnesses[0].data).toEqual(signedTransaction);
Expand Down
9 changes: 7 additions & 2 deletions packages/providers/src/provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -538,12 +538,17 @@ export default class Provider {
/**
* Get transaction with the given ID
*/
async getTransaction(transactionId: string): Promise<Transaction | null> {
async getTransaction<TTransactionType = void>(
transactionId: string
): Promise<Transaction<TTransactionType> | null> {
const { transaction } = await this.operations.getTransaction({ transactionId });
if (!transaction) {
return null;
}
return new TransactionCoder().decode(arrayify(transaction.rawPayload), 0)?.[0];
return new TransactionCoder().decode(
arrayify(transaction.rawPayload),
0
)?.[0] as Transaction<TTransactionType>;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import type {
} from '@fuel-ts/interfaces';
import type { BigNumberish, BN } from '@fuel-ts/math';
import { bn } from '@fuel-ts/math';
import type { Transaction } from '@fuel-ts/transactions';
import type { TransactionCreate, TransactionScript } from '@fuel-ts/transactions';
import {
TransactionType,
TransactionCoder,
Expand Down Expand Up @@ -147,7 +147,7 @@ abstract class BaseTransactionRequest implements BaseTransactionRequestLike {
}

protected getBaseTransaction(): Pick<
Transaction,
TransactionScript | TransactionCreate,
keyof BaseTransactionRequestLike | 'inputsCount' | 'outputsCount' | 'witnessesCount'
> {
const inputs = this.inputs?.map(inputify) ?? [];
Expand All @@ -166,7 +166,7 @@ abstract class BaseTransactionRequest implements BaseTransactionRequestLike {
};
}

abstract toTransaction(): Transaction;
abstract toTransaction(): TransactionCreate | TransactionScript;

toTransactionBytes(): Uint8Array {
return new TransactionCoder().encode(this.toTransaction());
Expand Down Expand Up @@ -471,7 +471,7 @@ export class ScriptTransactionRequest extends BaseTransactionRequest {
this.scriptData = arraifyFromUint8Array(scriptData ?? returnZeroScript.encodeScriptData());
}

toTransaction(): Transaction {
toTransaction(): TransactionScript {
const script = arrayify(this.script ?? '0x');
const scriptData = arrayify(this.scriptData ?? '0x');
return {
Expand Down Expand Up @@ -599,7 +599,7 @@ export class CreateTransactionRequest extends BaseTransactionRequest {
this.storageSlots = [...(storageSlots ?? [])];
}

toTransaction(): Transaction {
toTransaction(): TransactionCreate {
const baseTransaction = this.getBaseTransaction();
const bytecodeWitnessIndex = this.bytecodeWitnessIndex;
const storageSlots = this.storageSlots?.map(storageSlotify) ?? [];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ export type TransactionResultReceipt =
| TransactionResultScriptResultReceipt
| TransactionResultMessageOutReceipt;

export type TransactionResult<TStatus extends 'success' | 'failure'> = {
export type TransactionResult<TStatus extends 'success' | 'failure', TTransactionType = void> = {
status: TStatus extends 'success'
? { type: 'success'; programState: any }
: { type: 'failure'; reason: any };
Expand All @@ -62,7 +62,7 @@ export type TransactionResult<TStatus extends 'success' | 'failure'> = {
time: any;
gasUsed: BN;
fee: BN;
transaction: Transaction;
transaction: Transaction<TTransactionType>;
};

const STATUS_POLLING_INTERVAL_MAX_MS = 5000;
Expand Down Expand Up @@ -115,13 +115,15 @@ export class TransactionResponse {
}

/** Waits for transaction to succeed or fail and returns the result */
async waitForResult(): Promise<TransactionResult<any>> {
async waitForResult<TTransactionType = void>(): Promise<
TransactionResult<any, TTransactionType>
> {
const transaction = await this.#fetch();

const decodedTransaction = new TransactionCoder().decode(
arrayify(transaction.rawPayload),
0
)?.[0];
)?.[0] as Transaction<TTransactionType>;

switch (transaction.status?.type) {
case 'SubmittedStatus': {
Expand Down Expand Up @@ -157,7 +159,7 @@ export class TransactionResponse {
};
}
case 'SuccessStatus': {
const receipts = transaction.receipts!.map(processGqlReceipt);
const receipts = transaction.receipts?.map(processGqlReceipt) || [];
const { gasUsed, fee } = calculateTransactionFee({
receipts,
gasPrice: bn(transaction?.gasPrice),
Expand All @@ -181,8 +183,8 @@ export class TransactionResponse {
}

/** Waits for transaction to succeed and returns the result */
async wait(): Promise<TransactionResult<'success'>> {
const result = await this.waitForResult();
async wait<TTransactionType = void>(): Promise<TransactionResult<'success', TTransactionType>> {
const result = await this.waitForResult<TTransactionType>();

if (result.status.type === 'failure') {
throw new Error(`Transaction failed: ${result.status.reason}`);
Expand Down
77 changes: 69 additions & 8 deletions packages/transactions/src/coders/transaction.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ const U16 = 32;
const U8 = 1;

describe('TransactionCoder', () => {
it('Can encode TransactionScript without inputs, outputs and witnesses', () => {
const transaction: Transaction = {
it('Can encode/decode TransactionScript without inputs, outputs and witnesses', () => {
const transaction: Transaction<TransactionType.Script> = {
type: TransactionType.Script,
gasPrice: bn(U32),
gasLimit: bn(U32),
Expand Down Expand Up @@ -43,8 +43,8 @@ describe('TransactionCoder', () => {
expect(JSON.stringify(decoded)).toEqual(JSON.stringify(transaction));
});

it('Can encode TransactionScript with inputs, outputs and witnesses', () => {
const transaction: Transaction = {
it('Can encode/decode TransactionScript with inputs, outputs and witnesses', () => {
const transaction: Transaction<TransactionType.Script> = {
type: TransactionType.Script,
gasPrice: bn(U32),
gasLimit: bn(U32),
Expand Down Expand Up @@ -113,8 +113,8 @@ describe('TransactionCoder', () => {
);
});

it('Can encode TransactionCreate without inputs, outputs and witnesses', () => {
const transaction: Transaction = {
it('Can encode/decode TransactionCreate without inputs, outputs and witnesses', () => {
const transaction: Transaction<TransactionType.Create> = {
type: TransactionType.Create,
gasPrice: bn(U32),
gasLimit: bn(U32),
Expand Down Expand Up @@ -144,8 +144,8 @@ describe('TransactionCoder', () => {
expect(JSON.stringify(decoded)).toEqual(JSON.stringify(transaction));
});

it('Can encode TransactionCreate with inputs, outputs and witnesses', () => {
const transaction: Transaction = {
it('Can encode/decode TransactionCreate with inputs, outputs and witnesses', () => {
const transaction: Transaction<TransactionType.Create> = {
type: TransactionType.Create,
gasPrice: bn(U32),
gasLimit: bn(U32),
Expand Down Expand Up @@ -234,4 +234,65 @@ describe('TransactionCoder', () => {
JSON.parse(JSON.stringify(transaction))
);
});

it('Can encode/decode TransactionMint with outputs', () => {
const transaction: Transaction<TransactionType.Mint> = {
type: TransactionType.Mint,
outputsCount: 2,
outputs: [
{
type: OutputType.Coin,
to: B256,
amount: bn(1),
assetId: B256,
},
{
type: OutputType.Coin,
to: B256,
amount: bn(1),
assetId: B256,
},
],
txPointer: {
blockHeight: 0,
txIndex: 0,
},
};

const encoded = hexlify(new TransactionCoder().encode(transaction));

expect(encoded).toEqual(
'0x000000000000000200000000000000020000000000000000d5579c46dfcc7f18207013e65b44e4cb4e2c2298f4ac457ba8f82743f31e930b0000000000000001d5579c46dfcc7f18207013e65b44e4cb4e2c2298f4ac457ba8f82743f31e930b0000000000000000d5579c46dfcc7f18207013e65b44e4cb4e2c2298f4ac457ba8f82743f31e930b0000000000000001d5579c46dfcc7f18207013e65b44e4cb4e2c2298f4ac457ba8f82743f31e930b00000000000000000000000000000000'
);

const [decoded, offset] = new TransactionCoder().decode(arrayify(encoded), 0);

expect(offset).toEqual((encoded.length - 2) / 2);
expect(JSON.parse(JSON.stringify(decoded))).toMatchObject(
JSON.parse(JSON.stringify(transaction))
);
});

it('Can encode/decode TransactionMint without outputs', () => {
const transaction: Transaction<TransactionType.Mint> = {
type: TransactionType.Mint,
outputsCount: 0,
outputs: [],
txPointer: {
blockHeight: 0,
txIndex: 0,
},
};

const encoded = hexlify(new TransactionCoder().encode(transaction));

expect(encoded).toEqual('0x0000000000000002000000000000000000000000000000000000000000000000');

const [decoded, offset] = new TransactionCoder().decode(arrayify(encoded), 0);

expect(offset).toEqual((encoded.length - 2) / 2);
expect(JSON.parse(JSON.stringify(decoded))).toMatchObject(
JSON.parse(JSON.stringify(transaction))
);
});
});
Loading

0 comments on commit 90dc675

Please sign in to comment.