@stellar/typescript-wallet-sdk 2.0.0 → 3.0.0-beta.1779920488639
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.MD +7 -0
- package/lib/bundle.js +1630 -1721
- package/lib/bundle.js.map +1 -1
- package/lib/bundle_browser.js +70 -36
- package/lib/bundle_browser.js.map +1 -1
- package/lib/walletSdk/Exceptions/index.d.ts +3 -0
- package/package.json +3 -3
- package/src/walletSdk/Auth/index.ts +21 -8
- package/src/walletSdk/Exceptions/index.ts +9 -0
- package/src/walletSdk/Horizon/Stellar.ts +32 -12
- package/test/auth.test.ts +104 -1
- package/test/stellar.test.ts +121 -1
- package/test/wallet.test.ts +9 -8
|
@@ -133,6 +133,9 @@ export declare class SigningKeypairMissingSecretError extends Error {
|
|
|
133
133
|
export declare class DefaultSignerDomainAccountError extends Error {
|
|
134
134
|
constructor();
|
|
135
135
|
}
|
|
136
|
+
export declare class DomainSigningModifiedError extends Error {
|
|
137
|
+
constructor();
|
|
138
|
+
}
|
|
136
139
|
export declare class AuthHeaderSigningKeypairRequiredError extends Error {
|
|
137
140
|
constructor();
|
|
138
141
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stellar/typescript-wallet-sdk",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.0.0-beta.1779920488639",
|
|
4
4
|
"engines": {
|
|
5
5
|
"node": ">=20"
|
|
6
6
|
},
|
|
@@ -47,7 +47,7 @@
|
|
|
47
47
|
"dependencies": {
|
|
48
48
|
"@stablelib/base64": "^2.0.0",
|
|
49
49
|
"@stablelib/utf8": "^2.0.0",
|
|
50
|
-
"@stellar/stellar-sdk": "
|
|
50
|
+
"@stellar/stellar-sdk": "15.0.1",
|
|
51
51
|
"axios": "^1.4.0",
|
|
52
52
|
"base64url": "^3.0.1",
|
|
53
53
|
"https-browserify": "^1.0.0",
|
|
@@ -75,4 +75,4 @@
|
|
|
75
75
|
"example:sep24": "ts-node examples/sep24/sep24.ts",
|
|
76
76
|
"example:sep12": "ts-node examples/sep12/sep12.ts"
|
|
77
77
|
}
|
|
78
|
-
}
|
|
78
|
+
}
|
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
ExpiredTokenError,
|
|
13
13
|
ChallengeValidationFailedError,
|
|
14
14
|
NetworkPassphraseMismatchError,
|
|
15
|
+
DomainSigningModifiedError,
|
|
15
16
|
} from "../Exceptions";
|
|
16
17
|
import {
|
|
17
18
|
AuthenticateParams,
|
|
@@ -189,15 +190,27 @@ export class Sep10 {
|
|
|
189
190
|
networkPassphrase,
|
|
190
191
|
) as Transaction;
|
|
191
192
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
193
|
+
const hasClientDomain = transaction.operations.some(
|
|
194
|
+
(op) => op.type === "manageData" && op.name === "client_domain",
|
|
195
|
+
);
|
|
196
|
+
|
|
197
|
+
if (hasClientDomain) {
|
|
198
|
+
const originalHash = transaction.hash();
|
|
199
|
+
const returned = await walletSigner.signWithDomainAccount({
|
|
200
|
+
transactionXDR: challengeResponse.transaction,
|
|
201
|
+
networkPassphrase,
|
|
202
|
+
accountKp,
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
// Transaction.hash() covers the envelope body but excludes signatures, so
|
|
206
|
+
// a domain signer that only appends its signature preserves the hash. Any
|
|
207
|
+
// change to the operations, source account, memo, or other body fields
|
|
208
|
+
// changes the hash and is rejected here.
|
|
209
|
+
if (!returned.hash().equals(originalHash)) {
|
|
210
|
+
throw new DomainSigningModifiedError();
|
|
200
211
|
}
|
|
212
|
+
|
|
213
|
+
transaction = returned;
|
|
201
214
|
}
|
|
202
215
|
|
|
203
216
|
walletSigner.signWithClientAccount({ transaction, accountKp });
|
|
@@ -354,6 +354,15 @@ export class DefaultSignerDomainAccountError extends Error {
|
|
|
354
354
|
}
|
|
355
355
|
}
|
|
356
356
|
|
|
357
|
+
export class DomainSigningModifiedError extends Error {
|
|
358
|
+
constructor() {
|
|
359
|
+
super(
|
|
360
|
+
"Domain signer returned a transaction whose body differs from the original challenge. Only the client_domain signature should be added.",
|
|
361
|
+
);
|
|
362
|
+
Object.setPrototypeOf(this, DomainSigningModifiedError.prototype);
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
|
|
357
366
|
export class AuthHeaderSigningKeypairRequiredError extends Error {
|
|
358
367
|
constructor() {
|
|
359
368
|
super("Must be SigningKeypair to sign auth header");
|
|
@@ -24,6 +24,13 @@ import {
|
|
|
24
24
|
import { getResultCode } from "../Utils/getResultCode";
|
|
25
25
|
import { SigningKeypair } from "./Account";
|
|
26
26
|
|
|
27
|
+
const SUBMIT_504_MAX_RETRIES = 5;
|
|
28
|
+
const SUBMIT_504_BASE_DELAY_MS = 1000;
|
|
29
|
+
const SUBMIT_504_MAX_DELAY_MS = 30000;
|
|
30
|
+
|
|
31
|
+
const sleep = (ms: number) =>
|
|
32
|
+
new Promise<void>((resolve) => setTimeout(resolve, ms));
|
|
33
|
+
|
|
27
34
|
/**
|
|
28
35
|
* Interaction with the Stellar Network.
|
|
29
36
|
* Do not create this object directly, use the Wallet class.
|
|
@@ -127,21 +134,33 @@ export class Stellar {
|
|
|
127
134
|
async submitTransaction(
|
|
128
135
|
signedTransaction: Transaction | FeeBumpTransaction,
|
|
129
136
|
): Promise<boolean> {
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
137
|
+
let lastError: unknown;
|
|
138
|
+
for (let attempt = 0; attempt <= SUBMIT_504_MAX_RETRIES; attempt++) {
|
|
139
|
+
try {
|
|
140
|
+
const response = await this.server.submitTransaction(signedTransaction);
|
|
141
|
+
if (!response.successful) {
|
|
142
|
+
throw new TransactionSubmitFailedError(response);
|
|
143
|
+
}
|
|
144
|
+
return true;
|
|
145
|
+
} catch (e) {
|
|
146
|
+
if (e?.response?.status !== 504) {
|
|
147
|
+
throw e;
|
|
148
|
+
}
|
|
149
|
+
lastError = e;
|
|
150
|
+
if (attempt === SUBMIT_504_MAX_RETRIES) {
|
|
151
|
+
break;
|
|
152
|
+
}
|
|
139
153
|
// https://developers.stellar.org/api/errors/http-status-codes/horizon-specific/timeout
|
|
140
154
|
// https://developers.stellar.org/docs/encyclopedia/error-handling#timeouts
|
|
141
|
-
|
|
155
|
+
const cappedDelay = Math.min(
|
|
156
|
+
SUBMIT_504_BASE_DELAY_MS * 2 ** attempt,
|
|
157
|
+
SUBMIT_504_MAX_DELAY_MS,
|
|
158
|
+
);
|
|
159
|
+
const jitter = Math.random() * (cappedDelay / 2);
|
|
160
|
+
await sleep(cappedDelay + jitter);
|
|
142
161
|
}
|
|
143
|
-
throw e;
|
|
144
162
|
}
|
|
163
|
+
throw lastError;
|
|
145
164
|
}
|
|
146
165
|
|
|
147
166
|
/**
|
|
@@ -199,7 +218,7 @@ export class Stellar {
|
|
|
199
218
|
if (resultCode === "tx_too_late") {
|
|
200
219
|
const newFee = parseInt(transaction.fee) + baseFeeIncrease;
|
|
201
220
|
|
|
202
|
-
if (maxFee && newFee > maxFee) {
|
|
221
|
+
if (maxFee !== undefined && newFee > maxFee) {
|
|
203
222
|
throw new TransactionSubmitWithFeeIncreaseFailedError(maxFee, e);
|
|
204
223
|
}
|
|
205
224
|
|
|
@@ -211,6 +230,7 @@ export class Stellar {
|
|
|
211
230
|
signerFunction,
|
|
212
231
|
baseFee: newFee,
|
|
213
232
|
memo,
|
|
233
|
+
maxFee,
|
|
214
234
|
});
|
|
215
235
|
}
|
|
216
236
|
throw e;
|
package/test/auth.test.ts
CHANGED
|
@@ -16,7 +16,7 @@ import { randomBytes } from "crypto";
|
|
|
16
16
|
import axios from "axios";
|
|
17
17
|
import sinon from "sinon";
|
|
18
18
|
|
|
19
|
-
import { validateToken, Sep10 } from "../src/walletSdk/Auth";
|
|
19
|
+
import { validateToken, Sep10, type WalletSigner } from "../src/walletSdk/Auth";
|
|
20
20
|
import {
|
|
21
21
|
Config,
|
|
22
22
|
StellarConfiguration,
|
|
@@ -30,6 +30,7 @@ import {
|
|
|
30
30
|
ChallengeValidationFailedError,
|
|
31
31
|
NetworkPassphraseMismatchError,
|
|
32
32
|
MissingSigningKeyError,
|
|
33
|
+
DomainSigningModifiedError,
|
|
33
34
|
} from "../src/walletSdk/Exceptions";
|
|
34
35
|
|
|
35
36
|
const createToken = (payload: Record<string, unknown>): string => {
|
|
@@ -618,6 +619,108 @@ describe("Sep10 challenge validation", () => {
|
|
|
618
619
|
});
|
|
619
620
|
});
|
|
620
621
|
|
|
622
|
+
describe("client_domain signing integrity", () => {
|
|
623
|
+
const buildClientDomainChallenge = (clientKeypair: Keypair) => {
|
|
624
|
+
const clientDomainKeypair = Keypair.random();
|
|
625
|
+
return buildChallenge({
|
|
626
|
+
clientKeypair,
|
|
627
|
+
additionalOps: [
|
|
628
|
+
Operation.manageData({
|
|
629
|
+
name: "client_domain",
|
|
630
|
+
value: "wallet.example.com",
|
|
631
|
+
source: clientDomainKeypair.publicKey(),
|
|
632
|
+
}),
|
|
633
|
+
],
|
|
634
|
+
});
|
|
635
|
+
};
|
|
636
|
+
|
|
637
|
+
it("should accept when domain signer returns the same transaction with an appended signature", async () => {
|
|
638
|
+
const clientKeypair = Keypair.random();
|
|
639
|
+
const { xdr, serverKeypair } = buildClientDomainChallenge(clientKeypair);
|
|
640
|
+
|
|
641
|
+
const accountKp = SigningKeypair.fromSecret(clientKeypair.secret());
|
|
642
|
+
const token = createJwt(clientKeypair);
|
|
643
|
+
const { sep10 } = setupSep10({
|
|
644
|
+
serverSigningKey: serverKeypair.publicKey(),
|
|
645
|
+
challengeXdr: xdr,
|
|
646
|
+
token,
|
|
647
|
+
});
|
|
648
|
+
|
|
649
|
+
const walletSigner: WalletSigner = {
|
|
650
|
+
signWithClientAccount: ({ transaction, accountKp: kp }) => {
|
|
651
|
+
transaction.sign(kp.keypair);
|
|
652
|
+
return transaction;
|
|
653
|
+
},
|
|
654
|
+
// eslint-disable-next-line @typescript-eslint/require-await
|
|
655
|
+
signWithDomainAccount: async ({ transactionXDR }) => {
|
|
656
|
+
const tx = SdkTransactionBuilder.fromXDR(
|
|
657
|
+
transactionXDR,
|
|
658
|
+
networkPassphrase,
|
|
659
|
+
) as Transaction;
|
|
660
|
+
tx.sign(Keypair.random());
|
|
661
|
+
return tx;
|
|
662
|
+
},
|
|
663
|
+
};
|
|
664
|
+
|
|
665
|
+
const authToken = await sep10.authenticate({
|
|
666
|
+
accountKp,
|
|
667
|
+
clientDomain: "wallet.example.com",
|
|
668
|
+
walletSigner,
|
|
669
|
+
});
|
|
670
|
+
expect(authToken.account).toBe(clientKeypair.publicKey());
|
|
671
|
+
});
|
|
672
|
+
|
|
673
|
+
it("should reject when domain signer returns a transaction with a different body", async () => {
|
|
674
|
+
const clientKeypair = Keypair.random();
|
|
675
|
+
const { xdr, serverKeypair } = buildClientDomainChallenge(clientKeypair);
|
|
676
|
+
|
|
677
|
+
const accountKp = SigningKeypair.fromSecret(clientKeypair.secret());
|
|
678
|
+
const token = createJwt(clientKeypair);
|
|
679
|
+
const { sep10, postStub } = setupSep10({
|
|
680
|
+
serverSigningKey: serverKeypair.publicKey(),
|
|
681
|
+
challengeXdr: xdr,
|
|
682
|
+
token,
|
|
683
|
+
});
|
|
684
|
+
|
|
685
|
+
const differentSource = new Account(clientKeypair.publicKey(), "0");
|
|
686
|
+
const differentTx = new SdkTransactionBuilder(differentSource, {
|
|
687
|
+
fee: BASE_FEE,
|
|
688
|
+
networkPassphrase,
|
|
689
|
+
})
|
|
690
|
+
.addOperation(
|
|
691
|
+
Operation.payment({
|
|
692
|
+
destination: Keypair.random().publicKey(),
|
|
693
|
+
asset: Asset.native(),
|
|
694
|
+
amount: "100",
|
|
695
|
+
}),
|
|
696
|
+
)
|
|
697
|
+
.setTimeout(300)
|
|
698
|
+
.build();
|
|
699
|
+
|
|
700
|
+
const signWithClientAccountSpy = sinon.spy(
|
|
701
|
+
({ transaction, accountKp: kp }) => {
|
|
702
|
+
transaction.sign(kp.keypair);
|
|
703
|
+
return transaction;
|
|
704
|
+
},
|
|
705
|
+
);
|
|
706
|
+
const walletSigner: WalletSigner = {
|
|
707
|
+
signWithClientAccount: signWithClientAccountSpy,
|
|
708
|
+
// eslint-disable-next-line @typescript-eslint/require-await
|
|
709
|
+
signWithDomainAccount: async () => differentTx,
|
|
710
|
+
};
|
|
711
|
+
|
|
712
|
+
await expect(
|
|
713
|
+
sep10.authenticate({
|
|
714
|
+
accountKp,
|
|
715
|
+
clientDomain: "wallet.example.com",
|
|
716
|
+
walletSigner,
|
|
717
|
+
}),
|
|
718
|
+
).rejects.toThrow(DomainSigningModifiedError);
|
|
719
|
+
expect(signWithClientAccountSpy.notCalled).toBe(true);
|
|
720
|
+
expect(postStub.notCalled).toBe(true);
|
|
721
|
+
});
|
|
722
|
+
});
|
|
723
|
+
|
|
621
724
|
describe("network passphrase mismatch", () => {
|
|
622
725
|
it("should reject when server returns a different network passphrase", async () => {
|
|
623
726
|
const { xdr, serverKeypair, clientKeypair } = buildChallenge();
|
package/test/stellar.test.ts
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
Keypair,
|
|
3
|
+
Memo,
|
|
4
|
+
MemoText,
|
|
5
|
+
Horizon,
|
|
6
|
+
Transaction,
|
|
7
|
+
} from "@stellar/stellar-sdk";
|
|
2
8
|
import axios from "axios";
|
|
9
|
+
import sinon from "sinon";
|
|
3
10
|
|
|
4
11
|
import { Stellar, Wallet } from "../src";
|
|
5
12
|
import {
|
|
@@ -14,6 +21,7 @@ import {
|
|
|
14
21
|
} from "../src/walletSdk/Asset";
|
|
15
22
|
import { TransactionStatus, WithdrawTransaction } from "../src/walletSdk/Types";
|
|
16
23
|
import {
|
|
24
|
+
TransactionSubmitWithFeeIncreaseFailedError,
|
|
17
25
|
WithdrawalTxMissingDestinationError,
|
|
18
26
|
WithdrawalTxMissingMemoError,
|
|
19
27
|
WithdrawalTxNotPendingUserTransferStartError,
|
|
@@ -158,6 +166,51 @@ describe("Stellar", () => {
|
|
|
158
166
|
expect(txn.fee).toBe("200");
|
|
159
167
|
});
|
|
160
168
|
|
|
169
|
+
it("should enforce maxFee across multiple submitWithFeeIncrease retries", async () => {
|
|
170
|
+
const txTooLateRejection = {
|
|
171
|
+
response: {
|
|
172
|
+
status: 400,
|
|
173
|
+
statusText: "Bad Request",
|
|
174
|
+
data: {
|
|
175
|
+
extras: {
|
|
176
|
+
result_codes: { transaction: "tx_too_late" },
|
|
177
|
+
},
|
|
178
|
+
},
|
|
179
|
+
},
|
|
180
|
+
};
|
|
181
|
+
|
|
182
|
+
// Always reject with tx_too_late so the fee climbs on every retry. With the
|
|
183
|
+
// fix the maxFee cap is honored across all retries and submitWithFeeIncrease
|
|
184
|
+
// eventually throws; without it the cap is dropped after the first retry and
|
|
185
|
+
// the recursion never stops. Restore the spy in a finally block: a leaked
|
|
186
|
+
// mock on submitTransaction would turn the next test's real submission into
|
|
187
|
+
// a no-op.
|
|
188
|
+
const submitStub = jest
|
|
189
|
+
.spyOn(stellar, "submitTransaction")
|
|
190
|
+
.mockRejectedValue(txTooLateRejection);
|
|
191
|
+
|
|
192
|
+
const buildingFunction = (builder) =>
|
|
193
|
+
builder.transfer(kp.publicKey, new NativeAssetId(), "2");
|
|
194
|
+
|
|
195
|
+
try {
|
|
196
|
+
await expect(
|
|
197
|
+
stellar.submitWithFeeIncrease({
|
|
198
|
+
sourceAddress: kp,
|
|
199
|
+
timeout: 180,
|
|
200
|
+
baseFeeIncrease: 100,
|
|
201
|
+
buildingFunction,
|
|
202
|
+
baseFee: 100,
|
|
203
|
+
maxFee: 250,
|
|
204
|
+
}),
|
|
205
|
+
).rejects.toThrow(TransactionSubmitWithFeeIncreaseFailedError);
|
|
206
|
+
// The cap is enforced only after several retries, proving it survives
|
|
207
|
+
// past the first retry (the bug being fixed).
|
|
208
|
+
expect(submitStub.mock.calls.length).toBeGreaterThan(1);
|
|
209
|
+
} finally {
|
|
210
|
+
submitStub.mockRestore();
|
|
211
|
+
}
|
|
212
|
+
});
|
|
213
|
+
|
|
161
214
|
it("should add and remove asset support", async () => {
|
|
162
215
|
const asset = new IssuedAssetId(
|
|
163
216
|
"USDC",
|
|
@@ -202,6 +255,73 @@ describe("Stellar", () => {
|
|
|
202
255
|
expect(fee).toBeTruthy();
|
|
203
256
|
});
|
|
204
257
|
|
|
258
|
+
describe("submitTransaction 504 handling", () => {
|
|
259
|
+
let clock: sinon.SinonFakeTimers;
|
|
260
|
+
let randomStub: sinon.SinonStub;
|
|
261
|
+
|
|
262
|
+
beforeEach(() => {
|
|
263
|
+
clock = sinon.useFakeTimers();
|
|
264
|
+
// Zero jitter for deterministic test timing.
|
|
265
|
+
randomStub = sinon.stub(Math, "random").returns(0);
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
afterEach(() => {
|
|
269
|
+
clock.restore();
|
|
270
|
+
randomStub.restore();
|
|
271
|
+
jest.restoreAllMocks();
|
|
272
|
+
});
|
|
273
|
+
|
|
274
|
+
const make504 = () => ({ response: { status: 504 } });
|
|
275
|
+
|
|
276
|
+
it("retries once on 504 then returns on success", async () => {
|
|
277
|
+
const serverStub = jest
|
|
278
|
+
.spyOn(stellar.server, "submitTransaction")
|
|
279
|
+
.mockRejectedValueOnce(make504())
|
|
280
|
+
.mockResolvedValueOnce({ successful: true } as any);
|
|
281
|
+
|
|
282
|
+
const tx = {} as Transaction;
|
|
283
|
+
const promise = stellar.submitTransaction(tx);
|
|
284
|
+
|
|
285
|
+
// First retry waits SUBMIT_504_BASE_DELAY_MS = 1000ms (jitter stubbed to 0).
|
|
286
|
+
await clock.tickAsync(1000);
|
|
287
|
+
|
|
288
|
+
await expect(promise).resolves.toBe(true);
|
|
289
|
+
expect(serverStub).toHaveBeenCalledTimes(2);
|
|
290
|
+
});
|
|
291
|
+
|
|
292
|
+
it("rethrows immediately on a non-504 error", async () => {
|
|
293
|
+
const serverStub = jest
|
|
294
|
+
.spyOn(stellar.server, "submitTransaction")
|
|
295
|
+
.mockRejectedValueOnce({ response: { status: 500 } });
|
|
296
|
+
|
|
297
|
+
await expect(
|
|
298
|
+
stellar.submitTransaction({} as Transaction),
|
|
299
|
+
).rejects.toMatchObject({ response: { status: 500 } });
|
|
300
|
+
expect(serverStub).toHaveBeenCalledTimes(1);
|
|
301
|
+
});
|
|
302
|
+
|
|
303
|
+
it("gives up after the bounded number of retries and rethrows the last 504", async () => {
|
|
304
|
+
// SUBMIT_504_MAX_RETRIES = 5 → 1 initial + 5 retries = 6 total attempts.
|
|
305
|
+
const serverStub = jest
|
|
306
|
+
.spyOn(stellar.server, "submitTransaction")
|
|
307
|
+
.mockRejectedValue(make504());
|
|
308
|
+
|
|
309
|
+
const promise = stellar.submitTransaction({} as Transaction);
|
|
310
|
+
// Surface the rejection eagerly so an unhandled rejection doesn't crash
|
|
311
|
+
// the test runner mid-tick.
|
|
312
|
+
promise.catch(() => undefined);
|
|
313
|
+
|
|
314
|
+
// Sum of capped exponential delays with zero jitter:
|
|
315
|
+
// 1000 + 2000 + 4000 + 8000 + 16000 = 31000ms.
|
|
316
|
+
await clock.tickAsync(31000);
|
|
317
|
+
|
|
318
|
+
await expect(promise).rejects.toMatchObject({
|
|
319
|
+
response: { status: 504 },
|
|
320
|
+
});
|
|
321
|
+
expect(serverStub).toHaveBeenCalledTimes(6);
|
|
322
|
+
});
|
|
323
|
+
});
|
|
324
|
+
|
|
205
325
|
describe("TransactionBuilder/transferWithdrawalTransaction", () => {
|
|
206
326
|
it("should transfer withdrawal transaction", async () => {
|
|
207
327
|
const memoExamples = [
|
package/test/wallet.test.ts
CHANGED
|
@@ -339,14 +339,15 @@ describe("Anchor", () => {
|
|
|
339
339
|
expect(transactions.length === 2).toBeTruthy();
|
|
340
340
|
});
|
|
341
341
|
|
|
342
|
-
it("should
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
342
|
+
it("should pass through paging id to the server", async () => {
|
|
343
|
+
await expect(
|
|
344
|
+
anchor.sep24().getTransactionsForAsset({
|
|
345
|
+
authToken,
|
|
346
|
+
assetCode: "SRT",
|
|
347
|
+
lang: "en-US",
|
|
348
|
+
pagingId: "randomPagingId",
|
|
349
|
+
}),
|
|
350
|
+
).rejects.toThrow(ServerRequestFailedError);
|
|
350
351
|
});
|
|
351
352
|
|
|
352
353
|
describe("watchAllTransactions", () => {
|