diff --git a/packages/client-node/integration/Balance.ts b/packages/client-node/integration/Balance.ts index aa14cbac..d417aeb3 100644 --- a/packages/client-node/integration/Balance.ts +++ b/packages/client-node/integration/Balance.ts @@ -1,6 +1,5 @@ import { Numbers, CoinBalance, Lgnt } from "@logion/node-api"; import { BalanceState, waitFor } from "@logion/client"; -import { Duration } from "luxon"; import { State } from "./Utils.js"; @@ -11,21 +10,24 @@ export async function transfers(state: State) { const aliceClient = client.withCurrentAccount(alice.account) let aliceState = await aliceClient.balanceState(); - checkBalance(aliceState, "99.99k", "100.00k"); + let aliceSnapshot = takeSnapshot(aliceState); expect(aliceState.transactions.length).toBe(0); aliceState = await aliceState.transfer({ signer, amount: Lgnt.from(5000n), destination: requesterAccount, }); - checkBalance(aliceState, "94.99k", "95.00k"); + checkBalanceDelta(aliceState, "-4.99k", aliceSnapshot); aliceState = await waitFor({ - pollingParameters: { - period: Duration.fromMillis(1000), - maxRetries: 50, - }, producer: async state => state ? await state.refresh() : aliceState, - predicate: state => state.transactions.length === 2, + predicate: state => { + if (state.transactions.length > 0) { + const transaction = state.transactions[0]; + return transaction.pallet === "balances" && transaction.method === "transferKeepAlive" + } else { + return false; + } + } }); expect(aliceState.transactions[0].fees.inclusion).toBeGreaterThan(0); expect(aliceState.transactions[0].fees.storage).toBeUndefined(); @@ -35,6 +37,8 @@ export async function transfers(state: State) { const userClient = client.withCurrentAccount(requesterAccount) let userState = await userClient.balanceState(); + aliceSnapshot = takeSnapshot(await aliceState.refresh()); + checkBalance(userState, "5.00k"); userState = await userState.transfer({ signer, @@ -43,22 +47,39 @@ export async function transfers(state: State) { }); checkBalance(userState, "2.99k"); - // TODO: the balance of a LO is not stable as it increases with block rewards - // this integration test should be rewritten with regular users. - // // Alice checks her balance. - // aliceState = await aliceState.refresh(); - // checkBalance(aliceState, "97.00k"); // is sometimes 96.99k depending on block reward. + aliceState = await aliceState.refresh(); + checkBalanceDelta(aliceState, "2.00k", aliceSnapshot); } -export function checkBalance(balanceState: BalanceState, ...expectedValues: string[]) { +export function checkBalance(balanceState: BalanceState, expectedValue: string) { const balance = balanceState.balances[0]; - checkCoinBalance(balance, ...expectedValues); + checkCoinBalance(balance, expectedValue); +} + +export function takeSnapshot(balanceState: BalanceState): CoinBalance { + return balanceState.balances[0]; +} + +export function checkBalanceDelta(current: BalanceState, expectedDelta: string, previous: CoinBalance) { + checkCoinBalanceDelta(takeSnapshot(current), expectedDelta, previous); +} + +export function checkCoinBalanceDelta(current: CoinBalance, expectedDelta: string, previous: CoinBalance) { + expect(current.coin).toEqual(previous.coin); + const delta: CoinBalance = { + coin: current.coin, + available: current.available.subtract(previous.available), + reserved: current.reserved.subtract(previous.reserved), + total: current.total.subtract(previous.total), + level: current.level - previous.level, + } + checkCoinBalance(delta, expectedDelta); } -export function checkCoinBalance(balance: CoinBalance, ...expectedValues: string[]) { +export function checkCoinBalance(balance: CoinBalance, expectedValue: string) { const formatted = formatBalance(balance); - expect(expectedValues).toContain(formatted) + expect(expectedValue).toEqual(formatted) } export function formatBalance(balance: CoinBalance): string { diff --git a/packages/client-node/integration/Main.spec.ts b/packages/client-node/integration/Main.spec.ts index f955094d..063ac6d0 100644 --- a/packages/client-node/integration/Main.spec.ts +++ b/packages/client-node/integration/Main.spec.ts @@ -1,4 +1,4 @@ -import { setupInitialState, State, tearDown, ALICE, BOB } from "./Utils.js"; +import { setupInitialState, State, tearDown } from "./Utils.js"; import { enablesProtection, requestValidIdentity } from "./Protection.js"; import { transferAndCannotPayFees, transfers, transferWithInsufficientFunds } from "./Balance.js"; import { providesVault } from "./Vault.js"; @@ -23,7 +23,7 @@ import { invitedContributors } from "./InvitedContributors.js"; describe("Logion SDK", () => { - jasmine.DEFAULT_TIMEOUT_INTERVAL = 600000; + jasmine.DEFAULT_TIMEOUT_INTERVAL = 1200000; let state: State; diff --git a/packages/client-node/integration/Protection.ts b/packages/client-node/integration/Protection.ts index f7076f41..a795be37 100644 --- a/packages/client-node/integration/Protection.ts +++ b/packages/client-node/integration/Protection.ts @@ -11,6 +11,7 @@ import { import { initAccountBalance, State } from "./Utils.js"; import { ClosedLoc } from "@logion/client/dist/Loc"; import { LegalOfficerClass } from "@logion/client/dist/Types"; +import debugLog = jasmine.debugLog; export interface IdentityLocs { alice: UUID, @@ -36,7 +37,7 @@ async function activateProtection(state: State, identityLocs: IdentityLocs): Pro const authenticatedClient = client.withCurrentAccount(requesterAccount); - console.log("Requesting protection") + debugLog("Requesting protection") const current = await authenticatedClient.protectionState(); expect(current).toBeInstanceOf(NoProtection); @@ -57,7 +58,7 @@ async function activateProtection(state: State, identityLocs: IdentityLocs): Pro async function createsIdentityLoc(state: State, account: ValidAccountId, legalOfficer: LegalOfficerClass): Promise { const { client, signer } = state; - console.log("Setting balance of %s", account.address) + debugLog(`Setting balance of ${ account.address }`) await initAccountBalance(state, account); const authenticatedClient = client.withCurrentAccount(account); diff --git a/packages/client-node/integration/Recovery.ts b/packages/client-node/integration/Recovery.ts index af423c7a..9c170b63 100644 --- a/packages/client-node/integration/Recovery.ts +++ b/packages/client-node/integration/Recovery.ts @@ -17,13 +17,14 @@ import { import { IdentityLocs } from "./Protection.js"; import { aliceAcceptsTransfer } from "./Vault.js"; import { initAccountBalance, NEW_ADDRESS, REQUESTER_ADDRESS, State } from "./Utils.js"; +import debugLog = jasmine.debugLog; export async function requestRecoveryAndCancel(state: State, identityLocs: IdentityLocs) { const { client, signer, alice, charlie, newAccount } = state; const pending = await requestRecovery(state, identityLocs) as PendingProtection; - console.log("LO's - Alice and Charlie Rejecting") + debugLog("LO's - Alice and Charlie Rejecting") await rejectRequest(client, signer, charlie, newAccount, "Your protection request is not complete"); await rejectRequest(client, signer, alice, newAccount, "Some info is missing"); @@ -45,7 +46,7 @@ export async function rejectRequest( const response = await axios.put("/api/protection-request", { legalOfficerAddress: legalOfficer.account.address, statuses: [ "PENDING" ], - requester: requester.address, + requesterAddress: requester.address, }); const request: ProtectionRequest = response.data.requests[0]; @@ -66,7 +67,7 @@ export async function acceptRequest( const response = await axios.put("/api/protection-request", { legalOfficerAddress: legalOfficer.account.address, statuses: [ "PENDING" ], - requesterAddress: requester + requesterAddress: requester.address, }); const request: ProtectionRequest = response.data.requests[0]; @@ -127,23 +128,23 @@ export async function requestRecoveryWithResubmit(state: State, identityLocs: Id const requested = await requestRecovery(state, identityLocs); - console.log("LO's - Alice Rejecting") + debugLog("LO's - Alice Rejecting") await rejectRequest(client, signer, alice, newAccount, "for some reason"); - console.log("User resubmitting to Alice"); + debugLog("User resubmitting to Alice"); const rejected = await requested.refresh() as RejectedRecovery; const pending = await rejected.resubmit(alice); - console.log("LO's - Accepting and vouching") + debugLog("LO's - Accepting and vouching") await acceptRequestAndVouch(client.config, client, signer, alice, REQUESTER_ADDRESS, newAccount); await acceptRequestAndVouch(client.config, client, signer, charlie, REQUESTER_ADDRESS, newAccount); - console.log("Activating") + debugLog("Activating") const accepted = await pending.refresh() as AcceptedProtection; let pendingRecovery = await accepted.activate({ signer }) as PendingRecovery; pendingRecovery = await pendingRecovery.waitForFullyReady(); - console.log("Claiming") + debugLog("Claiming") await pendingRecovery.claimRecovery({ signer }); } @@ -152,7 +153,7 @@ export async function recoverLostVault(state: State) { const claimed = await getClaimedRecovery(state); - console.log("Transfer from recovered vault") + debugLog("Transfer from recovered vault") const newVault = await claimed.vaultState(); let recoveredVault = await claimed.recoveredVaultState(); recoveredVault = await recoveredVault.createVaultTransferRequest({ @@ -163,7 +164,7 @@ export async function recoverLostVault(state: State) { }); const pendingRequest = recoveredVault.pendingVaultTransferRequests[0]; - console.log("Alice accepts transfer from recovered vault") + debugLog("Alice accepts transfer from recovered vault") await aliceAcceptsTransfer(state, pendingRequest, claimed); } @@ -180,7 +181,7 @@ export async function recoverLostAccount(state: State) { const claimed = await getClaimedRecovery(state); - console.log("Transfer from recovered account") + debugLog("Transfer from recovered account") const recoveredBalance = await claimed.recoveredBalanceState(); await recoveredBalance.transferAll({ signer, @@ -199,7 +200,7 @@ async function requestRecovery(state: State, identityLocs: IdentityLocs): Promis const current = await authenticatedClient.protectionState(); expect(current).toBeInstanceOf(NoProtection); if(current instanceof NoProtection) { - console.log("Requesting recovery") + debugLog("Requesting recovery") return await current.requestRecovery({ payload: { recoveredAccount: requesterAccount, diff --git a/packages/client/src/Polling.ts b/packages/client/src/Polling.ts index 8bd56e61..9bca7e79 100644 --- a/packages/client/src/Polling.ts +++ b/packages/client/src/Polling.ts @@ -13,7 +13,7 @@ export interface WaitForParameters { export const DEFAULT_POLLING_PARAMETERS: PollingParameters = { period: Duration.fromMillis(1000), - maxRetries: 20, + maxRetries: 40, }; export function waitFor(params: WaitForParameters): Promise {