diff --git a/docs/capabilities/client.md b/docs/capabilities/client.md index afd15403..07a56e64 100644 --- a/docs/capabilities/client.md +++ b/docs/capabilities/client.md @@ -35,7 +35,7 @@ There are a number of ways to produce one of these configuration objects: Once you have the configuration for a client, to get the client you can use the following functions: - [`algokit.getAlgoClient(config)`](../code/modules/index.md#getalgoclient) - Returns an Algod client for the given configuration; the client automatically retries on transient HTTP errors; if one isn't provided it retrieves it from the environment -- [`algokit.getAlgoIndexerClient(config)`](../code/modules/index.md#getalgoindexerclient) - Returns an Indexer client for given configuration; if one isn't provided it retrieves it from the environment +- [`algokit.getAlgoIndexerClient(config, overrideIntDecoding)`](../code/modules/index.md#getalgoindexerclient) - Returns an Indexer client for given configuration; if one isn't provided it retrieves it from the environment - [`algokit.getAlgoKmdClient(config)`](../code/modules/index.md#getalgokmdclient) - Returns a Kmd client for the given configuration; if one isn't provided it retrieves it from the environment ## Automatic retry diff --git a/docs/code/interfaces/types_indexer.AssetHolding.md b/docs/code/interfaces/types_indexer.AssetHolding.md index 15d0f05f..3418837a 100644 --- a/docs/code/interfaces/types_indexer.AssetHolding.md +++ b/docs/code/interfaces/types_indexer.AssetHolding.md @@ -21,7 +21,7 @@ Describes an asset held by an account. https://developer.algorand.org/docs/rest- ### amount -• **amount**: `number` +• **amount**: `number` \| `bigint` (a) number of units held. diff --git a/docs/code/interfaces/types_indexer.AssetTransferTransactionResult.md b/docs/code/interfaces/types_indexer.AssetTransferTransactionResult.md index 2d2da900..89d3bd51 100644 --- a/docs/code/interfaces/types_indexer.AssetTransferTransactionResult.md +++ b/docs/code/interfaces/types_indexer.AssetTransferTransactionResult.md @@ -21,7 +21,7 @@ Fields for an asset transfer transaction. https://developer.algorand.org/docs/re ### amount -• **amount**: `number` +• **amount**: `number` \| `bigint` [aamt] Amount of asset to transfer. A zero amount transferred to self allocates that asset in the account's Assets map. @@ -45,7 +45,7 @@ ___ ### close-amount -• `Optional` **close-amount**: `number` +• `Optional` **close-amount**: `number` \| `bigint` Number of assets transfered to the close-to account as part of the transaction. diff --git a/docs/code/interfaces/types_indexer.StateProofTransactionResult.md b/docs/code/interfaces/types_indexer.StateProofTransactionResult.md index d5a03dea..ff8fd664 100644 --- a/docs/code/interfaces/types_indexer.StateProofTransactionResult.md +++ b/docs/code/interfaces/types_indexer.StateProofTransactionResult.md @@ -42,7 +42,7 @@ are needed in order to verify the next state proofs (VotersCommitment and LnProv | `block-headers-commitment` | `string` | [b] BlockHeadersCommitment contains a commitment on all light block headers within a state proof interval. | | `first-attested-round` | `number` | [f] First round the message attests to | | `latest-attested-round` | `number` | [l] Last round the message attests to | -| `ln-proven-weight` | `number` | [P] An integer value representing the natural log of the proven weight with 16 bits of precision. This value would be used to verify the next state proof. | +| `ln-proven-weight` | `number` \| `bigint` | [P] An integer value representing the natural log of the proven weight with 16 bits of precision. This value would be used to verify the next state proof. | | `voters-commitment` | `string` | [v] The vector commitment root of the top N accounts to sign the next StateProof. Pattern : "^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==\\|[A-Za-z0-9+/]{3}=)?$" | #### Defined in @@ -63,11 +63,11 @@ ___ | :------ | :------ | :------ | | `part-proofs` | [`MerkleArrayProof`](types_indexer.MerkleArrayProof.md) | [P] Part proofs that make up the overall proof | | `positions-to-reveal` | `number`[] | [pr] The positions that are revealed | -| `reveals` | \{ `participant`: \{ `verifier`: \{ `commitment`: `string` ; `key-lifetime`: `number` } ; `weight`: `number` } ; `position`: `number` ; `sig-slot`: \{ `lower-sig-weight`: `number` ; `signature`: \{ `falcon-signature`: `string` ; `merkle-array-index`: `number` ; `proof`: [`MerkleArrayProof`](types_indexer.MerkleArrayProof.md) ; `verifying-key`: `string` } } }[] | [r] Reveals is a sparse map from the position being revealed to the corresponding elements from the sigs and participants arrays. | +| `reveals` | \{ `participant`: \{ `verifier`: \{ `commitment`: `string` ; `key-lifetime`: `number` } ; `weight`: `number` \| `bigint` } ; `position`: `number` ; `sig-slot`: \{ `lower-sig-weight`: `number` \| `bigint` ; `signature`: \{ `falcon-signature`: `string` ; `merkle-array-index`: `number` ; `proof`: [`MerkleArrayProof`](types_indexer.MerkleArrayProof.md) ; `verifying-key`: `string` } } }[] | [r] Reveals is a sparse map from the position being revealed to the corresponding elements from the sigs and participants arrays. | | `salt-version` | `number` | [v] Merkle signature salt version | | `sig-commit` | `string` | [c] Digest of the signature commit | | `sig-proofs` | [`MerkleArrayProof`](types_indexer.MerkleArrayProof.md) | [S] Proofs for the signature | -| `signed-weight` | `number` | [w] The combined weight of the signatures | +| `signed-weight` | `number` \| `bigint` | [w] The combined weight of the signatures | #### Defined in diff --git a/docs/code/modules/index.md b/docs/code/modules/index.md index e0fa00ee..00d40dab 100644 --- a/docs/code/modules/index.md +++ b/docs/code/modules/index.md @@ -203,7 +203,7 @@ algokit.bulkOptIn({ account: account, assetIds: [12345, 67890] }, algod) #### Defined in -[src/asset.ts:237](https://github.com/algorandfoundation/algokit-utils-ts/blob/main/src/asset.ts#L237) +[src/asset.ts:241](https://github.com/algorandfoundation/algokit-utils-ts/blob/main/src/asset.ts#L241) ___ @@ -238,7 +238,7 @@ algokit.bulkOptOut({ account: account, assetIds: [12345, 67890] }, algod) #### Defined in -[src/asset.ts:304](https://github.com/algorandfoundation/algokit-utils-ts/blob/main/src/asset.ts#L304) +[src/asset.ts:308](https://github.com/algorandfoundation/algokit-utils-ts/blob/main/src/asset.ts#L308) ___ @@ -269,7 +269,7 @@ await algokit.assetOptIn({ account, assetId }, algod) #### Defined in -[src/asset.ts:148](https://github.com/algorandfoundation/algokit-utils-ts/blob/main/src/asset.ts#L148) +[src/asset.ts:152](https://github.com/algorandfoundation/algokit-utils-ts/blob/main/src/asset.ts#L152) ___ @@ -300,7 +300,7 @@ await algokit.assetOptOut({ account, assetId, assetCreatorAddress }, algod) #### Defined in -[src/asset.ts:186](https://github.com/algorandfoundation/algokit-utils-ts/blob/main/src/asset.ts#L186) +[src/asset.ts:190](https://github.com/algorandfoundation/algokit-utils-ts/blob/main/src/asset.ts#L190) ___ @@ -437,7 +437,7 @@ ___ ### createAsset -▸ **createAsset**(`create`, `algod`): `Promise`\<[`SendTransactionResult`](../interfaces/types_transaction.SendTransactionResult.md)\> +▸ **createAsset**(`create`, `algod`): `Promise`\<[`SendTransactionResult`](../interfaces/types_transaction.SendTransactionResult.md) & \{ `confirmation?`: \{ `assetIndex`: `number` \| `bigint` } }\> Create an Algorand Standard Asset (ASA). @@ -450,7 +450,7 @@ Create an Algorand Standard Asset (ASA). #### Returns -`Promise`\<[`SendTransactionResult`](../interfaces/types_transaction.SendTransactionResult.md)\> +`Promise`\<[`SendTransactionResult`](../interfaces/types_transaction.SendTransactionResult.md) & \{ `confirmation?`: \{ `assetIndex`: `number` \| `bigint` } }\> The transaction object and optionally the confirmation if it was sent to the chain (`skipSending` is `false` or unset) @@ -655,7 +655,7 @@ ___ #### Defined in -[src/indexer-lookup.ts:133](https://github.com/algorandfoundation/algokit-utils-ts/blob/main/src/indexer-lookup.ts#L133) +[src/indexer-lookup.ts:109](https://github.com/algorandfoundation/algokit-utils-ts/blob/main/src/indexer-lookup.ts#L109) ___ @@ -920,13 +920,13 @@ Returns an algod SDK client that automatically retries on idempotent calls #### Defined in -[src/network-client.ts:129](https://github.com/algorandfoundation/algokit-utils-ts/blob/main/src/network-client.ts#L129) +[src/network-client.ts:130](https://github.com/algorandfoundation/algokit-utils-ts/blob/main/src/network-client.ts#L130) ___ ### getAlgoIndexerClient -▸ **getAlgoIndexerClient**(`config?`): `Indexer` +▸ **getAlgoIndexerClient**(`config?`, `overrideIntDecoding?`): `Indexer` Returns an indexer SDK client that automatically retries on idempotent calls @@ -935,6 +935,7 @@ Returns an indexer SDK client that automatically retries on idempotent calls | Name | Type | Description | | :------ | :------ | :------ | | `config?` | [`AlgoClientConfig`](../interfaces/types_network_client.AlgoClientConfig.md) | The config if you want to override the default (getting config from process.env) | +| `overrideIntDecoding?` | `IntDecoding` | Override the default int decoding for responses, uses MIXED by default to avoid lost precision for big integers | #### Returns @@ -944,7 +945,6 @@ Returns an indexer SDK client that automatically retries on idempotent calls ```typescript // Uses process.env.INDEXER_SERVER, process.env.INDEXER_PORT and process.env.INDEXER_TOKEN - // Automatically detects if you are using PureStake to switch in the right header name for INDEXER_TOKEN const indexer = getAlgoIndexerClient() await indexer.makeHealthCheck().do() ``` @@ -970,9 +970,15 @@ Returns an indexer SDK client that automatically retries on idempotent calls await indexer.makeHealthCheck().do() ``` +**`Example`** + +```typescript + const indexer = getAlgoIndexerClient(config, IntDecoding.BIGINT) +``` + #### Defined in -[src/network-client.ts:162](https://github.com/algorandfoundation/algokit-utils-ts/blob/main/src/network-client.ts#L162) +[src/network-client.ts:167](https://github.com/algorandfoundation/algokit-utils-ts/blob/main/src/network-client.ts#L167) ___ @@ -1009,7 +1015,7 @@ KMD client allows you to export private keys, which is useful to get the default #### Defined in -[src/network-client.ts:185](https://github.com/algorandfoundation/algokit-utils-ts/blob/main/src/network-client.ts#L185) +[src/network-client.ts:193](https://github.com/algorandfoundation/algokit-utils-ts/blob/main/src/network-client.ts#L193) ___ @@ -1032,7 +1038,7 @@ Returns the Algorand configuration to point to the AlgoNode service #### Defined in -[src/network-client.ts:75](https://github.com/algorandfoundation/algokit-utils-ts/blob/main/src/network-client.ts#L75) +[src/network-client.ts:76](https://github.com/algorandfoundation/algokit-utils-ts/blob/main/src/network-client.ts#L76) ___ @@ -1048,7 +1054,7 @@ Retrieve the algod configuration from environment variables (expects to be calle #### Defined in -[src/network-client.ts:37](https://github.com/algorandfoundation/algokit-utils-ts/blob/main/src/network-client.ts#L37) +[src/network-client.ts:38](https://github.com/algorandfoundation/algokit-utils-ts/blob/main/src/network-client.ts#L38) ___ @@ -1549,7 +1555,7 @@ Retrieve configurations from environment variables when defined or get defaults #### Defined in -[src/network-client.ts:10](https://github.com/algorandfoundation/algokit-utils-ts/blob/main/src/network-client.ts#L10) +[src/network-client.ts:11](https://github.com/algorandfoundation/algokit-utils-ts/blob/main/src/network-client.ts#L11) ___ @@ -1598,7 +1604,7 @@ Returns the Algorand configuration to point to the default LocalNet #### Defined in -[src/network-client.ts:86](https://github.com/algorandfoundation/algokit-utils-ts/blob/main/src/network-client.ts#L86) +[src/network-client.ts:87](https://github.com/algorandfoundation/algokit-utils-ts/blob/main/src/network-client.ts#L87) ___ @@ -1640,7 +1646,7 @@ Retrieve the indexer configuration from environment variables (expects to be cal #### Defined in -[src/network-client.ts:54](https://github.com/algorandfoundation/algokit-utils-ts/blob/main/src/network-client.ts#L54) +[src/network-client.ts:55](https://github.com/algorandfoundation/algokit-utils-ts/blob/main/src/network-client.ts#L55) ___ @@ -1910,7 +1916,7 @@ ___ #### Defined in -[src/network-client.ts:197](https://github.com/algorandfoundation/algokit-utils-ts/blob/main/src/network-client.ts#L197) +[src/network-client.ts:205](https://github.com/algorandfoundation/algokit-utils-ts/blob/main/src/network-client.ts#L205) ___ @@ -1957,7 +1963,7 @@ ___ #### Defined in -[src/network-client.ts:192](https://github.com/algorandfoundation/algokit-utils-ts/blob/main/src/network-client.ts#L192) +[src/network-client.ts:200](https://github.com/algorandfoundation/algokit-utils-ts/blob/main/src/network-client.ts#L200) ___ @@ -1982,7 +1988,7 @@ The result of the look-up #### Defined in -[src/indexer-lookup.ts:54](https://github.com/algorandfoundation/algokit-utils-ts/blob/main/src/indexer-lookup.ts#L54) +[src/indexer-lookup.ts:30](https://github.com/algorandfoundation/algokit-utils-ts/blob/main/src/indexer-lookup.ts#L30) ___ @@ -2009,7 +2015,7 @@ The list of application results #### Defined in -[src/indexer-lookup.ts:66](https://github.com/algorandfoundation/algokit-utils-ts/blob/main/src/indexer-lookup.ts#L66) +[src/indexer-lookup.ts:42](https://github.com/algorandfoundation/algokit-utils-ts/blob/main/src/indexer-lookup.ts#L42) ___ @@ -2034,7 +2040,7 @@ The result of the look-up #### Defined in -[src/indexer-lookup.ts:42](https://github.com/algorandfoundation/algokit-utils-ts/blob/main/src/indexer-lookup.ts#L42) +[src/indexer-lookup.ts:20](https://github.com/algorandfoundation/algokit-utils-ts/blob/main/src/indexer-lookup.ts#L20) ___ @@ -2443,7 +2449,7 @@ The search results #### Defined in -[src/indexer-lookup.ts:99](https://github.com/algorandfoundation/algokit-utils-ts/blob/main/src/indexer-lookup.ts#L99) +[src/indexer-lookup.ts:75](https://github.com/algorandfoundation/algokit-utils-ts/blob/main/src/indexer-lookup.ts#L75) ___ diff --git a/src/indexer-lookup.spec.ts b/src/indexer-lookup.spec.ts index cfed86da..cb464f39 100644 --- a/src/indexer-lookup.spec.ts +++ b/src/indexer-lookup.spec.ts @@ -85,4 +85,71 @@ describe('indexer-lookup', () => { expect(apps.map((a) => a.id).sort()).toEqual([app1.appId, app2.appId].sort()) }) + + test('Asset transfer and creation transactions are found by search or by ID with amounts gt 53-bit', async () => { + const { algod, indexer, testAccount, generateAccount, waitForIndexer } = localnet.context + const secondAccount = await generateAccount({ + initialFunds: algokit.algos(1), + suppressLog: true, + }) + const asset = await algokit.createAsset( + { + creator: testAccount, + total: 135_640_597_783_270_615n, + decimals: 0, + }, + algod, + ) + await algokit.assetOptIn( + { + account: secondAccount, + assetId: Number(asset.confirmation!.assetIndex), + }, + algod, + ) + const transfer = await algokit.transferAsset( + { + amount: 134_640_597_783_270_615n, + from: testAccount, + to: secondAccount, + assetId: Number(asset.confirmation!.assetIndex), + }, + algod, + ) + const closeOut = await algokit.sendTransaction( + { + transaction: algosdk.makeAssetTransferTxnWithSuggestedParamsFromObject({ + assetIndex: Number(asset.confirmation!.assetIndex), + from: algokit.getSenderAddress(secondAccount), + to: algokit.getSenderAddress(testAccount), + closeRemainderTo: algokit.getSenderAddress(testAccount), + amount: 257, + suggestedParams: await algokit.getTransactionParams(undefined, algod), + }), + from: secondAccount, + }, + algod, + ) + await waitForIndexer() + + const searchTransactions = (await algokit.searchTransactions(indexer, (s) => s.assetID(Number(asset.confirmation!.assetIndex)))) + .transactions + + const acfgTxn = await algokit.lookupTransactionById(asset.transaction.txID(), indexer) + const acfgTxnFromSearch = searchTransactions.find((t) => t.id === asset.transaction.txID())! + expect(acfgTxn.transaction['asset-config-transaction']!.params!.total).toBe(135_640_597_783_270_615n) + expect(acfgTxnFromSearch['asset-config-transaction']!.params!.total).toBe(135_640_597_783_270_615n) + + const axferTxn = await algokit.lookupTransactionById(transfer.transaction.txID(), indexer) + const axferTxnFromSearch = searchTransactions.find((t) => t.id === transfer.transaction.txID())! + expect(axferTxn.transaction['asset-transfer-transaction']!.amount).toBe(134_640_597_783_270_615n) + expect(axferTxnFromSearch['asset-transfer-transaction']!.amount).toBe(134_640_597_783_270_615n) + + const closeOutTxn = await algokit.lookupTransactionById(closeOut.transaction.txID(), indexer) + const closeOutTxnFromSearch = searchTransactions.find((t) => t.id === closeOut.transaction.txID())! + expect(closeOutTxn.transaction['asset-transfer-transaction']!.amount).toBe(257) + expect(closeOutTxnFromSearch['asset-transfer-transaction']!.amount).toBe(257) + expect(closeOutTxn.transaction['asset-transfer-transaction']!['close-amount']).toBe(134_640_597_783_270_615n - 257n) + expect(closeOutTxnFromSearch['asset-transfer-transaction']!['close-amount']).toBe(134_640_597_783_270_615n - 257n) + }) }) diff --git a/src/network-client.ts b/src/network-client.ts index 2c79e14d..3730e690 100644 --- a/src/network-client.ts +++ b/src/network-client.ts @@ -5,6 +5,7 @@ import { AlgoClientConfig, AlgoConfig } from './types/network-client' import Algodv2 = algosdk.Algodv2 import Indexer = algosdk.Indexer import Kmd = algosdk.Kmd +import IntDecoding = algosdk.IntDecoding /** Retrieve configurations from environment variables when defined or get defaults (expects to be called from a Node.js environment not algod-side) */ export function getConfigFromEnvOrDefaults(): AlgoConfig { @@ -135,11 +136,11 @@ export function getAlgoClient(config?: AlgoClientConfig): Algodv2 { /** Returns an indexer SDK client that automatically retries on idempotent calls * * @param config The config if you want to override the default (getting config from process.env) + * @param overrideIntDecoding Override the default int decoding for responses, uses MIXED by default to avoid lost precision for big integers * @example Default (load from environment variables) * * ```typescript * // Uses process.env.INDEXER_SERVER, process.env.INDEXER_PORT and process.env.INDEXER_TOKEN - * // Automatically detects if you are using PureStake to switch in the right header name for INDEXER_TOKEN * const indexer = getAlgoIndexerClient() * await indexer.makeHealthCheck().do() * ``` @@ -158,11 +159,18 @@ export function getAlgoClient(config?: AlgoClientConfig): Algodv2 { * const indexer = getAlgoIndexerClient({server: 'http://localhost', port: '8980', token: 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'}) * await indexer.makeHealthCheck().do() * ``` + * @example Override int decoding for responses + * ```typescript + * const indexer = getAlgoIndexerClient(config, IntDecoding.BIGINT) + * ``` */ -export function getAlgoIndexerClient(config?: AlgoClientConfig): Indexer { +export function getAlgoIndexerClient(config?: AlgoClientConfig, overrideIntDecoding?: IntDecoding): Indexer { const { token, server, port } = config ?? getIndexerConfigFromEnvironment() const httpClientWithRetry = new AlgoHttpClientWithRetry(getAlgoTokenHeader(server, token, 'X-Indexer-API-Token'), server, port) - return new Indexer(httpClientWithRetry) + const indexer = new Indexer(httpClientWithRetry) + // Use mixed int decoding by default so bigints don't have lost precision + indexer.setIntEncoding(overrideIntDecoding ?? IntDecoding.MIXED) + return indexer } /** diff --git a/src/types/indexer.ts b/src/types/indexer.ts index 86a0bf2f..4916293e 100644 --- a/src/types/indexer.ts +++ b/src/types/indexer.ts @@ -300,7 +300,7 @@ export interface StateProofTransactionResult { /** [l] Last round the message attests to */ 'latest-attested-round': number /** [P] An integer value representing the natural log of the proven weight with 16 bits of precision. This value would be used to verify the next state proof. */ - 'ln-proven-weight': number + 'ln-proven-weight': number | bigint /** [v] The vector commitment root of the top N accounts to sign the next StateProof. * * Pattern : "^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==\|[A-Za-z0-9+/]{3}=)?$" */ @@ -343,7 +343,7 @@ export interface StateProofTransactionResult { 'key-lifetime': number } /** [w] Weight is AccountData.MicroAlgos. */ - weight: number + weight: number | bigint } /** [s] A sigslotCommit is a single slot in the sigs array that forms the state proof. */ 'sig-slot': { @@ -351,7 +351,7 @@ export interface StateProofTransactionResult { * This is initialized once the builder has collected a sufficient * number of signatures. */ - 'lower-sig-weight': number + 'lower-sig-weight': number | bigint /** [s] Sig is a signature by the participant on the expected message. * * Signature represents a signature in the Merkle signature scheme using falcon signatures as an underlying crypto scheme. @@ -380,7 +380,7 @@ export interface StateProofTransactionResult { /** [S] Proofs for the signature */ 'sig-proofs': MerkleArrayProof /** [w] The combined weight of the signatures */ - 'signed-weight': number + 'signed-weight': number | bigint } /** [sptype] State proof type, per https://github.com/algorand/go-algorand/blob/master/protocol/stateproof.go#L24 * @@ -484,11 +484,11 @@ export interface AssetFreezeTransactionResult { /** Fields for an asset transfer transaction. https://developer.algorand.org/docs/rest-apis/indexer/#transactionassettransfer */ export interface AssetTransferTransactionResult { /** [aamt] Amount of asset to transfer. A zero amount transferred to self allocates that asset in the account's Assets map. */ - amount: number + amount: number | bigint /** [xaid] ID of the asset being transferred. */ 'asset-id': number /** Number of assets transfered to the close-to account as part of the transaction. */ - 'close-amount'?: number + 'close-amount'?: number | bigint /** [aclose] Indicates that the asset should be removed from the account's Assets map, and specifies where the remaining asset holdings should be transferred. It's always valid to transfer remaining asset holdings to the creator account. */ 'close-to'?: string /** [arcv] Recipient address of the transfer. */ @@ -820,7 +820,7 @@ export interface AssetHolding { /** * (a) number of units held. */ - amount: number + amount: number | bigint /** * Asset ID of the holding. */