Skip to content
Merged
Show file tree
Hide file tree
Changes from 17 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
828150c
test: shared sendTransaction tests for both facades
tuliomir Mar 31, 2026
ca9c346
Merge remote-tracking branch 'origin/master' into test/shared-send-tr…
tuliomir Apr 1, 2026
e2624ee
fix(test): resolve integration test failures
tuliomir Apr 1, 2026
6240d5a
fix: null guard
tuliomir Apr 1, 2026
9acf2d4
fix(test): ensure walletTxs cleanup and assertions
tuliomir Apr 1, 2026
fc3fb68
Merge branch 'master' into test/shared-send-transaction
tuliomir Apr 1, 2026
baf474f
fix(test): address PR review comments for send-transaction tests
tuliomir Apr 1, 2026
59ab89a
refact(test): move service-specific sendTransaction tests to shared
tuliomir Apr 2, 2026
629eed7
chore: remove unused imports in hathorwallet_facade test
tuliomir Apr 2, 2026
89ccc84
test: migrate token send tests to shared suite
tuliomir Apr 2, 2026
2f7804f
test: migrate address tracking test to shared suite
tuliomir Apr 2, 2026
9490cee
fix: address review comments and itest failures
tuliomir Apr 2, 2026
43059a9
test: add fee token edge case tests
tuliomir Apr 2, 2026
ef3e2b1
fix: native token version defaulting to deposit (#1054)
raul-oliveira Apr 2, 2026
a8ad5f7
fix: isolates change address test
tuliomir Apr 3, 2026
c1bcc92
chore: workaround for input bug
tuliomir Apr 6, 2026
3e77f0f
Merge branch 'master' into test/shared-send-transaction
tuliomir Apr 6, 2026
4c027f2
fix: address PR review on fee validation
tuliomir Apr 8, 2026
dc321ca
Merge remote-tracking branch 'origin/master' into test/shared-send-tr…
tuliomir Apr 8, 2026
5b978aa
fix: linter
tuliomir Apr 8, 2026
b81a2d0
docs: improves comment messages
tuliomir Apr 9, 2026
18bc8e9
Merge remote-tracking branch 'origin/master'
tuliomir Apr 17, 2026
fdef446
feat(test): add recvWallet option to adapters
tuliomir Apr 22, 2026
10e61f1
test: address Carneiro's review on PR 1053
tuliomir Apr 22, 2026
d200936
refactor(test): migrate remaining sendTransaction
tuliomir Apr 22, 2026
a3147fd
Merge branch 'master' into test/shared-send-transaction
tuliomir Apr 22, 2026
4a58909
refact(test): move recvWallet to waitForTx helper
tuliomir Apr 22, 2026
b556e5c
fix(test): restore dropped coverage from migration
tuliomir Apr 22, 2026
87ff71d
fix(test): fix integration test failures
tuliomir Apr 23, 2026
eef4dad
refact(test): rename TTS to DBT for clarity
tuliomir Apr 23, 2026
9619ae2
Merge remote-tracking branch 'origin/master' into test/shared-send-tr…
tuliomir Apr 23, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 84 additions & 0 deletions __tests__/integration/adapters/fullnode.adapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,21 @@ import { GenesisWalletHelper } from '../helpers/genesis-wallet.helper';
import { precalculationHelpers } from '../helpers/wallet-precalculation.helper';
import type { WalletStopOptions } from '../../../src/new/types';
import { FULLNODE_URL, NETWORK_NAME } from '../configuration/test-constants';
import type { FullNodeTxResponse } from '../../../src/wallet/types';
import type {
FuzzyWalletType,
IWalletTestAdapter,
WalletCapabilities,
CreateWalletOptions,
CreateWalletResult,
SendTransactionOptions,
SendTransactionResult,
CreateTokenAdapterOptions,
CreateTokenResult,
GetUtxosAdapterOptions,
GetUtxosResult,
AdapterOutput,
SendManyOutputsAdapterOptions,
} from './types';
import type { PrecalculatedWalletData } from '../helpers/wallet-precalculation.helper';

Expand Down Expand Up @@ -184,6 +193,81 @@ export class FullnodeWalletTestAdapter implements IWalletTestAdapter {
return precalculationHelpers.test!.getPrecalculatedWallet();
}

async sendTransaction(
Comment thread
r4mmer marked this conversation as resolved.
wallet: FuzzyWalletType,
address: string,
amount: bigint,
options?: SendTransactionOptions
): Promise<SendTransactionResult> {
const hWallet = this.concrete(wallet);
const result = await hWallet.sendTransaction(address, amount, {
pinCode: DEFAULT_PIN_CODE,
...options,
});
if (!result || !result.hash) {
throw new Error('sendTransaction: transaction had no hash');
}
await waitForTxReceived(hWallet, result.hash);
await waitUntilNextTimestamp(hWallet, result.hash);
return { hash: result.hash, transaction: result };
}

async getFullTxById(wallet: FuzzyWalletType, txId: string): Promise<FullNodeTxResponse> {
// The fullnode facade returns FullNodeTxApiResponse (zod-inferred), which is structurally
// compatible with FullNodeTxResponse but has minor nullability differences.
return this.concrete(wallet).getFullTxById(txId) as Promise<FullNodeTxResponse>;
}

async createToken(
wallet: FuzzyWalletType,
name: string,
symbol: string,
amount: bigint,
options?: CreateTokenAdapterOptions
): Promise<CreateTokenResult> {
const hWallet = this.concrete(wallet);
const result = await hWallet.createNewToken(name, symbol, amount, {
pinCode: DEFAULT_PIN_CODE,
...options,
});
if (!result?.hash) {
throw new Error('createToken: transaction had no hash');
}
await waitForTxReceived(hWallet, result.hash);
await waitUntilNextTimestamp(hWallet, result.hash);
return { hash: result.hash, transaction: result };
}

async getUtxos(
wallet: FuzzyWalletType,
options?: GetUtxosAdapterOptions
): Promise<GetUtxosResult> {
const result = await this.concrete(wallet).getUtxos(options);
return {
total_amount_available: result.total_amount_available,
total_utxos_available: result.total_utxos_available,
utxos: result.utxos,
};
}

async sendManyOutputsTransaction(
wallet: FuzzyWalletType,
outputs: AdapterOutput[],
options?: SendManyOutputsAdapterOptions
): Promise<SendTransactionResult> {
const hWallet = this.concrete(wallet);
const result = await hWallet.sendManyOutputsTransaction(outputs, {
pinCode: DEFAULT_PIN_CODE,
...options,
});
if (!result?.hash) {
throw new Error('sendManyOutputsTransaction: transaction had no hash');
}
await waitForTxReceived(hWallet, result.hash);
await waitUntilNextTimestamp(hWallet, result.hash);
return { hash: result.hash, transaction: result };
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.

// --- Private helpers ---

/**
Expand Down
79 changes: 79 additions & 0 deletions __tests__/integration/adapters/service.adapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,21 @@ import { GenesisWalletServiceHelper } from '../helpers/genesis-wallet.helper';
import { precalculationHelpers } from '../helpers/wallet-precalculation.helper';
import type { WalletStopOptions } from '../../../src/new/types';
import { NETWORK_NAME } from '../configuration/test-constants';
import type { FullNodeTxResponse } from '../../../src/wallet/types';
import type {
FuzzyWalletType,
IWalletTestAdapter,
WalletCapabilities,
CreateWalletOptions,
CreateWalletResult,
SendTransactionOptions,
SendTransactionResult,
CreateTokenAdapterOptions,
CreateTokenResult,
GetUtxosAdapterOptions,
GetUtxosResult,
AdapterOutput,
SendManyOutputsAdapterOptions,
} from './types';
import type { PrecalculatedWalletData } from '../helpers/wallet-precalculation.helper';

Expand Down Expand Up @@ -213,4 +222,74 @@ export class ServiceWalletTestAdapter implements IWalletTestAdapter {
getPrecalculatedWallet(): PrecalculatedWalletData {
return precalculationHelpers.test!.getPrecalculatedWallet();
}

async sendTransaction(
wallet: FuzzyWalletType,
address: string,
amount: bigint,
options?: SendTransactionOptions
): Promise<SendTransactionResult> {
const sw = this.concrete(wallet);
const result = await sw.sendTransaction(address, amount, {
pinCode: SERVICE_PIN,
...options,
});
if (!result.hash) {
throw new Error('sendTransaction: transaction had no hash');
}
await pollForTx(sw, result.hash);
return { hash: result.hash, transaction: result };
}

async getFullTxById(wallet: FuzzyWalletType, txId: string): Promise<FullNodeTxResponse> {
return this.concrete(wallet).getFullTxById(txId);
}

async createToken(
wallet: FuzzyWalletType,
name: string,
symbol: string,
amount: bigint,
options?: CreateTokenAdapterOptions
): Promise<CreateTokenResult> {
const sw = this.concrete(wallet);
const result = await sw.createNewToken(name, symbol, amount, {
pinCode: SERVICE_PIN,
...options,
});
if (!result?.hash) {
throw new Error('createToken: transaction had no hash');
}
await pollForTx(sw, result.hash);
return { hash: result.hash, transaction: result };
}

async getUtxos(
wallet: FuzzyWalletType,
options?: GetUtxosAdapterOptions
): Promise<GetUtxosResult> {
const result = await this.concrete(wallet).getUtxos(options);
return {
total_amount_available: result.total_amount_available,
total_utxos_available: result.total_utxos_available,
utxos: result.utxos,
};
}

async sendManyOutputsTransaction(
wallet: FuzzyWalletType,
outputs: AdapterOutput[],
options?: SendManyOutputsAdapterOptions
): Promise<SendTransactionResult> {
const sw = this.concrete(wallet);
const result = await sw.sendManyOutputsTransaction(outputs, {
pinCode: SERVICE_PIN,
...options,
});
if (!result?.hash) {
throw new Error('sendManyOutputsTransaction: transaction had no hash');
}
await pollForTx(sw, result.hash);
return { hash: result.hash, transaction: result };
}
}
150 changes: 148 additions & 2 deletions __tests__/integration/adapters/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@
* LICENSE file in the root directory of this source tree.
*/

import type { IHathorWallet } from '../../../src/wallet/types';
import type { IHathorWallet, FullNodeTxResponse } from '../../../src/wallet/types';
import type { PrecalculatedWalletData } from '../helpers/wallet-precalculation.helper';
import type Transaction from '../../../src/models/transaction';
import type { IStorage } from '../../../src/types';
import type { IStorage, TokenVersion } from '../../../src/types';
import { HathorWallet, HathorWalletServiceWallet } from '../../../src';

/**
Expand Down Expand Up @@ -175,4 +175,150 @@ export interface IWalletTestAdapter {

/** Returns a fresh precalculated wallet for tests that need one */
getPrecalculatedWallet(): PrecalculatedWalletData;

// --- Transaction operations ---

/**
* Sends a transaction from the wallet to the given address.
* Handles pinCode injection for facades that require per-call credentials.
* Returns the hash and the full Transaction model.
*/
sendTransaction(
wallet: FuzzyWalletType,
address: string,
amount: bigint,
options?: SendTransactionOptions
): Promise<SendTransactionResult>;

/**
* Retrieves the full transaction data from the network node.
* Both facades support this via the fullnode API.
*/
getFullTxById(wallet: FuzzyWalletType, txId: string): Promise<FullNodeTxResponse>;

// --- Token creation ---

/**
* Creates a new custom token and waits for it to be processed.
* Both facades support token creation via `createNewToken()`.
*/
createToken(
wallet: FuzzyWalletType,
name: string,
symbol: string,
amount: bigint,
options?: CreateTokenAdapterOptions
): Promise<CreateTokenResult>;

// --- UTXO queries ---

/**
* Retrieves unspent transaction outputs for a wallet.
* Both facades support `getUtxos()`.
*/
getUtxos(wallet: FuzzyWalletType, options?: GetUtxosAdapterOptions): Promise<GetUtxosResult>;

// --- Multi-output transactions ---

/**
* Sends a transaction with multiple outputs and optional explicit inputs.
* Both facades support `sendManyOutputsTransaction()`.
*/
sendManyOutputsTransaction(
wallet: FuzzyWalletType,
outputs: AdapterOutput[],
options?: SendManyOutputsAdapterOptions
): Promise<SendTransactionResult>;
}

/**
* Options for sending a transaction via the adapter.
*/
export interface SendTransactionOptions {
token?: string;
changeAddress?: string;
}

/**
* Result of sending a transaction.
*/
export interface SendTransactionResult {
hash: string;
transaction: Transaction;
}

/**
* Options for creating a token via the adapter.
*/
export interface CreateTokenAdapterOptions {
tokenVersion?: TokenVersion;
address?: string;
changeAddress?: string;
createMint?: boolean;
createMelt?: boolean;
}

/**
* Result of creating a token.
*/
export interface CreateTokenResult {
hash: string;
transaction: Transaction;
}

/**
* Options for querying UTXOs via the adapter.
*/
export interface GetUtxosAdapterOptions {
token?: string;
max_utxos?: number;
filter_address?: string;
amount_smaller_than?: bigint;
amount_bigger_than?: bigint;
}

/**
* A single UTXO entry returned by the adapter.
*/
export interface AdapterUtxo {
address: string;
amount: bigint;
tx_id: string;
locked: boolean;
index: number;
}

/**
* Result of a getUtxos query.
*/
export interface GetUtxosResult {
total_amount_available: bigint;
total_utxos_available: bigint;
utxos: AdapterUtxo[];
}

/**
* An output for sendManyOutputsTransaction.
*/
export interface AdapterOutput {
address: string;
value: bigint;
token: string;
}

/**
* An explicit input for sendManyOutputsTransaction.
*/
export interface AdapterInput {
txId: string;
index: number;
token?: string;
}

/**
* Options for sendManyOutputsTransaction via the adapter.
*/
export interface SendManyOutputsAdapterOptions {
inputs?: AdapterInput[];
changeAddress?: string;
}
Loading
Loading