diff --git a/.github/workflows/tests-build-js.yml b/.github/workflows/tests-build-js.yml index 86eb576bf4d..f7e9104792d 100644 --- a/.github/workflows/tests-build-js.yml +++ b/.github/workflows/tests-build-js.yml @@ -5,7 +5,7 @@ jobs: build-js: name: Build JS runs-on: ubuntu-24.04 - timeout-minutes: 10 + timeout-minutes: 15 steps: - uses: softwareforgood/check-artifact-v4-existence@v0 id: check-artifact diff --git a/packages/js-evo-sdk/src/group/facade.ts b/packages/js-evo-sdk/src/group/facade.ts index 3f8093f7104..7024fc509fd 100644 --- a/packages/js-evo-sdk/src/group/facade.ts +++ b/packages/js-evo-sdk/src/group/facade.ts @@ -4,6 +4,92 @@ export class GroupFacade { private sdk: EvoSDK; constructor(sdk: EvoSDK) { this.sdk = sdk; } + async info(contractId: string, groupContractPosition: number): Promise { + const w = await this.sdk.getWasmSdkConnected(); + return w.getGroupInfo(contractId, groupContractPosition); + } + + async infoWithProof(contractId: string, groupContractPosition: number): Promise { + const w = await this.sdk.getWasmSdkConnected(); + return w.getGroupInfoWithProofInfo(contractId, groupContractPosition); + } + + async infos(contractId: string, startAtInfo?: unknown, count?: number): Promise { + const w = await this.sdk.getWasmSdkConnected(); + return w.getGroupInfos(contractId, startAtInfo ?? null, count ?? null); + } + + async infosWithProof(contractId: string, startAtInfo?: unknown, count?: number): Promise { + const w = await this.sdk.getWasmSdkConnected(); + return w.getGroupInfosWithProofInfo(contractId, startAtInfo ?? null, count ?? null); + } + + async members(contractId: string, groupContractPosition: number, opts: { memberIds?: string[]; startAt?: string; limit?: number } = {}): Promise { + const { memberIds, startAt, limit } = opts; + const w = await this.sdk.getWasmSdkConnected(); + return w.getGroupMembers(contractId, groupContractPosition, memberIds ?? null, startAt ?? null, limit ?? null); + } + + async membersWithProof(contractId: string, groupContractPosition: number, opts: { memberIds?: string[]; startAt?: string; limit?: number } = {}): Promise { + const { memberIds, startAt, limit } = opts; + const w = await this.sdk.getWasmSdkConnected(); + return w.getGroupMembersWithProofInfo(contractId, groupContractPosition, memberIds ?? null, startAt ?? null, limit ?? null); + } + + async identityGroups(identityId: string, opts: { memberDataContracts?: string[]; ownerDataContracts?: string[]; moderatorDataContracts?: string[] } = {}): Promise { + const { memberDataContracts, ownerDataContracts, moderatorDataContracts } = opts; + const w = await this.sdk.getWasmSdkConnected(); + return w.getIdentityGroups( + identityId, + memberDataContracts ?? null, + ownerDataContracts ?? null, + moderatorDataContracts ?? null, + ); + } + + async identityGroupsWithProof(identityId: string, opts: { memberDataContracts?: string[]; ownerDataContracts?: string[]; moderatorDataContracts?: string[] } = {}): Promise { + const { memberDataContracts, ownerDataContracts, moderatorDataContracts } = opts; + const w = await this.sdk.getWasmSdkConnected(); + return w.getIdentityGroupsWithProofInfo( + identityId, + memberDataContracts ?? null, + ownerDataContracts ?? null, + moderatorDataContracts ?? null, + ); + } + + async actions(contractId: string, groupContractPosition: number, status: string, opts: { startAtInfo?: unknown; count?: number } = {}): Promise { + const { startAtInfo, count } = opts; + const w = await this.sdk.getWasmSdkConnected(); + return w.getGroupActions(contractId, groupContractPosition, status, startAtInfo ?? null, count ?? null); + } + + async actionsWithProof(contractId: string, groupContractPosition: number, status: string, opts: { startAtInfo?: unknown; count?: number } = {}): Promise { + const { startAtInfo, count } = opts; + const w = await this.sdk.getWasmSdkConnected(); + return w.getGroupActionsWithProofInfo(contractId, groupContractPosition, status, startAtInfo ?? null, count ?? null); + } + + async actionSigners(contractId: string, groupContractPosition: number, status: string, actionId: string): Promise { + const w = await this.sdk.getWasmSdkConnected(); + return w.getGroupActionSigners(contractId, groupContractPosition, status, actionId); + } + + async actionSignersWithProof(contractId: string, groupContractPosition: number, status: string, actionId: string): Promise { + const w = await this.sdk.getWasmSdkConnected(); + return w.getGroupActionSignersWithProofInfo(contractId, groupContractPosition, status, actionId); + } + + async groupsDataContracts(dataContractIds: string[]): Promise { + const w = await this.sdk.getWasmSdkConnected(); + return w.getGroupsDataContracts(dataContractIds); + } + + async groupsDataContractsWithProof(dataContractIds: string[]): Promise { + const w = await this.sdk.getWasmSdkConnected(); + return w.getGroupsDataContractsWithProofInfo(dataContractIds); + } + async contestedResources(params: { documentTypeName: string; contractId: string; indexName: string; startAtValue?: Uint8Array; limit?: number; orderAscending?: boolean }): Promise { const { documentTypeName, contractId, indexName, startAtValue, limit, orderAscending } = params; const w = await this.sdk.getWasmSdkConnected(); diff --git a/packages/js-evo-sdk/src/identities/facade.ts b/packages/js-evo-sdk/src/identities/facade.ts index 94a448ccd11..c7331b132fc 100644 --- a/packages/js-evo-sdk/src/identities/facade.ts +++ b/packages/js-evo-sdk/src/identities/facade.ts @@ -38,6 +38,114 @@ export class IdentitiesFacade { ); } + async getKeysWithProof(args: { identityId: string; keyRequestType: 'all' | 'specific' | 'search'; specificKeyIds?: number[]; limit?: number; offset?: number }): Promise { + const { identityId, keyRequestType, specificKeyIds, limit, offset } = args; + const w = await this.sdk.getWasmSdkConnected(); + return w.getIdentityKeysWithProofInfo( + identityId, + keyRequestType, + specificKeyIds ? Uint32Array.from(specificKeyIds) : null, + limit ?? null, + offset ?? null, + ); + } + + async nonce(identityId: string): Promise { + const w = await this.sdk.getWasmSdkConnected(); + return w.getIdentityNonce(identityId); + } + + async nonceWithProof(identityId: string): Promise { + const w = await this.sdk.getWasmSdkConnected(); + return w.getIdentityNonceWithProofInfo(identityId); + } + + async contractNonce(identityId: string, contractId: string): Promise { + const w = await this.sdk.getWasmSdkConnected(); + return w.getIdentityContractNonce(identityId, contractId); + } + + async contractNonceWithProof(identityId: string, contractId: string): Promise { + const w = await this.sdk.getWasmSdkConnected(); + return w.getIdentityContractNonceWithProofInfo(identityId, contractId); + } + + async balance(identityId: string): Promise { + const w = await this.sdk.getWasmSdkConnected(); + return w.getIdentityBalance(identityId); + } + + async balanceWithProof(identityId: string): Promise { + const w = await this.sdk.getWasmSdkConnected(); + return w.getIdentityBalanceWithProofInfo(identityId); + } + + async balances(identityIds: string[]): Promise { + const w = await this.sdk.getWasmSdkConnected(); + return w.getIdentitiesBalances(identityIds); + } + + async balancesWithProof(identityIds: string[]): Promise { + const w = await this.sdk.getWasmSdkConnected(); + return w.getIdentitiesBalancesWithProofInfo(identityIds); + } + + async balanceAndRevision(identityId: string): Promise { + const w = await this.sdk.getWasmSdkConnected(); + return w.getIdentityBalanceAndRevision(identityId); + } + + async balanceAndRevisionWithProof(identityId: string): Promise { + const w = await this.sdk.getWasmSdkConnected(); + return w.getIdentityBalanceAndRevisionWithProofInfo(identityId); + } + + async byPublicKeyHash(publicKeyHash: string): Promise { + const w = await this.sdk.getWasmSdkConnected(); + return w.getIdentityByPublicKeyHash(publicKeyHash); + } + + async byPublicKeyHashWithProof(publicKeyHash: string): Promise { + const w = await this.sdk.getWasmSdkConnected(); + return w.getIdentityByPublicKeyHashWithProofInfo(publicKeyHash); + } + + async byNonUniquePublicKeyHash(publicKeyHash: string, opts: { startAfter?: string } = {}): Promise { + const { startAfter } = opts; + const w = await this.sdk.getWasmSdkConnected(); + return w.getIdentityByNonUniquePublicKeyHash(publicKeyHash, startAfter ?? null); + } + + async byNonUniquePublicKeyHashWithProof(publicKeyHash: string, opts: { startAfter?: string } = {}): Promise { + const { startAfter } = opts; + const w = await this.sdk.getWasmSdkConnected(); + return w.getIdentityByNonUniquePublicKeyHashWithProofInfo(publicKeyHash, startAfter ?? null); + } + + async contractKeys(args: { identityIds: string[]; contractId: string; purposes?: number[] }): Promise { + const { identityIds, contractId, purposes } = args; + const purposesArray = purposes && purposes.length > 0 ? Uint32Array.from(purposes) : null; + const w = await this.sdk.getWasmSdkConnected(); + return w.getIdentitiesContractKeys(identityIds, contractId, purposesArray); + } + + async contractKeysWithProof(args: { identityIds: string[]; contractId: string; purposes?: number[] }): Promise { + const { identityIds, contractId, purposes } = args; + const purposesArray = purposes && purposes.length > 0 ? Uint32Array.from(purposes) : null; + const w = await this.sdk.getWasmSdkConnected(); + return w.getIdentitiesContractKeysWithProofInfo(identityIds, contractId, purposesArray); + } + + async tokenBalances(identityId: string, tokenIds: string[]): Promise { + const w = await this.sdk.getWasmSdkConnected(); + return w.getIdentityTokenBalances(identityId, tokenIds); + } + + async tokenBalancesWithProof(identityId: string, tokenIds: string[]): Promise { + const w = await this.sdk.getWasmSdkConnected(); + return w.getIdentityTokenBalancesWithProofInfo(identityId, tokenIds); + } + async create(args: { assetLockProof: unknown; assetLockPrivateKeyWif: string; publicKeys: unknown[] }): Promise { const { assetLockProof, assetLockPrivateKeyWif, publicKeys } = args; const w = await this.sdk.getWasmSdkConnected(); diff --git a/packages/js-evo-sdk/src/sdk.ts b/packages/js-evo-sdk/src/sdk.ts index 992d3d21825..f1bf123ceaa 100644 --- a/packages/js-evo-sdk/src/sdk.ts +++ b/packages/js-evo-sdk/src/sdk.ts @@ -45,7 +45,6 @@ export class EvoSDK { public system!: SystemFacade; public group!: GroupFacade; public voting!: VotingFacade; - constructor(options: EvoSDKOptions = {}) { // Apply defaults while preserving any future connection options const { network = 'testnet', trusted = false, ...connection } = options; @@ -113,6 +112,18 @@ export class EvoSDK { return sdk; } + version(): number { + return this.wasm.version(); + } + + static setLogLevel(levelOrFilter: string): void { + wasm.WasmSdk.setLogLevel(levelOrFilter); + } + + static getLatestVersionNumber(): number { + return wasm.WasmSdkBuilder.getLatestVersionNumber(); + } + // Factory helpers that return configured instances (not connected) static testnet(options: ConnectionOptions = {}): EvoSDK { return new EvoSDK({ network: 'testnet', ...options }); } static mainnet(options: ConnectionOptions = {}): EvoSDK { return new EvoSDK({ network: 'mainnet', ...options }); } @@ -130,4 +141,5 @@ export { ProtocolFacade } from './protocol/facade.js'; export { SystemFacade } from './system/facade.js'; export { GroupFacade } from './group/facade.js'; export { VotingFacade } from './voting/facade.js'; -// For error types, import directly from '@dashevo/wasm-sdk/errors' +export { wallet } from './wallet/functions.js'; +export { verifyIdentityResponse, verifyDataContract, verifyDocuments, start } from './wasm.js'; diff --git a/packages/js-evo-sdk/src/tokens/facade.ts b/packages/js-evo-sdk/src/tokens/facade.ts index 853b16c6fc2..48152f05276 100644 --- a/packages/js-evo-sdk/src/tokens/facade.ts +++ b/packages/js-evo-sdk/src/tokens/facade.ts @@ -1,3 +1,4 @@ +import * as wasm from '../wasm.js'; import { asJsonString } from '../util.js'; import type { EvoSDK } from '../sdk.js'; @@ -8,6 +9,10 @@ export class TokensFacade { this.sdk = sdk; } + calculateId(contractId: string, tokenPosition: number): string { + return wasm.WasmSdk.calculateTokenIdFromContract(contractId, tokenPosition); + } + // Queries async priceByContract(contractId: string, tokenPosition: number): Promise { const w = await this.sdk.getWasmSdkConnected(); @@ -44,6 +49,16 @@ export class TokensFacade { return w.getIdentitiesTokenBalancesWithProofInfo(identityIds, tokenId); } + async identityBalances(identityId: string, tokenIds: string[]): Promise { + const w = await this.sdk.getWasmSdkConnected(); + return w.getIdentityTokenBalances(identityId, tokenIds); + } + + async identityBalancesWithProof(identityId: string, tokenIds: string[]): Promise { + const w = await this.sdk.getWasmSdkConnected(); + return w.getIdentityTokenBalancesWithProofInfo(identityId, tokenIds); + } + async identityTokenInfos(identityId: string, tokenIds: string[], _opts: { limit?: number; offset?: number } = {}): Promise { const w = await this.sdk.getWasmSdkConnected(); return w.getIdentityTokenInfos(identityId, tokenIds); diff --git a/packages/js-evo-sdk/src/wallet/functions.ts b/packages/js-evo-sdk/src/wallet/functions.ts new file mode 100644 index 00000000000..935cba0bc66 --- /dev/null +++ b/packages/js-evo-sdk/src/wallet/functions.ts @@ -0,0 +1,99 @@ +import * as wasm from '../wasm.js'; + +export namespace wallet { + export function generateMnemonic(wordCount?: number, languageCode?: string): string { + return wasm.WasmSdk.generateMnemonic(wordCount ?? null, languageCode ?? null); + } + + export function validateMnemonic(mnemonic: string, languageCode?: string): boolean { + return wasm.WasmSdk.validateMnemonic(mnemonic, languageCode ?? null); + } + + export function mnemonicToSeed(mnemonic: string, passphrase?: string): Uint8Array { + return wasm.WasmSdk.mnemonicToSeed(mnemonic, passphrase ?? null); + } + + export function deriveKeyFromSeedPhrase(mnemonic: string, passphrase: string | null | undefined, network: string): any { + return wasm.WasmSdk.deriveKeyFromSeedPhrase(mnemonic, passphrase ?? null, network); + } + + export function deriveKeyFromSeedWithPath(mnemonic: string, passphrase: string | null | undefined, path: string, network: string): any { + return wasm.WasmSdk.deriveKeyFromSeedWithPath(mnemonic, passphrase ?? null, path, network); + } + + export function deriveKeyFromSeedWithExtendedPath(mnemonic: string, passphrase: string | null | undefined, path: string, network: string): any { + return wasm.WasmSdk.deriveKeyFromSeedWithExtendedPath(mnemonic, passphrase ?? null, path, network); + } + + export function deriveDashpayContactKey(mnemonic: string, passphrase: string | null | undefined, senderIdentityId: string, receiverIdentityId: string, account: number, addressIndex: number, network: string): any { + return wasm.WasmSdk.deriveDashpayContactKey( + mnemonic, + passphrase ?? null, + senderIdentityId, + receiverIdentityId, + account, + addressIndex, + network, + ); + } + + export function derivationPathBip44Mainnet(account: number, change: number, index: number): any { + return wasm.WasmSdk.derivationPathBip44Mainnet(account, change, index); + } + + export function derivationPathBip44Testnet(account: number, change: number, index: number): any { + return wasm.WasmSdk.derivationPathBip44Testnet(account, change, index); + } + + export function derivationPathDip9Mainnet(featureType: number, account: number, index: number): any { + return wasm.WasmSdk.derivationPathDip9Mainnet(featureType, account, index); + } + + export function derivationPathDip9Testnet(featureType: number, account: number, index: number): any { + return wasm.WasmSdk.derivationPathDip9Testnet(featureType, account, index); + } + + export function derivationPathDip13Mainnet(account: number): any { + return wasm.WasmSdk.derivationPathDip13Mainnet(account); + } + + export function derivationPathDip13Testnet(account: number): any { + return wasm.WasmSdk.derivationPathDip13Testnet(account); + } + + export function deriveChildPublicKey(xpub: string, index: number, hardened: boolean): string { + return wasm.WasmSdk.deriveChildPublicKey(xpub, index, hardened); + } + + export function xprvToXpub(xprv: string): string { + return wasm.WasmSdk.xprvToXpub(xprv); + } + + export function generateKeyPair(network: string): any { + return wasm.WasmSdk.generateKeyPair(network); + } + + export function generateKeyPairs(network: string, count: number): any[] { + return wasm.WasmSdk.generateKeyPairs(network, count); + } + + export function keyPairFromWif(privateKeyWif: string): any { + return wasm.WasmSdk.keyPairFromWif(privateKeyWif); + } + + export function keyPairFromHex(privateKeyHex: string, network: string): any { + return wasm.WasmSdk.keyPairFromHex(privateKeyHex, network); + } + + export function pubkeyToAddress(pubkeyHex: string, network: string): string { + return wasm.WasmSdk.pubkeyToAddress(pubkeyHex, network); + } + + export function validateAddress(address: string, network: string): boolean { + return wasm.WasmSdk.validateAddress(address, network); + } + + export function signMessage(message: string, privateKeyWif: string): string { + return wasm.WasmSdk.signMessage(message, privateKeyWif); + } +} diff --git a/packages/js-evo-sdk/tests/functional/documents.spec.mjs b/packages/js-evo-sdk/tests/functional/documents.spec.mjs index 8ec59326580..e375c5d1dce 100644 --- a/packages/js-evo-sdk/tests/functional/documents.spec.mjs +++ b/packages/js-evo-sdk/tests/functional/documents.spec.mjs @@ -1,4 +1,3 @@ -import { expect } from 'chai'; import { EvoSDK } from '../../dist/evo-sdk.module.js'; import { TEST_IDS } from '../fixtures/testnet.mjs'; diff --git a/packages/js-evo-sdk/tests/functional/dpns.spec.mjs b/packages/js-evo-sdk/tests/functional/dpns.spec.mjs index 275f1745619..cbbdd6bbfc6 100644 --- a/packages/js-evo-sdk/tests/functional/dpns.spec.mjs +++ b/packages/js-evo-sdk/tests/functional/dpns.spec.mjs @@ -1,4 +1,3 @@ -import { expect } from 'chai'; import { EvoSDK } from '../../dist/evo-sdk.module.js'; import { TEST_IDS } from '../fixtures/testnet.mjs'; diff --git a/packages/js-evo-sdk/tests/functional/epoch.spec.mjs b/packages/js-evo-sdk/tests/functional/epoch.spec.mjs index 4ff1cd0faf3..f843fc9cef3 100644 --- a/packages/js-evo-sdk/tests/functional/epoch.spec.mjs +++ b/packages/js-evo-sdk/tests/functional/epoch.spec.mjs @@ -1,4 +1,3 @@ -import { expect } from 'chai'; import { EvoSDK } from '../../dist/evo-sdk.module.js'; import { TEST_IDS } from '../fixtures/testnet.mjs'; diff --git a/packages/js-evo-sdk/tests/functional/group.spec.mjs b/packages/js-evo-sdk/tests/functional/group.spec.mjs index b5dc7b9075d..21dd24c69df 100644 --- a/packages/js-evo-sdk/tests/functional/group.spec.mjs +++ b/packages/js-evo-sdk/tests/functional/group.spec.mjs @@ -32,4 +32,29 @@ describe('Group', function groupSuite() { }); expect(res).to.exist(); }); + + it('info() is callable for group contracts', async () => { + const res = await sdk.group.info(TEST_IDS.groupContractId, 0); + expect(res).to.exist(); + }); + + it('members() is callable for group contracts', async () => { + const res = await sdk.group.members(TEST_IDS.groupContractId, 0, { limit: 5 }); + expect(res).to.exist(); + }); + + it('identityGroups() is callable for known identity', async () => { + const res = await sdk.group.identityGroups(TEST_IDS.identityId); + expect(res).to.exist(); + }); + + it('actions() is callable for group contract', async () => { + const res = await sdk.group.actions(TEST_IDS.groupContractId, 0, 'ACTIVE', { count: 5 }); + expect(res).to.exist(); + }); + + it('groupsDataContracts() is callable with known ids', async () => { + const res = await sdk.group.groupsDataContracts([TEST_IDS.groupContractId]); + expect(res).to.not.equal(undefined); + }); }); diff --git a/packages/js-evo-sdk/tests/functional/identities.spec.mjs b/packages/js-evo-sdk/tests/functional/identities.spec.mjs index bb4b1cb1124..ae46b45d38c 100644 --- a/packages/js-evo-sdk/tests/functional/identities.spec.mjs +++ b/packages/js-evo-sdk/tests/functional/identities.spec.mjs @@ -1,4 +1,3 @@ -import { expect } from 'chai'; import { EvoSDK } from '../../dist/evo-sdk.module.js'; import { TEST_IDS, TEST_SECRETS } from '../fixtures/testnet.mjs'; @@ -31,6 +30,44 @@ describe('Identities', function identitiesSuite() { expect(res).to.exist(); }); + it('getKeysWithProof({ keyRequestType: "all" }) returns proof info', async () => { + const res = await sdk.identities.getKeysWithProof({ + identityId: TEST_IDS.identityId, + keyRequestType: 'all', + }); + expect(res).to.exist(); + }); + + it('nonce() returns a numeric nonce', async () => { + const res = await sdk.identities.nonce(TEST_IDS.identityId); + expect(res).to.exist(); + }); + + it('balance() returns current balance', async () => { + const res = await sdk.identities.balance(TEST_IDS.identityId); + expect(res).to.exist(); + }); + + it('balanceAndRevision() returns structure with balance field', async () => { + const res = await sdk.identities.balanceAndRevision(TEST_IDS.identityId); + expect(res).to.exist(); + }); + + it('byPublicKeyHash() resolves identity by unique hash', async () => { + const res = await sdk.identities.byPublicKeyHash(TEST_IDS.publicKeyHashUnique); + expect(res).to.exist(); + }); + + it('byNonUniquePublicKeyHash() resolves entries (may be empty)', async () => { + const res = await sdk.identities.byNonUniquePublicKeyHash(TEST_IDS.publicKeyHashNonUnique); + expect(res).to.exist(); + }); + + it('tokenBalances() resolves for known identity/token pair', async () => { + const res = await sdk.identities.tokenBalances(TEST_IDS.identityId, [TEST_IDS.tokenId]); + expect(res).to.exist(); + }); + it.skip('creditTransfer() executes when secrets provided (skipped by default)', async function creditTransferExecutesWhenSecretsProvided() { if (!TEST_SECRETS.identityId || !TEST_SECRETS.privateKeyWif) { this.skip(); diff --git a/packages/js-evo-sdk/tests/functional/protocol.spec.mjs b/packages/js-evo-sdk/tests/functional/protocol.spec.mjs index ef69fe79a42..4c48e48f3f9 100644 --- a/packages/js-evo-sdk/tests/functional/protocol.spec.mjs +++ b/packages/js-evo-sdk/tests/functional/protocol.spec.mjs @@ -1,4 +1,3 @@ -import { expect } from 'chai'; import { EvoSDK } from '../../dist/evo-sdk.module.js'; import { TEST_IDS } from '../fixtures/testnet.mjs'; diff --git a/packages/js-evo-sdk/tests/functional/system.spec.mjs b/packages/js-evo-sdk/tests/functional/system.spec.mjs index b8b051bf33f..887640ed639 100644 --- a/packages/js-evo-sdk/tests/functional/system.spec.mjs +++ b/packages/js-evo-sdk/tests/functional/system.spec.mjs @@ -1,4 +1,3 @@ -import { expect } from 'chai'; import { EvoSDK } from '../../dist/evo-sdk.module.js'; import { TEST_IDS } from '../fixtures/testnet.mjs'; diff --git a/packages/js-evo-sdk/tests/functional/tokens.spec.mjs b/packages/js-evo-sdk/tests/functional/tokens.spec.mjs index 71b6b39cbdb..68ae4e952dd 100644 --- a/packages/js-evo-sdk/tests/functional/tokens.spec.mjs +++ b/packages/js-evo-sdk/tests/functional/tokens.spec.mjs @@ -1,4 +1,3 @@ -import { expect } from 'chai'; import { EvoSDK } from '../../dist/evo-sdk.module.js'; import { TEST_IDS } from '../fixtures/testnet.mjs'; @@ -11,6 +10,11 @@ describe('Tokens', function tokensSuite() { await sdk.connect(); }); + it('calculateId() derives token ID from contract', () => { + const id = sdk.tokens.calculateId(TEST_IDS.tokenContractId, 0); + expect(id).to.equal(TEST_IDS.tokenId); + }); + it('totalSupply() returns supply for token', async () => { const res = await sdk.tokens.totalSupply(TEST_IDS.tokenId); expect(res).to.exist(); @@ -26,6 +30,11 @@ describe('Tokens', function tokensSuite() { expect(res).to.exist(); }); + it('identityBalances() returns balance list for identity', async () => { + const res = await sdk.tokens.identityBalances(TEST_IDS.identityId, [TEST_IDS.tokenId]); + expect(res).to.exist(); + }); + // TODO: Fix this test it.skip('contractInfo() returns token contract info', async () => { const res = await sdk.tokens.contractInfo(TEST_IDS.tokenContractId); diff --git a/packages/js-evo-sdk/tests/functional/voting.spec.mjs b/packages/js-evo-sdk/tests/functional/voting.spec.mjs index e16ed58d526..a5c0f260af7 100644 --- a/packages/js-evo-sdk/tests/functional/voting.spec.mjs +++ b/packages/js-evo-sdk/tests/functional/voting.spec.mjs @@ -1,4 +1,3 @@ -import { expect } from 'chai'; import { EvoSDK } from '../../dist/evo-sdk.module.js'; import { TEST_IDS } from '../fixtures/testnet.mjs'; diff --git a/packages/js-evo-sdk/tests/functional/wallet.spec.mjs b/packages/js-evo-sdk/tests/functional/wallet.spec.mjs new file mode 100644 index 00000000000..3d9a5fcb180 --- /dev/null +++ b/packages/js-evo-sdk/tests/functional/wallet.spec.mjs @@ -0,0 +1,25 @@ +import { wallet } from '../../dist/evo-sdk.module.js'; + +describe('wallet helpers', () => { + it('generateMnemonic() returns phrase and validateMnemonic() succeeds', () => { + const mnemonic = wallet.generateMnemonic(12, 'en'); + expect(mnemonic).to.be.a('string'); + expect(wallet.validateMnemonic(mnemonic, 'en')).to.equal(true); + }); + + it('mnemonicToSeed() returns Uint8Array and derive functions respond', () => { + const mnemonic = wallet.generateMnemonic(); + const seed = wallet.mnemonicToSeed(mnemonic); + expect(seed).to.be.instanceOf(Uint8Array); + expect(wallet.deriveKeyFromSeedPhrase(mnemonic, null, 'testnet')).to.exist(); + expect(wallet.deriveKeyFromSeedWithPath(mnemonic, null, "m/44'/5'/0'", 'testnet')).to.exist(); + expect(wallet.deriveKeyFromSeedWithExtendedPath(mnemonic, null, "m/15'/0'", 'testnet')).to.exist(); + }); + + it('key utilities return expected shapes', () => { + const kp = wallet.generateKeyPair('testnet'); + expect(kp).to.be.an('object'); + const kps = wallet.generateKeyPairs('testnet', 2); + expect(kps).to.be.an('array'); + }); +}); diff --git a/packages/js-evo-sdk/tests/unit/facades/group.spec.mjs b/packages/js-evo-sdk/tests/unit/facades/group.spec.mjs index 0573cd4ec6f..905d78e0702 100644 --- a/packages/js-evo-sdk/tests/unit/facades/group.spec.mjs +++ b/packages/js-evo-sdk/tests/unit/facades/group.spec.mjs @@ -11,12 +11,74 @@ describe('GroupFacade', () => { wasmSdk = builder.build(); client = EvoSDK.fromWasm(wasmSdk); + this.sinon.stub(wasmSdk, 'getGroupInfo').resolves('ok'); + this.sinon.stub(wasmSdk, 'getGroupInfoWithProofInfo').resolves('ok'); + this.sinon.stub(wasmSdk, 'getGroupInfos').resolves('ok'); + this.sinon.stub(wasmSdk, 'getGroupInfosWithProofInfo').resolves('ok'); + this.sinon.stub(wasmSdk, 'getGroupMembers').resolves('ok'); + this.sinon.stub(wasmSdk, 'getGroupMembersWithProofInfo').resolves('ok'); + this.sinon.stub(wasmSdk, 'getIdentityGroups').resolves('ok'); + this.sinon.stub(wasmSdk, 'getIdentityGroupsWithProofInfo').resolves('ok'); + this.sinon.stub(wasmSdk, 'getGroupActions').resolves('ok'); + this.sinon.stub(wasmSdk, 'getGroupActionsWithProofInfo').resolves('ok'); + this.sinon.stub(wasmSdk, 'getGroupActionSigners').resolves('ok'); + this.sinon.stub(wasmSdk, 'getGroupActionSignersWithProofInfo').resolves('ok'); + this.sinon.stub(wasmSdk, 'getGroupsDataContracts').resolves('ok'); + this.sinon.stub(wasmSdk, 'getGroupsDataContractsWithProofInfo').resolves('ok'); this.sinon.stub(wasmSdk, 'getContestedResources').resolves('ok'); this.sinon.stub(wasmSdk, 'getContestedResourcesWithProofInfo').resolves('ok'); this.sinon.stub(wasmSdk, 'getContestedResourceVotersForIdentity').resolves('ok'); this.sinon.stub(wasmSdk, 'getContestedResourceVotersForIdentityWithProofInfo').resolves('ok'); }); + it('info queries forward to wasm', async () => { + await client.group.info('contract', 1); + await client.group.infoWithProof('contract', 2); + expect(wasmSdk.getGroupInfo).to.be.calledOnceWithExactly('contract', 1); + expect(wasmSdk.getGroupInfoWithProofInfo).to.be.calledOnceWithExactly('contract', 2); + }); + + it('infos() forwards optional args with null defaults', async () => { + await client.group.infos('contract', 'cursor', 5); + await client.group.infosWithProof('contract'); + expect(wasmSdk.getGroupInfos).to.be.calledOnceWithExactly('contract', 'cursor', 5); + expect(wasmSdk.getGroupInfosWithProofInfo).to.be.calledOnceWithExactly('contract', null, null); + }); + + it('members() forwards list and optional filters', async () => { + await client.group.members('contract', 1, { memberIds: ['a'], startAt: 's', limit: 2 }); + await client.group.membersWithProof('contract', 1); + expect(wasmSdk.getGroupMembers).to.be.calledOnceWithExactly('contract', 1, ['a'], 's', 2); + expect(wasmSdk.getGroupMembersWithProofInfo).to.be.calledOnceWithExactly('contract', 1, null, null, null); + }); + + it('identityGroups() forwards optional contract filters', async () => { + await client.group.identityGroups('identity', { + memberDataContracts: ['m'], ownerDataContracts: ['o'], moderatorDataContracts: ['d'], + }); + await client.group.identityGroupsWithProof('identity'); + expect(wasmSdk.getIdentityGroups).to.be.calledOnceWithExactly('identity', ['m'], ['o'], ['d']); + expect(wasmSdk.getIdentityGroupsWithProofInfo).to.be.calledOnceWithExactly('identity', null, null, null); + }); + + it('group actions helpers forward to wasm', async () => { + await client.group.actions('contract', 1, 'pending', { startAtInfo: 'cursor', count: 3 }); + await client.group.actionsWithProof('contract', 1, 'completed'); + await client.group.actionSigners('contract', 1, 'pending', 'action'); + await client.group.actionSignersWithProof('contract', 1, 'pending', 'action'); + expect(wasmSdk.getGroupActions).to.be.calledOnceWithExactly('contract', 1, 'pending', 'cursor', 3); + expect(wasmSdk.getGroupActionsWithProofInfo).to.be.calledOnceWithExactly('contract', 1, 'completed', null, null); + expect(wasmSdk.getGroupActionSigners).to.be.calledOnceWithExactly('contract', 1, 'pending', 'action'); + expect(wasmSdk.getGroupActionSignersWithProofInfo).to.be.calledOnceWithExactly('contract', 1, 'pending', 'action'); + }); + + it('groupsDataContracts() forwards', async () => { + await client.group.groupsDataContracts(['a', 'b']); + await client.group.groupsDataContractsWithProof(['a']); + expect(wasmSdk.getGroupsDataContracts).to.be.calledOnceWithExactly(['a', 'b']); + expect(wasmSdk.getGroupsDataContractsWithProofInfo).to.be.calledOnceWithExactly(['a']); + }); + it('forwards contestedResources and voters queries', async () => { await client.group.contestedResources({ documentTypeName: 'dt', contractId: 'c', indexName: 'i', startAtValue: new Uint8Array([1]), limit: 2, orderAscending: false, diff --git a/packages/js-evo-sdk/tests/unit/facades/identities.spec.mjs b/packages/js-evo-sdk/tests/unit/facades/identities.spec.mjs index b934d83f237..4b72935988b 100644 --- a/packages/js-evo-sdk/tests/unit/facades/identities.spec.mjs +++ b/packages/js-evo-sdk/tests/unit/facades/identities.spec.mjs @@ -15,6 +15,25 @@ describe('IdentitiesFacade', () => { this.sinon.stub(wasmSdk, 'getIdentityWithProofInfo').resolves('ok'); this.sinon.stub(wasmSdk, 'getIdentityUnproved').resolves('ok'); this.sinon.stub(wasmSdk, 'getIdentityKeys').resolves('ok'); + this.sinon.stub(wasmSdk, 'getIdentityKeysWithProofInfo').resolves('ok'); + this.sinon.stub(wasmSdk, 'getIdentityNonce').resolves('ok'); + this.sinon.stub(wasmSdk, 'getIdentityNonceWithProofInfo').resolves('ok'); + this.sinon.stub(wasmSdk, 'getIdentityContractNonce').resolves('ok'); + this.sinon.stub(wasmSdk, 'getIdentityContractNonceWithProofInfo').resolves('ok'); + this.sinon.stub(wasmSdk, 'getIdentityBalance').resolves('ok'); + this.sinon.stub(wasmSdk, 'getIdentityBalanceWithProofInfo').resolves('ok'); + this.sinon.stub(wasmSdk, 'getIdentitiesBalances').resolves('ok'); + this.sinon.stub(wasmSdk, 'getIdentitiesBalancesWithProofInfo').resolves('ok'); + this.sinon.stub(wasmSdk, 'getIdentityBalanceAndRevision').resolves('ok'); + this.sinon.stub(wasmSdk, 'getIdentityBalanceAndRevisionWithProofInfo').resolves('ok'); + this.sinon.stub(wasmSdk, 'getIdentityByPublicKeyHash').resolves('ok'); + this.sinon.stub(wasmSdk, 'getIdentityByPublicKeyHashWithProofInfo').resolves('ok'); + this.sinon.stub(wasmSdk, 'getIdentityByNonUniquePublicKeyHash').resolves('ok'); + this.sinon.stub(wasmSdk, 'getIdentityByNonUniquePublicKeyHashWithProofInfo').resolves('ok'); + this.sinon.stub(wasmSdk, 'getIdentitiesContractKeys').resolves('ok'); + this.sinon.stub(wasmSdk, 'getIdentitiesContractKeysWithProofInfo').resolves('ok'); + this.sinon.stub(wasmSdk, 'getIdentityTokenBalances').resolves('ok'); + this.sinon.stub(wasmSdk, 'getIdentityTokenBalancesWithProofInfo').resolves('ok'); this.sinon.stub(wasmSdk, 'identityCreate').resolves('ok'); this.sinon.stub(wasmSdk, 'identityTopUp').resolves('ok'); this.sinon.stub(wasmSdk, 'identityCreditTransfer').resolves('ok'); @@ -53,6 +72,84 @@ describe('IdentitiesFacade', () => { expect(args[5]).to.equal(2); }); + it('getKeysWithProof() forwards with Uint32Array', async () => { + await client.identities.getKeysWithProof({ + identityId: 'id', + keyRequestType: 'specific', + specificKeyIds: [5], + limit: 1, + offset: 0, + }); + const { args } = wasmSdk.getIdentityKeysWithProofInfo.firstCall; + expect(args[0]).to.equal('id'); + expect(args[1]).to.equal('specific'); + expect(args[2]).to.be.instanceOf(Uint32Array); + expect(Array.from(args[2])).to.deep.equal([5]); + expect(args[3]).to.equal(1); + expect(args[4]).to.equal(0); + }); + + it('nonce helpers forward to wasm', async () => { + await client.identities.nonce('id'); + await client.identities.nonceWithProof('id'); + expect(wasmSdk.getIdentityNonce).to.be.calledOnceWithExactly('id'); + expect(wasmSdk.getIdentityNonceWithProofInfo).to.be.calledOnceWithExactly('id'); + }); + + it('contractNonce helpers forward to wasm', async () => { + await client.identities.contractNonce('id', 'contract'); + await client.identities.contractNonceWithProof('id', 'contract'); + expect(wasmSdk.getIdentityContractNonce).to.be.calledOnceWithExactly('id', 'contract'); + expect(wasmSdk.getIdentityContractNonceWithProofInfo).to.be.calledOnceWithExactly('id', 'contract'); + }); + + it('balance helpers forward to wasm', async () => { + await client.identities.balance('id'); + await client.identities.balanceWithProof('id'); + await client.identities.balances(['a', 'b']); + await client.identities.balancesWithProof(['c']); + expect(wasmSdk.getIdentityBalance).to.be.calledOnceWithExactly('id'); + expect(wasmSdk.getIdentityBalanceWithProofInfo).to.be.calledOnceWithExactly('id'); + expect(wasmSdk.getIdentitiesBalances).to.be.calledOnceWithExactly(['a', 'b']); + expect(wasmSdk.getIdentitiesBalancesWithProofInfo).to.be.calledOnceWithExactly(['c']); + }); + + it('balanceAndRevision helpers forward to wasm', async () => { + await client.identities.balanceAndRevision('id'); + await client.identities.balanceAndRevisionWithProof('id'); + expect(wasmSdk.getIdentityBalanceAndRevision).to.be.calledOnceWithExactly('id'); + expect(wasmSdk.getIdentityBalanceAndRevisionWithProofInfo).to.be.calledOnceWithExactly('id'); + }); + + it('public key hash lookups forward to wasm', async () => { + await client.identities.byPublicKeyHash('hash'); + await client.identities.byPublicKeyHashWithProof('hash'); + await client.identities.byNonUniquePublicKeyHash('hash', { startAfter: 'cursor' }); + await client.identities.byNonUniquePublicKeyHashWithProof('hash'); + expect(wasmSdk.getIdentityByPublicKeyHash).to.be.calledOnceWithExactly('hash'); + expect(wasmSdk.getIdentityByPublicKeyHashWithProofInfo).to.be.calledOnceWithExactly('hash'); + expect(wasmSdk.getIdentityByNonUniquePublicKeyHash).to.be.calledOnceWithExactly('hash', 'cursor'); + expect(wasmSdk.getIdentityByNonUniquePublicKeyHashWithProofInfo).to.be.calledOnceWithExactly('hash', null); + }); + + it('contractKeys helpers convert purposes to Uint32Array and forward', async () => { + await client.identities.contractKeys({ identityIds: ['a'], contractId: 'c', purposes: [1, 2] }); + await client.identities.contractKeysWithProof({ identityIds: ['b'], contractId: 'c' }); + const arrayCall = wasmSdk.getIdentitiesContractKeys.firstCall.args; + expect(arrayCall[0]).to.deep.equal(['a']); + expect(arrayCall[1]).to.equal('c'); + expect(arrayCall[2]).to.be.instanceOf(Uint32Array); + expect(Array.from(arrayCall[2])).to.deep.equal([1, 2]); + expect(wasmSdk.getIdentitiesContractKeysWithProofInfo).to.be.calledOnceWithExactly(['b'], 'c', null); + }); + + it('tokenBalances helpers forward to wasm', async () => { + await client.identities.tokenBalances('id', ['t1']); + await client.identities.tokenBalancesWithProof('id', ['t2']); + expect(wasmSdk.getIdentityTokenBalances).to.be.calledOnceWithExactly('id', ['t1']); + expect(wasmSdk.getIdentityTokenBalancesWithProofInfo).to.be.calledOnceWithExactly('id', ['t2']); + }); + it('create() calls wasmSdk.identityCreate with JSON proof and keys', async () => { await client.identities.create({ assetLockProof: { p: true }, diff --git a/packages/js-evo-sdk/tests/unit/facades/tokens.spec.mjs b/packages/js-evo-sdk/tests/unit/facades/tokens.spec.mjs index 438009b70ad..0b535d243b7 100644 --- a/packages/js-evo-sdk/tests/unit/facades/tokens.spec.mjs +++ b/packages/js-evo-sdk/tests/unit/facades/tokens.spec.mjs @@ -19,6 +19,8 @@ describe('TokensFacade', () => { this.sinon.stub(wasmSdk, 'getTokenStatusesWithProofInfo').resolves('ok'); this.sinon.stub(wasmSdk, 'getIdentitiesTokenBalances').resolves('ok'); this.sinon.stub(wasmSdk, 'getIdentitiesTokenBalancesWithProofInfo').resolves('ok'); + this.sinon.stub(wasmSdk, 'getIdentityTokenBalances').resolves('ok'); + this.sinon.stub(wasmSdk, 'getIdentityTokenBalancesWithProofInfo').resolves('ok'); this.sinon.stub(wasmSdk, 'getIdentityTokenInfos').resolves('ok'); this.sinon.stub(wasmSdk, 'getIdentitiesTokenInfos').resolves('ok'); this.sinon.stub(wasmSdk, 'getIdentityTokenInfosWithProofInfo').resolves('ok'); @@ -43,6 +45,11 @@ describe('TokensFacade', () => { this.sinon.stub(wasmSdk, 'tokenConfigUpdate').resolves('ok'); }); + it('calculateId() uses wasm static helper', () => { + const out = client.tokens.calculateId('Hqyu8WcRwXCTwbNxdga4CN5gsVEGc67wng4TFzceyLUv', 0); + expect(out).to.equal('BpJvvpPiR2obh7ueZixjtYXsmWQdgJhiZtQJWjD7Ruus'); + }); + it('query functions forward to instance methods', async () => { await client.tokens.priceByContract('c', 1); await client.tokens.totalSupply('t'); @@ -51,6 +58,8 @@ describe('TokensFacade', () => { await client.tokens.statusesWithProof(['a']); await client.tokens.balances(['i1', 'i2'], 't'); await client.tokens.balancesWithProof(['i'], 't'); + await client.tokens.identityBalances('id', ['t']); + await client.tokens.identityBalancesWithProof('id', ['t']); await client.tokens.identityTokenInfos('id', ['t1', 't2']); await client.tokens.identitiesTokenInfos(['i1'], 't'); await client.tokens.identityTokenInfosWithProof('id', ['t']); @@ -64,6 +73,22 @@ describe('TokensFacade', () => { expect(wasmSdk.getTokenPriceByContract).to.be.calledOnceWithExactly('c', 1); expect(wasmSdk.getTokenTotalSupply).to.be.calledOnceWithExactly('t'); expect(wasmSdk.getTokenTotalSupplyWithProofInfo).to.be.calledOnceWithExactly('t'); + expect(wasmSdk.getTokenStatuses).to.be.calledOnceWithExactly(['a', 'b']); + expect(wasmSdk.getTokenStatusesWithProofInfo).to.be.calledOnceWithExactly(['a']); + expect(wasmSdk.getIdentitiesTokenBalances).to.be.calledOnceWithExactly(['i1', 'i2'], 't'); + expect(wasmSdk.getIdentitiesTokenBalancesWithProofInfo).to.be.calledOnceWithExactly(['i'], 't'); + expect(wasmSdk.getIdentityTokenBalances).to.be.calledOnceWithExactly('id', ['t']); + expect(wasmSdk.getIdentityTokenBalancesWithProofInfo).to.be.calledOnceWithExactly('id', ['t']); + expect(wasmSdk.getIdentityTokenInfos).to.be.calledOnceWithExactly('id', ['t1', 't2']); + expect(wasmSdk.getIdentitiesTokenInfos).to.be.calledOnceWithExactly(['i1'], 't'); + expect(wasmSdk.getIdentityTokenInfosWithProofInfo).to.be.calledOnceWithExactly('id', ['t']); + expect(wasmSdk.getIdentitiesTokenInfosWithProofInfo).to.be.calledOnceWithExactly(['i'], 't'); + expect(wasmSdk.getTokenDirectPurchasePrices).to.be.calledOnceWithExactly(['t']); + expect(wasmSdk.getTokenDirectPurchasePricesWithProofInfo).to.be.calledOnceWithExactly(['t']); + expect(wasmSdk.getTokenContractInfo).to.be.calledOnceWithExactly('c'); + expect(wasmSdk.getTokenContractInfoWithProofInfo).to.be.calledOnceWithExactly('c'); + expect(wasmSdk.getTokenPerpetualDistributionLastClaim).to.be.calledOnceWithExactly('i', 't'); + expect(wasmSdk.getTokenPerpetualDistributionLastClaimWithProofInfo).to.be.calledOnceWithExactly('i', 't'); }); it('mint() stringifies amount and passes nullables', async () => { diff --git a/packages/js-evo-sdk/tests/unit/sdk.spec.mjs b/packages/js-evo-sdk/tests/unit/sdk.spec.mjs index 9c19d92fb4f..c45f5ae9b63 100644 --- a/packages/js-evo-sdk/tests/unit/sdk.spec.mjs +++ b/packages/js-evo-sdk/tests/unit/sdk.spec.mjs @@ -9,12 +9,10 @@ describe('EvoSDK', () => { expect(EvoSDK.mainnetTrusted).to.be.a('function'); }); - it('connects and sets isConnected', async function connectsAndSetsIsConnected() { - this.timeout(90000); - - const sdk = new EvoSDK(); - expect(sdk.isConnected).to.equal(false); - await sdk.connect(); + it('fromWasm() marks instance as connected', () => { + const wasmStub = { version: () => 1 }; + const sdk = EvoSDK.fromWasm(wasmStub); expect(sdk.isConnected).to.equal(true); + expect(sdk.wasm).to.equal(wasmStub); }); }); diff --git a/packages/js-evo-sdk/tests/unit/wallet.spec.mjs b/packages/js-evo-sdk/tests/unit/wallet.spec.mjs new file mode 100644 index 00000000000..b30694bff4f --- /dev/null +++ b/packages/js-evo-sdk/tests/unit/wallet.spec.mjs @@ -0,0 +1,35 @@ +import { expect } from 'chai'; +import { wallet } from '../../dist/sdk.js'; + +describe('wallet namespace', () => { + const exportedFns = [ + 'generateMnemonic', + 'validateMnemonic', + 'mnemonicToSeed', + 'deriveKeyFromSeedPhrase', + 'deriveKeyFromSeedWithPath', + 'deriveKeyFromSeedWithExtendedPath', + 'deriveDashpayContactKey', + 'derivationPathBip44Mainnet', + 'derivationPathBip44Testnet', + 'derivationPathDip9Mainnet', + 'derivationPathDip9Testnet', + 'derivationPathDip13Mainnet', + 'derivationPathDip13Testnet', + 'deriveChildPublicKey', + 'xprvToXpub', + 'generateKeyPair', + 'generateKeyPairs', + 'keyPairFromWif', + 'keyPairFromHex', + 'pubkeyToAddress', + 'validateAddress', + 'signMessage', + ]; + + it('exposes the expected helper functions', () => { + exportedFns.forEach((fn) => { + expect(wallet).to.have.property(fn).that.is.a('function'); + }); + }); +});