feat: add getParsedConfirmedTransaction API
This commit is contained in:
committed by
Justin Starry
parent
5a63c9d535
commit
b36e60738e
36
web3.js/module.d.ts
vendored
36
web3.js/module.d.ts
vendored
@ -148,6 +148,39 @@ declare module '@solana/web3.js' {
|
|||||||
meta: ConfirmedTransactionMeta | null;
|
meta: ConfirmedTransactionMeta | null;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type ParsedMessageAccount = {
|
||||||
|
pubkey: PublicKey;
|
||||||
|
signer: boolean;
|
||||||
|
writable: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type ParsedInstruction = {
|
||||||
|
programId: PublicKey;
|
||||||
|
program: string;
|
||||||
|
parsed: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type PartiallyDecodedInstruction = {
|
||||||
|
programId: PublicKey;
|
||||||
|
accounts: Array<PublicKey>;
|
||||||
|
data: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type ParsedTransaction = {
|
||||||
|
signatures: Array<string>;
|
||||||
|
message: {
|
||||||
|
accountKeys: ParsedMessageAccount[];
|
||||||
|
instructions: (ParsedInstruction | PartiallyDecodedInstruction)[];
|
||||||
|
recentBlockhash: string;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export type ParsedConfirmedTransaction = {
|
||||||
|
slot: number;
|
||||||
|
transaction: ParsedTransaction;
|
||||||
|
meta: ConfirmedTransactionMeta | null;
|
||||||
|
};
|
||||||
|
|
||||||
export type KeyedAccountInfo = {
|
export type KeyedAccountInfo = {
|
||||||
accountId: PublicKey;
|
accountId: PublicKey;
|
||||||
accountInfo: AccountInfo;
|
accountInfo: AccountInfo;
|
||||||
@ -288,6 +321,9 @@ declare module '@solana/web3.js' {
|
|||||||
getConfirmedTransaction(
|
getConfirmedTransaction(
|
||||||
signature: TransactionSignature,
|
signature: TransactionSignature,
|
||||||
): Promise<ConfirmedTransaction | null>;
|
): Promise<ConfirmedTransaction | null>;
|
||||||
|
getParsedConfirmedTransaction(
|
||||||
|
signature: TransactionSignature,
|
||||||
|
): Promise<ParsedConfirmedTransaction | null>;
|
||||||
getConfirmedSignaturesForAddress(
|
getConfirmedSignaturesForAddress(
|
||||||
address: PublicKey,
|
address: PublicKey,
|
||||||
startSlot: number,
|
startSlot: number,
|
||||||
|
@ -169,6 +169,39 @@ declare module '@solana/web3.js' {
|
|||||||
meta: ConfirmedTransactionMeta | null,
|
meta: ConfirmedTransactionMeta | null,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
declare export type ParsedMessageAccount = {
|
||||||
|
pubkey: PublicKey,
|
||||||
|
signer: boolean,
|
||||||
|
writable: boolean,
|
||||||
|
};
|
||||||
|
|
||||||
|
declare export type ParsedInstruction = {|
|
||||||
|
programId: PublicKey,
|
||||||
|
program: string,
|
||||||
|
parsed: string,
|
||||||
|
|};
|
||||||
|
|
||||||
|
declare export type PartiallyDecodedInstruction = {|
|
||||||
|
programId: PublicKey,
|
||||||
|
accounts: Array<PublicKey>,
|
||||||
|
data: string,
|
||||||
|
|};
|
||||||
|
|
||||||
|
declare export type ParsedTransaction = {
|
||||||
|
signatures: Array<string>,
|
||||||
|
message: {
|
||||||
|
accountKeys: ParsedMessageAccount[],
|
||||||
|
instructions: (ParsedInstruction | PartiallyDecodedInstruction)[],
|
||||||
|
recentBlockhash: string,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
declare export type ParsedConfirmedTransaction = {
|
||||||
|
slot: number,
|
||||||
|
transaction: ParsedTransaction,
|
||||||
|
meta: ConfirmedTransactionMeta | null,
|
||||||
|
};
|
||||||
|
|
||||||
declare export type KeyedAccountInfo = {
|
declare export type KeyedAccountInfo = {
|
||||||
accountId: PublicKey,
|
accountId: PublicKey,
|
||||||
accountInfo: AccountInfo,
|
accountInfo: AccountInfo,
|
||||||
@ -309,6 +342,9 @@ declare module '@solana/web3.js' {
|
|||||||
getConfirmedTransaction(
|
getConfirmedTransaction(
|
||||||
signature: TransactionSignature,
|
signature: TransactionSignature,
|
||||||
): Promise<ConfirmedTransaction | null>;
|
): Promise<ConfirmedTransaction | null>;
|
||||||
|
getParsedConfirmedTransaction(
|
||||||
|
signature: TransactionSignature,
|
||||||
|
): Promise<ParsedConfirmedTransaction | null>;
|
||||||
getConfirmedSignaturesForAddress(
|
getConfirmedSignaturesForAddress(
|
||||||
address: PublicKey,
|
address: PublicKey,
|
||||||
startSlot: number,
|
startSlot: number,
|
||||||
|
37
web3.js/package-lock.json
generated
37
web3.js/package-lock.json
generated
@ -4743,24 +4743,23 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@solana/spl-token": {
|
"@solana/spl-token": {
|
||||||
"version": "0.0.4",
|
"version": "0.0.5",
|
||||||
"resolved": "https://registry.npmjs.org/@solana/spl-token/-/spl-token-0.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/@solana/spl-token/-/spl-token-0.0.5.tgz",
|
||||||
"integrity": "sha512-zYoZ6iYMKxGYbouunEkWdf6vWRJyEPOkAjvlNVjww9oPKMkIeM9VzgGtjZ/kKMelao1QEohH4JN9qXO4+LwfRA==",
|
"integrity": "sha512-OXW/zHzMQqVGcSNrNt8sRaHlKT5vjdcUcmUHi8d4ssG8ChbZVA2lkJK10XDXlcnMIiSTindpEjiFmooYc9K3uQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"@babel/runtime": "^7.10.5",
|
"@babel/runtime": "^7.10.5",
|
||||||
"@solana/web3.js": "^0.63.2",
|
"@solana/web3.js": "^0.64.0",
|
||||||
"bn.js": "^5.0.0",
|
"bn.js": "^5.0.0",
|
||||||
"buffer-layout": "^1.2.0",
|
"buffer-layout": "^1.2.0",
|
||||||
"dotenv": "8.2.0",
|
"dotenv": "8.2.0",
|
||||||
"json-to-pretty-yaml": "^1.2.2",
|
|
||||||
"mkdirp-promise": "^5.0.1"
|
"mkdirp-promise": "^5.0.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@solana/web3.js": {
|
"@solana/web3.js": {
|
||||||
"version": "0.63.2",
|
"version": "0.64.2",
|
||||||
"resolved": "https://registry.npmjs.org/@solana/web3.js/-/web3.js-0.63.2.tgz",
|
"resolved": "https://registry.npmjs.org/@solana/web3.js/-/web3.js-0.64.2.tgz",
|
||||||
"integrity": "sha512-4jd8U1U/eFTEemr+jCzQCDepKnkttV4dxWsjMloifb82x1d6KgCzP+Jd6D9kr8f1MFj2i/AnG++97tlHAGTOkA==",
|
"integrity": "sha512-aGRG1rn8fLerE4NscRL6rq0nSyYAK9K+TGRZxb6ue7Ontufa6wO1kxum4zJs17+xT0zVf8wABUtCMgP4W7FxpA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"@babel/runtime": "^7.3.1",
|
"@babel/runtime": "^7.3.1",
|
||||||
@ -14214,16 +14213,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
|
||||||
"integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus="
|
"integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus="
|
||||||
},
|
},
|
||||||
"json-to-pretty-yaml": {
|
|
||||||
"version": "1.2.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/json-to-pretty-yaml/-/json-to-pretty-yaml-1.2.2.tgz",
|
|
||||||
"integrity": "sha1-9M0L0KXo/h3yWq9boRiwmf2ZLVs=",
|
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
|
||||||
"remedial": "^1.0.7",
|
|
||||||
"remove-trailing-spaces": "^1.0.6"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"json5": {
|
"json5": {
|
||||||
"version": "0.5.1",
|
"version": "0.5.1",
|
||||||
"resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz",
|
"resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz",
|
||||||
@ -20159,24 +20148,12 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"remedial": {
|
|
||||||
"version": "1.0.8",
|
|
||||||
"resolved": "https://registry.npmjs.org/remedial/-/remedial-1.0.8.tgz",
|
|
||||||
"integrity": "sha512-/62tYiOe6DzS5BqVsNpH/nkGlX45C/Sp6V+NtiN6JQNS1Viay7cWkazmRkrQrdFj2eshDe96SIQNIoMxqhzBOg==",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"remove-trailing-separator": {
|
"remove-trailing-separator": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz",
|
||||||
"integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=",
|
"integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"remove-trailing-spaces": {
|
|
||||||
"version": "1.0.7",
|
|
||||||
"resolved": "https://registry.npmjs.org/remove-trailing-spaces/-/remove-trailing-spaces-1.0.7.tgz",
|
|
||||||
"integrity": "sha512-wjM17CJ2kk0SgoGyJ7ZMzRRCuTq+V8YhMwpZ5XEWX0uaked2OUq6utvHXGNBQrfkUzUUABFMyxlKn+85hMv4dg==",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"repeat-element": {
|
"repeat-element": {
|
||||||
"version": "1.1.3",
|
"version": "1.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz",
|
||||||
|
@ -97,7 +97,7 @@
|
|||||||
"@babel/preset-flow": "^7.0.0",
|
"@babel/preset-flow": "^7.0.0",
|
||||||
"@commitlint/config-conventional": "^9.0.1",
|
"@commitlint/config-conventional": "^9.0.1",
|
||||||
"@commitlint/travis-cli": "^9.0.1",
|
"@commitlint/travis-cli": "^9.0.1",
|
||||||
"@solana/spl-token": "^0.0.4",
|
"@solana/spl-token": "^0.0.5",
|
||||||
"@typescript-eslint/eslint-plugin": "^2.18.0",
|
"@typescript-eslint/eslint-plugin": "^2.18.0",
|
||||||
"@typescript-eslint/parser": "^2.18.0",
|
"@typescript-eslint/parser": "^2.18.0",
|
||||||
"acorn": "^7.0.0",
|
"acorn": "^7.0.0",
|
||||||
|
@ -49,7 +49,7 @@ type Context = {
|
|||||||
* @property {boolean | undefined} skipPreflight disable transaction verification step
|
* @property {boolean | undefined} skipPreflight disable transaction verification step
|
||||||
*/
|
*/
|
||||||
export type SendOptions = {
|
export type SendOptions = {
|
||||||
skipPreflight: ?boolean,
|
skipPreflight?: boolean,
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -60,8 +60,8 @@ export type SendOptions = {
|
|||||||
* @property {number | undefined} confirmations desired number of cluster confirmations
|
* @property {number | undefined} confirmations desired number of cluster confirmations
|
||||||
*/
|
*/
|
||||||
export type ConfirmOptions = {
|
export type ConfirmOptions = {
|
||||||
skipPreflight: ?boolean,
|
skipPreflight?: boolean,
|
||||||
confirmations: ?number,
|
confirmations?: number,
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -378,6 +378,88 @@ type ConfirmedTransaction = {
|
|||||||
meta: ConfirmedTransactionMeta | null,
|
meta: ConfirmedTransactionMeta | null,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A partially decoded transaction instruction
|
||||||
|
*
|
||||||
|
* @typedef {Object} ParsedMessageAccount
|
||||||
|
* @property {PublicKey} pubkey Public key of the account
|
||||||
|
* @property {PublicKey} accounts Indicates if the account signed the transaction
|
||||||
|
* @property {string} data Raw base-58 instruction data
|
||||||
|
*/
|
||||||
|
type PartiallyDecodedInstruction = {|
|
||||||
|
programId: PublicKey,
|
||||||
|
accounts: Array<PublicKey>,
|
||||||
|
data: string,
|
||||||
|
|};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A parsed transaction message account
|
||||||
|
*
|
||||||
|
* @typedef {Object} ParsedMessageAccount
|
||||||
|
* @property {PublicKey} pubkey Public key of the account
|
||||||
|
* @property {boolean} signer Indicates if the account signed the transaction
|
||||||
|
* @property {boolean} writable Indicates if the account is writable for this transaction
|
||||||
|
*/
|
||||||
|
type ParsedMessageAccount = {
|
||||||
|
pubkey: PublicKey,
|
||||||
|
signer: boolean,
|
||||||
|
writable: boolean,
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A parsed transaction instruction
|
||||||
|
*
|
||||||
|
* @typedef {Object} ParsedInstruction
|
||||||
|
* @property {string} program Name of the program for this instruction
|
||||||
|
* @property {PublicKey} programId ID of the program for this instruction
|
||||||
|
* @property {any} parsed Parsed instruction info
|
||||||
|
*/
|
||||||
|
type ParsedInstruction = {|
|
||||||
|
program: string,
|
||||||
|
programId: PublicKey,
|
||||||
|
parsed: any,
|
||||||
|
|};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A parsed transaction message
|
||||||
|
*
|
||||||
|
* @typedef {Object} ParsedMessage
|
||||||
|
* @property {Array<ParsedMessageAccount>} accountKeys Accounts used in the instructions
|
||||||
|
* @property {Array<ParsedInstruction | PartiallyDecodedInstruction>} instructions The atomically executed instructions for the transaction
|
||||||
|
* @property {string} recentBlockhash Recent blockhash
|
||||||
|
*/
|
||||||
|
type ParsedMessage = {
|
||||||
|
accountKeys: ParsedMessageAccount[],
|
||||||
|
instructions: (ParsedInstruction | PartiallyDecodedInstruction)[],
|
||||||
|
recentBlockhash: string,
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A parsed transaction
|
||||||
|
*
|
||||||
|
* @typedef {Object} ParsedTransaction
|
||||||
|
* @property {Array<string>} signatures Signatures for the transaction
|
||||||
|
* @property {ParsedMessage} message Message of the transaction
|
||||||
|
*/
|
||||||
|
type ParsedTransaction = {
|
||||||
|
signatures: Array<string>,
|
||||||
|
message: ParsedMessage,
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A parsed and confirmed transaction on the ledger
|
||||||
|
*
|
||||||
|
* @typedef {Object} ParsedConfirmedTransaction
|
||||||
|
* @property {number} slot The slot during which the transaction was processed
|
||||||
|
* @property {ParsedTransaction} transaction The details of the transaction
|
||||||
|
* @property {ConfirmedTransactionMeta|null} meta Metadata produced from the transaction
|
||||||
|
*/
|
||||||
|
type ParsedConfirmedTransaction = {
|
||||||
|
slot: number,
|
||||||
|
transaction: ParsedTransaction,
|
||||||
|
meta: ConfirmedTransactionMeta | null,
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A ConfirmedBlock on the ledger
|
* A ConfirmedBlock on the ledger
|
||||||
*
|
*
|
||||||
@ -808,14 +890,42 @@ const ConfirmedTransactionResult = struct({
|
|||||||
numReadonlyUnsignedAccounts: 'number',
|
numReadonlyUnsignedAccounts: 'number',
|
||||||
}),
|
}),
|
||||||
instructions: struct.array([
|
instructions: struct.array([
|
||||||
struct.union([
|
|
||||||
struct.array(['number']),
|
|
||||||
struct({
|
struct({
|
||||||
accounts: struct.array(['number']),
|
accounts: struct.array(['number']),
|
||||||
data: 'string',
|
data: 'string',
|
||||||
programIdIndex: 'number',
|
programIdIndex: 'number',
|
||||||
}),
|
}),
|
||||||
]),
|
]),
|
||||||
|
recentBlockhash: 'string',
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
const ParsedConfirmedTransactionResult = struct({
|
||||||
|
signatures: struct.array(['string']),
|
||||||
|
message: struct({
|
||||||
|
accountKeys: struct.array([
|
||||||
|
struct({
|
||||||
|
pubkey: 'string',
|
||||||
|
signer: 'boolean',
|
||||||
|
writable: 'boolean',
|
||||||
|
}),
|
||||||
|
]),
|
||||||
|
instructions: struct.array([
|
||||||
|
struct.union([
|
||||||
|
struct({
|
||||||
|
accounts: struct.array(['string']),
|
||||||
|
data: 'string',
|
||||||
|
programId: 'string',
|
||||||
|
}),
|
||||||
|
struct({
|
||||||
|
parsed: 'any',
|
||||||
|
program: 'string',
|
||||||
|
programId: 'string',
|
||||||
|
}),
|
||||||
|
]),
|
||||||
]),
|
]),
|
||||||
recentBlockhash: 'string',
|
recentBlockhash: 'string',
|
||||||
}),
|
}),
|
||||||
@ -877,6 +987,20 @@ const GetConfirmedTransactionRpcResult = jsonRpcResult(
|
|||||||
]),
|
]),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Expected JSON RPC response for the "getConfirmedTransaction" message
|
||||||
|
*/
|
||||||
|
const GetParsedConfirmedTransactionRpcResult = jsonRpcResult(
|
||||||
|
struct.union([
|
||||||
|
'null',
|
||||||
|
struct.pick({
|
||||||
|
slot: 'number',
|
||||||
|
transaction: ParsedConfirmedTransactionResult,
|
||||||
|
meta: ConfirmedTransactionMetaResult,
|
||||||
|
}),
|
||||||
|
]),
|
||||||
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Expected JSON RPC response for the "getRecentBlockhash" message
|
* Expected JSON RPC response for the "getRecentBlockhash" message
|
||||||
*/
|
*/
|
||||||
@ -1853,6 +1977,56 @@ export class Connection {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetch parsed transaction details for a confirmed transaction
|
||||||
|
*/
|
||||||
|
async getParsedConfirmedTransaction(
|
||||||
|
signature: TransactionSignature,
|
||||||
|
): Promise<ParsedConfirmedTransaction | null> {
|
||||||
|
const unsafeRes = await this._rpcRequest('getConfirmedTransaction', [
|
||||||
|
signature,
|
||||||
|
'jsonParsed',
|
||||||
|
]);
|
||||||
|
const {result, error} = GetParsedConfirmedTransactionRpcResult(unsafeRes);
|
||||||
|
if (error) {
|
||||||
|
throw new Error('failed to get confirmed transaction: ' + error.message);
|
||||||
|
}
|
||||||
|
assert(typeof result !== 'undefined');
|
||||||
|
if (result === null) return result;
|
||||||
|
|
||||||
|
const {
|
||||||
|
accountKeys,
|
||||||
|
instructions,
|
||||||
|
recentBlockhash,
|
||||||
|
} = result.transaction.message;
|
||||||
|
return {
|
||||||
|
slot: result.slot,
|
||||||
|
meta: result.meta,
|
||||||
|
transaction: {
|
||||||
|
signatures: result.transaction.signatures,
|
||||||
|
message: {
|
||||||
|
accountKeys: accountKeys.map(accountKey => ({
|
||||||
|
pubkey: new PublicKey(accountKey.pubkey),
|
||||||
|
signer: accountKey.signer,
|
||||||
|
writable: accountKey.writable,
|
||||||
|
})),
|
||||||
|
instructions: instructions.map(ix => {
|
||||||
|
let mapped: any = {programId: new PublicKey(ix.programId)};
|
||||||
|
if ('accounts' in ix) {
|
||||||
|
mapped.accounts = ix.accounts.map(key => new PublicKey(key));
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
...ix,
|
||||||
|
...mapped,
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
recentBlockhash,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fetch a list of all the confirmed signatures for transactions involving an address
|
* Fetch a list of all the confirmed signatures for transactions involving an address
|
||||||
* within a specified slot range. Max range allowed is 10,000 slots.
|
* within a specified slot range. Max range allowed is 10,000 slots.
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
// @flow
|
// @flow
|
||||||
|
|
||||||
|
import bs58 from 'bs58';
|
||||||
import fs from 'mz/fs';
|
import fs from 'mz/fs';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
@ -77,7 +78,29 @@ test('load BPF Rust program', async () => {
|
|||||||
programId: program.publicKey,
|
programId: program.publicKey,
|
||||||
});
|
});
|
||||||
await sendAndConfirmTransaction(connection, transaction, [from], {
|
await sendAndConfirmTransaction(connection, transaction, [from], {
|
||||||
confirmations: 1,
|
|
||||||
skipPreflight: true,
|
skipPreflight: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (transaction.signature === null) {
|
||||||
|
expect(transaction.signature).not.toBeNull();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const confirmedSignature = bs58.encode(transaction.signature);
|
||||||
|
const parsedTx = await connection.getParsedConfirmedTransaction(
|
||||||
|
confirmedSignature,
|
||||||
|
);
|
||||||
|
if (parsedTx === null) {
|
||||||
|
expect(parsedTx).not.toBeNull();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const {signatures, message} = parsedTx.transaction;
|
||||||
|
expect(signatures[0]).toEqual(confirmedSignature);
|
||||||
|
const ix = message.instructions[0];
|
||||||
|
if (ix.parsed) {
|
||||||
|
expect('parsed' in ix).toBe(false);
|
||||||
|
} else {
|
||||||
|
expect(ix.programId.equals(program.publicKey)).toBe(true);
|
||||||
|
expect(ix.data).toEqual('');
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
@ -16,6 +16,7 @@ import {mockGetRecentBlockhash} from './mockrpc/get-recent-blockhash';
|
|||||||
import {url} from './url';
|
import {url} from './url';
|
||||||
import {sleep} from '../src/util/sleep';
|
import {sleep} from '../src/util/sleep';
|
||||||
import {BLOCKHASH_CACHE_TIMEOUT_MS} from '../src/connection';
|
import {BLOCKHASH_CACHE_TIMEOUT_MS} from '../src/connection';
|
||||||
|
import type {TransactionSignature} from '../src/transaction';
|
||||||
import type {SignatureStatus, TransactionError} from '../src/connection';
|
import type {SignatureStatus, TransactionError} from '../src/connection';
|
||||||
import {mockConfirmTransaction} from './mockrpc/confirm-transaction';
|
import {mockConfirmTransaction} from './mockrpc/confirm-transaction';
|
||||||
|
|
||||||
@ -1299,13 +1300,22 @@ const TOKEN_PROGRAM_ID = new PublicKey(
|
|||||||
'TokenSVp5gheXUvJ6jGWGeCsgPKgnE3YgdGKRVCMY9o',
|
'TokenSVp5gheXUvJ6jGWGeCsgPKgnE3YgdGKRVCMY9o',
|
||||||
);
|
);
|
||||||
|
|
||||||
test('token methods', async () => {
|
describe('token methods', () => {
|
||||||
if (mockRpcEnabled) {
|
if (mockRpcEnabled) {
|
||||||
console.log('non-live test skipped');
|
console.log('non-live test skipped');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const connection = new Connection(url);
|
const connection = new Connection(url);
|
||||||
|
const newAccount = new Account().publicKey;
|
||||||
|
|
||||||
|
let testToken: Token;
|
||||||
|
let testTokenAccount: PublicKey;
|
||||||
|
let testSignature: TransactionSignature;
|
||||||
|
let testOwner: Account;
|
||||||
|
|
||||||
|
// Setup token mints and accounts for token tests
|
||||||
|
beforeAll(async () => {
|
||||||
const payerAccount = new Account();
|
const payerAccount = new Account();
|
||||||
await connection.confirmTransaction(
|
await connection.confirmTransaction(
|
||||||
await connection.requestAirdrop(payerAccount.publicKey, 100000000000),
|
await connection.requestAirdrop(payerAccount.publicKey, 100000000000),
|
||||||
@ -1337,7 +1347,7 @@ test('token methods', async () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const tokenAccountDest = await token.createAccount(accountOwner.publicKey);
|
const tokenAccountDest = await token.createAccount(accountOwner.publicKey);
|
||||||
await token.transfer(
|
testSignature = await token.transfer(
|
||||||
tokenAccount,
|
tokenAccount,
|
||||||
tokenAccountDest,
|
tokenAccountDest,
|
||||||
accountOwner,
|
accountOwner,
|
||||||
@ -1345,71 +1355,96 @@ test('token methods', async () => {
|
|||||||
new u64(1),
|
new u64(1),
|
||||||
);
|
);
|
||||||
|
|
||||||
const supply = (await connection.getTokenSupply(token.publicKey, 'recent'))
|
await connection.confirmTransaction(testSignature);
|
||||||
.value;
|
|
||||||
|
testOwner = accountOwner;
|
||||||
|
testToken = token;
|
||||||
|
testTokenAccount = tokenAccount;
|
||||||
|
});
|
||||||
|
|
||||||
|
test('get token supply', async () => {
|
||||||
|
const supply = (await connection.getTokenSupply(testToken.publicKey)).value;
|
||||||
expect(supply.uiAmount).toEqual(111.11);
|
expect(supply.uiAmount).toEqual(111.11);
|
||||||
expect(supply.decimals).toEqual(2);
|
expect(supply.decimals).toEqual(2);
|
||||||
expect(supply.amount).toEqual('11111');
|
expect(supply.amount).toEqual('11111');
|
||||||
|
|
||||||
const newAccount = new Account();
|
await expect(connection.getTokenSupply(newAccount)).rejects.toThrow();
|
||||||
await expect(
|
});
|
||||||
connection.getTokenSupply(newAccount.publicKey, 'recent'),
|
|
||||||
).rejects.toThrow();
|
|
||||||
|
|
||||||
const balance = (
|
test('get confirmed token transaction', async () => {
|
||||||
await connection.getTokenAccountBalance(tokenAccount, 'recent')
|
const parsedTx = await connection.getParsedConfirmedTransaction(
|
||||||
).value;
|
testSignature,
|
||||||
|
);
|
||||||
|
if (parsedTx === null) {
|
||||||
|
expect(parsedTx).not.toBeNull();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const {signatures, message} = parsedTx.transaction;
|
||||||
|
expect(signatures[0]).toEqual(testSignature);
|
||||||
|
const ix = message.instructions[0];
|
||||||
|
if (ix.parsed) {
|
||||||
|
expect(ix.program).toEqual('spl-token');
|
||||||
|
expect(ix.programId.equals(TOKEN_PROGRAM_ID)).toBe(true);
|
||||||
|
} else {
|
||||||
|
expect('parsed' in ix).toBe(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
const missingSignature =
|
||||||
|
'45pGoC4Rr3fJ1TKrsiRkhHRbdUeX7633XAGVec6XzVdpRbzQgHhe6ZC6Uq164MPWtiqMg7wCkC6Wy3jy2BqsDEKf';
|
||||||
|
const nullResponse = await connection.getParsedConfirmedTransaction(
|
||||||
|
missingSignature,
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(nullResponse).toBeNull();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('get token account balance', async () => {
|
||||||
|
const balance = (await connection.getTokenAccountBalance(testTokenAccount))
|
||||||
|
.value;
|
||||||
expect(balance.amount).toEqual('11110');
|
expect(balance.amount).toEqual('11110');
|
||||||
expect(balance.decimals).toEqual(2);
|
expect(balance.decimals).toEqual(2);
|
||||||
expect(balance.uiAmount).toEqual(111.1);
|
expect(balance.uiAmount).toEqual(111.1);
|
||||||
|
|
||||||
await expect(
|
await expect(
|
||||||
connection.getTokenAccountBalance(newAccount.publicKey, 'recent'),
|
connection.getTokenAccountBalance(newAccount),
|
||||||
).rejects.toThrow();
|
).rejects.toThrow();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('get token accounts by owner', async () => {
|
||||||
const accountsWithMintFilter = (
|
const accountsWithMintFilter = (
|
||||||
await connection.getTokenAccountsByOwner(
|
await connection.getTokenAccountsByOwner(testOwner.publicKey, {
|
||||||
accountOwner.publicKey,
|
mint: testToken.publicKey,
|
||||||
{mint: token.publicKey},
|
})
|
||||||
'recent',
|
|
||||||
)
|
|
||||||
).value;
|
).value;
|
||||||
expect(accountsWithMintFilter.length).toEqual(2);
|
expect(accountsWithMintFilter.length).toEqual(2);
|
||||||
|
|
||||||
const accountsWithProgramFilter = (
|
const accountsWithProgramFilter = (
|
||||||
await connection.getTokenAccountsByOwner(
|
await connection.getTokenAccountsByOwner(testOwner.publicKey, {
|
||||||
accountOwner.publicKey,
|
programId: TOKEN_PROGRAM_ID,
|
||||||
{programId: TOKEN_PROGRAM_ID},
|
})
|
||||||
'recent',
|
|
||||||
)
|
|
||||||
).value;
|
).value;
|
||||||
expect(accountsWithProgramFilter.length).toEqual(3);
|
expect(accountsWithProgramFilter.length).toEqual(3);
|
||||||
|
|
||||||
const noAccounts = (
|
const noAccounts = (
|
||||||
await connection.getTokenAccountsByOwner(
|
await connection.getTokenAccountsByOwner(newAccount, {
|
||||||
newAccount.publicKey,
|
mint: testToken.publicKey,
|
||||||
{mint: token.publicKey},
|
})
|
||||||
'recent',
|
|
||||||
)
|
|
||||||
).value;
|
).value;
|
||||||
expect(noAccounts.length).toEqual(0);
|
expect(noAccounts.length).toEqual(0);
|
||||||
|
|
||||||
await expect(
|
await expect(
|
||||||
connection.getTokenAccountsByOwner(
|
connection.getTokenAccountsByOwner(testOwner.publicKey, {
|
||||||
accountOwner.publicKey,
|
mint: newAccount,
|
||||||
{mint: newAccount.publicKey},
|
}),
|
||||||
'recent',
|
|
||||||
),
|
|
||||||
).rejects.toThrow();
|
).rejects.toThrow();
|
||||||
|
|
||||||
await expect(
|
await expect(
|
||||||
connection.getTokenAccountsByOwner(
|
connection.getTokenAccountsByOwner(testOwner.publicKey, {
|
||||||
accountOwner.publicKey,
|
programId: newAccount,
|
||||||
{programId: newAccount.publicKey},
|
}),
|
||||||
'recent',
|
|
||||||
),
|
|
||||||
).rejects.toThrow();
|
).rejects.toThrow();
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|
||||||
test('get largest accounts', async () => {
|
test('get largest accounts', async () => {
|
||||||
const connection = new Connection(url);
|
const connection = new Connection(url);
|
||||||
|
Reference in New Issue
Block a user