@qubic.ts/sdk 0.1.0
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/package.json +38 -0
- package/src/assets.test.ts +114 -0
- package/src/assets.ts +175 -0
- package/src/bob/client.test.ts +109 -0
- package/src/bob/client.ts +393 -0
- package/src/bob/log-stream.test.ts +55 -0
- package/src/bob/log-stream.ts +241 -0
- package/src/browser.ts +43 -0
- package/src/contracts.test.ts +90 -0
- package/src/contracts.ts +140 -0
- package/src/errors.ts +15 -0
- package/src/http.ts +1 -0
- package/src/index.ts +141 -0
- package/src/node.ts +1 -0
- package/src/retry.ts +61 -0
- package/src/rpc/client.test.ts +322 -0
- package/src/rpc/client.ts +688 -0
- package/src/sdk.test.ts +34 -0
- package/src/sdk.ts +113 -0
- package/src/tick.test.ts +69 -0
- package/src/tick.ts +47 -0
- package/src/transactions.queue.test.ts +102 -0
- package/src/transactions.test.ts +149 -0
- package/src/transactions.ts +234 -0
- package/src/transfers.test.ts +59 -0
- package/src/transfers.ts +132 -0
- package/src/tx/confirm.test.ts +149 -0
- package/src/tx/confirm.ts +147 -0
- package/src/tx/tx-queue.test.ts +146 -0
- package/src/tx/tx-queue.ts +214 -0
- package/src/tx/tx.ts +36 -0
- package/src/vault/types.ts +131 -0
- package/src/vault-browser.test.ts +77 -0
- package/src/vault-browser.ts +449 -0
- package/src/vault-cli.test.ts +63 -0
- package/src/vault-cli.ts +123 -0
- package/src/vault.test.ts +97 -0
- package/src/vault.ts +439 -0
package/src/sdk.test.ts
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { describe, expect, it } from "bun:test";
|
|
2
|
+
import { createSdk } from "./sdk.js";
|
|
3
|
+
|
|
4
|
+
describe("sdk scaffold", () => {
|
|
5
|
+
it("creates a sdk object", () => {
|
|
6
|
+
const sdk = createSdk();
|
|
7
|
+
expect(sdk).toHaveProperty("rpc");
|
|
8
|
+
expect(sdk).toHaveProperty("tx");
|
|
9
|
+
expect(sdk).toHaveProperty("txQueue");
|
|
10
|
+
expect(sdk).toHaveProperty("tick");
|
|
11
|
+
expect(sdk).toHaveProperty("transactions");
|
|
12
|
+
expect(sdk).toHaveProperty("transfers");
|
|
13
|
+
expect(sdk).toHaveProperty("contracts");
|
|
14
|
+
expect(sdk).toHaveProperty("assets");
|
|
15
|
+
expect(sdk).toHaveProperty("bob");
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
it("honors txQueue disabled and wires optional assets helper", async () => {
|
|
19
|
+
const sdk = createSdk({
|
|
20
|
+
txQueue: { enabled: false },
|
|
21
|
+
assets: {
|
|
22
|
+
requestAssets: async () => [new Uint8Array(56)],
|
|
23
|
+
},
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
expect(sdk.txQueue).toBeUndefined();
|
|
27
|
+
expect(sdk.assets).toBeDefined();
|
|
28
|
+
await expect(
|
|
29
|
+
sdk.assets?.listByUniverseIndex({
|
|
30
|
+
universeIndex: 1,
|
|
31
|
+
}),
|
|
32
|
+
).resolves.toBeDefined();
|
|
33
|
+
});
|
|
34
|
+
});
|
package/src/sdk.ts
ADDED
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { createAssetsHelpers } from "./assets.js";
|
|
2
|
+
import { createBobClient } from "./bob/client.js";
|
|
3
|
+
import { createContractHelpers } from "./contracts.js";
|
|
4
|
+
import type { FetchLike } from "./http.js";
|
|
5
|
+
import type { RetryConfig } from "./retry.js";
|
|
6
|
+
import { createRpcClient } from "./rpc/client.js";
|
|
7
|
+
import { createTickHelpers } from "./tick.js";
|
|
8
|
+
import { createTransactionHelpers } from "./transactions.js";
|
|
9
|
+
import { createTransferHelpers } from "./transfers.js";
|
|
10
|
+
import { createTxConfirmationHelpers } from "./tx/confirm.js";
|
|
11
|
+
import { createTxHelpers } from "./tx/tx.js";
|
|
12
|
+
import type { TxQueuePolicy } from "./tx/tx-queue.js";
|
|
13
|
+
import { TxQueue } from "./tx/tx-queue.js";
|
|
14
|
+
import type { SeedVault } from "./vault/types.js";
|
|
15
|
+
|
|
16
|
+
export type SdkConfig = Readonly<{
|
|
17
|
+
/** Partner RPC base URL (recommended: `https://rpc.qubic.org`). */
|
|
18
|
+
baseUrl?: string;
|
|
19
|
+
/** Optional custom fetch implementation (for testing, instrumentation, etc). */
|
|
20
|
+
fetch?: FetchLike;
|
|
21
|
+
rpc?: Readonly<{
|
|
22
|
+
headers?: Readonly<Record<string, string>>;
|
|
23
|
+
retry?: RetryConfig;
|
|
24
|
+
}>;
|
|
25
|
+
tick?: Readonly<{
|
|
26
|
+
minOffset?: bigint | number;
|
|
27
|
+
defaultOffset?: bigint | number;
|
|
28
|
+
maxOffset?: bigint | number;
|
|
29
|
+
}>;
|
|
30
|
+
tx?: Readonly<{
|
|
31
|
+
confirmTimeoutMs?: number;
|
|
32
|
+
confirmPollIntervalMs?: number;
|
|
33
|
+
}>;
|
|
34
|
+
txQueue?: Readonly<{
|
|
35
|
+
enabled?: boolean;
|
|
36
|
+
policy?: TxQueuePolicy;
|
|
37
|
+
}>;
|
|
38
|
+
contracts?: Readonly<{
|
|
39
|
+
defaultRetries?: number;
|
|
40
|
+
defaultRetryDelayMs?: number;
|
|
41
|
+
}>;
|
|
42
|
+
assets?: Readonly<{
|
|
43
|
+
requestAssets?: (request: Uint8Array, signal?: AbortSignal) => Promise<readonly Uint8Array[]>;
|
|
44
|
+
}>;
|
|
45
|
+
vault?: SeedVault;
|
|
46
|
+
bob?: Readonly<{
|
|
47
|
+
baseUrl?: string;
|
|
48
|
+
fetch?: FetchLike;
|
|
49
|
+
headers?: Readonly<Record<string, string>>;
|
|
50
|
+
retry?: RetryConfig;
|
|
51
|
+
}>;
|
|
52
|
+
}>;
|
|
53
|
+
|
|
54
|
+
export function createSdk(config: SdkConfig = {}) {
|
|
55
|
+
const rpc = createRpcClient({
|
|
56
|
+
baseUrl: config.baseUrl,
|
|
57
|
+
fetch: config.fetch,
|
|
58
|
+
headers: config.rpc?.headers,
|
|
59
|
+
retry: config.rpc?.retry,
|
|
60
|
+
});
|
|
61
|
+
const tick = createTickHelpers({
|
|
62
|
+
rpc,
|
|
63
|
+
minOffset: config.tick?.minOffset,
|
|
64
|
+
defaultOffset: config.tick?.defaultOffset,
|
|
65
|
+
maxOffset: config.tick?.maxOffset,
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
const confirm = createTxConfirmationHelpers({
|
|
69
|
+
rpc,
|
|
70
|
+
defaultTimeoutMs: config.tx?.confirmTimeoutMs,
|
|
71
|
+
defaultPollIntervalMs: config.tx?.confirmPollIntervalMs,
|
|
72
|
+
});
|
|
73
|
+
const tx = createTxHelpers({ rpc, confirm });
|
|
74
|
+
const contracts = createContractHelpers({
|
|
75
|
+
rpc,
|
|
76
|
+
defaultRetries: config.contracts?.defaultRetries,
|
|
77
|
+
defaultRetryDelayMs: config.contracts?.defaultRetryDelayMs,
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
const txQueue =
|
|
81
|
+
config.txQueue?.enabled === false
|
|
82
|
+
? undefined
|
|
83
|
+
: new TxQueue({
|
|
84
|
+
policy: config.txQueue?.policy,
|
|
85
|
+
confirm: ({ txId, targetTick, signal }) =>
|
|
86
|
+
tx.waitForConfirmation({ txId, targetTick, signal }),
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
const transactions = createTransactionHelpers({ tick, tx, txQueue, vault: config.vault });
|
|
90
|
+
const transfers = createTransferHelpers({ transactions });
|
|
91
|
+
const assets = config.assets?.requestAssets
|
|
92
|
+
? createAssetsHelpers({ requestAssets: config.assets.requestAssets })
|
|
93
|
+
: undefined;
|
|
94
|
+
const bob = createBobClient({
|
|
95
|
+
baseUrl: config.bob?.baseUrl,
|
|
96
|
+
fetch: config.bob?.fetch ?? config.fetch,
|
|
97
|
+
headers: config.bob?.headers,
|
|
98
|
+
retry: config.bob?.retry,
|
|
99
|
+
});
|
|
100
|
+
const vault = config.vault;
|
|
101
|
+
return {
|
|
102
|
+
rpc,
|
|
103
|
+
tick,
|
|
104
|
+
tx,
|
|
105
|
+
txQueue,
|
|
106
|
+
transactions,
|
|
107
|
+
transfers,
|
|
108
|
+
contracts,
|
|
109
|
+
assets,
|
|
110
|
+
vault,
|
|
111
|
+
bob,
|
|
112
|
+
} as const;
|
|
113
|
+
}
|
package/src/tick.test.ts
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { describe, expect, it } from "bun:test";
|
|
2
|
+
import type { RpcClient } from "./rpc/client.js";
|
|
3
|
+
import { createTickHelpers } from "./tick.js";
|
|
4
|
+
|
|
5
|
+
function createMockRpc(tick: bigint): RpcClient {
|
|
6
|
+
return {
|
|
7
|
+
live: {
|
|
8
|
+
async tickInfo() {
|
|
9
|
+
return { tick, duration: 0n, epoch: 0n, initialTick: 0n };
|
|
10
|
+
},
|
|
11
|
+
async balance() {
|
|
12
|
+
throw new Error("not implemented");
|
|
13
|
+
},
|
|
14
|
+
async broadcastTransaction() {
|
|
15
|
+
throw new Error("not implemented");
|
|
16
|
+
},
|
|
17
|
+
async querySmartContract() {
|
|
18
|
+
throw new Error("not implemented");
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
query: {
|
|
22
|
+
async getLastProcessedTick() {
|
|
23
|
+
throw new Error("not implemented");
|
|
24
|
+
},
|
|
25
|
+
async getTransactionByHash() {
|
|
26
|
+
throw new Error("not implemented");
|
|
27
|
+
},
|
|
28
|
+
async getTransactionsForIdentity() {
|
|
29
|
+
throw new Error("not implemented");
|
|
30
|
+
},
|
|
31
|
+
async *getTransactionsForIdentityPages() {
|
|
32
|
+
yield* [];
|
|
33
|
+
throw new Error("not implemented");
|
|
34
|
+
},
|
|
35
|
+
async getTransactionsForIdentityAll() {
|
|
36
|
+
throw new Error("not implemented");
|
|
37
|
+
},
|
|
38
|
+
async getTransactionsForTick() {
|
|
39
|
+
throw new Error("not implemented");
|
|
40
|
+
},
|
|
41
|
+
async getTickData() {
|
|
42
|
+
throw new Error("not implemented");
|
|
43
|
+
},
|
|
44
|
+
async getProcessedTickIntervals() {
|
|
45
|
+
throw new Error("not implemented");
|
|
46
|
+
},
|
|
47
|
+
async getComputorListsForEpoch() {
|
|
48
|
+
throw new Error("not implemented");
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
describe("tick helpers", () => {
|
|
55
|
+
it("uses default offset (15) with guardrails", async () => {
|
|
56
|
+
const tick = createTickHelpers({ rpc: createMockRpc(100n) });
|
|
57
|
+
await expect(tick.getSuggestedTargetTick()).resolves.toBe(115n);
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it("rejects offsets below minOffset", async () => {
|
|
61
|
+
const tick = createTickHelpers({ rpc: createMockRpc(0n), minOffset: 5, defaultOffset: 5 });
|
|
62
|
+
await expect(tick.getSuggestedTargetTick({ offset: 4 })).rejects.toBeInstanceOf(RangeError);
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
it("rejects offsets above maxOffset", async () => {
|
|
66
|
+
const tick = createTickHelpers({ rpc: createMockRpc(0n), maxOffset: 10, defaultOffset: 10 });
|
|
67
|
+
await expect(tick.getSuggestedTargetTick({ offset: 11 })).rejects.toBeInstanceOf(RangeError);
|
|
68
|
+
});
|
|
69
|
+
});
|
package/src/tick.ts
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type { RpcClient } from "./rpc/client.js";
|
|
2
|
+
|
|
3
|
+
export type TickHelpersConfig = Readonly<{
|
|
4
|
+
rpc: RpcClient;
|
|
5
|
+
minOffset?: bigint | number;
|
|
6
|
+
defaultOffset?: bigint | number;
|
|
7
|
+
maxOffset?: bigint | number;
|
|
8
|
+
}>;
|
|
9
|
+
|
|
10
|
+
export type SuggestedTargetTickInput = Readonly<{ offset?: bigint | number }>;
|
|
11
|
+
|
|
12
|
+
export type TickHelpers = Readonly<{
|
|
13
|
+
getSuggestedTargetTick(input?: SuggestedTargetTickInput): Promise<bigint>;
|
|
14
|
+
}>;
|
|
15
|
+
|
|
16
|
+
export function createTickHelpers(config: TickHelpersConfig): TickHelpers {
|
|
17
|
+
const minOffset = toBigint(config.minOffset ?? 5);
|
|
18
|
+
const defaultOffset = toBigint(config.defaultOffset ?? 15);
|
|
19
|
+
const maxOffset = toBigint(config.maxOffset ?? 300);
|
|
20
|
+
|
|
21
|
+
if (minOffset < 0n) throw new RangeError("minOffset must be >= 0");
|
|
22
|
+
if (defaultOffset < 0n) throw new RangeError("defaultOffset must be >= 0");
|
|
23
|
+
if (maxOffset < 0n) throw new RangeError("maxOffset must be >= 0");
|
|
24
|
+
if (minOffset > maxOffset) throw new RangeError("minOffset must be <= maxOffset");
|
|
25
|
+
|
|
26
|
+
return {
|
|
27
|
+
async getSuggestedTargetTick(input: SuggestedTargetTickInput = {}): Promise<bigint> {
|
|
28
|
+
const offset = toBigint(input.offset ?? defaultOffset);
|
|
29
|
+
if (offset < minOffset) {
|
|
30
|
+
throw new RangeError(`offset must be >= ${minOffset}`);
|
|
31
|
+
}
|
|
32
|
+
if (offset > maxOffset) {
|
|
33
|
+
throw new RangeError(`offset must be <= ${maxOffset}`);
|
|
34
|
+
}
|
|
35
|
+
const { tick } = await config.rpc.live.tickInfo();
|
|
36
|
+
return tick + offset;
|
|
37
|
+
},
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function toBigint(value: bigint | number): bigint {
|
|
42
|
+
if (typeof value === "bigint") return value;
|
|
43
|
+
if (!Number.isFinite(value) || !Number.isInteger(value)) {
|
|
44
|
+
throw new TypeError("Expected an integer");
|
|
45
|
+
}
|
|
46
|
+
return BigInt(value);
|
|
47
|
+
}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { describe, expect, it } from "bun:test";
|
|
2
|
+
import type { BroadcastTransactionResult } from "./rpc/client.js";
|
|
3
|
+
import { createTransactionHelpers } from "./transactions.js";
|
|
4
|
+
import type { TxHelpers } from "./tx/tx.js";
|
|
5
|
+
import { TxQueue } from "./tx/tx-queue.js";
|
|
6
|
+
|
|
7
|
+
function createDeferred<T>() {
|
|
8
|
+
let resolve!: (value: T) => void;
|
|
9
|
+
let reject!: (error: unknown) => void;
|
|
10
|
+
const promise = new Promise<T>((res, rej) => {
|
|
11
|
+
resolve = res;
|
|
12
|
+
reject = rej;
|
|
13
|
+
});
|
|
14
|
+
return { promise, resolve, reject } as const;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
describe("transactions (queued)", () => {
|
|
18
|
+
it("enforces one in-flight tx per source identity", async () => {
|
|
19
|
+
const confirmations = new Map<string, ReturnType<typeof createDeferred<void>>>();
|
|
20
|
+
const broadcastOrder: string[] = [];
|
|
21
|
+
|
|
22
|
+
const tx: TxHelpers = {
|
|
23
|
+
async broadcastSigned() {
|
|
24
|
+
const txId = `tx${broadcastOrder.length + 1}`;
|
|
25
|
+
broadcastOrder.push(txId);
|
|
26
|
+
confirmations.set(txId, createDeferred<void>());
|
|
27
|
+
const res: BroadcastTransactionResult = {
|
|
28
|
+
peersBroadcasted: 1,
|
|
29
|
+
encodedTransaction: "",
|
|
30
|
+
transactionId: txId,
|
|
31
|
+
};
|
|
32
|
+
return res;
|
|
33
|
+
},
|
|
34
|
+
async waitForConfirmation({ txId }) {
|
|
35
|
+
const d = confirmations.get(txId);
|
|
36
|
+
if (!d) throw new Error(`missing deferred for ${txId}`);
|
|
37
|
+
await d.promise;
|
|
38
|
+
},
|
|
39
|
+
async waitForConfirmedTransaction() {
|
|
40
|
+
throw new Error("not implemented");
|
|
41
|
+
},
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
const txQueue = new TxQueue({
|
|
45
|
+
confirm: ({ txId, targetTick, signal }) =>
|
|
46
|
+
tx.waitForConfirmation({ txId, targetTick, signal }),
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
const transactions = createTransactionHelpers({
|
|
50
|
+
tick: {
|
|
51
|
+
async getSuggestedTargetTick() {
|
|
52
|
+
return 100n;
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
tx,
|
|
56
|
+
txQueue,
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
const seed = "jvhbyzjinlyutyuhsweuxiwootqoevjqwqmdhjeohrytxjxidpbcfyg";
|
|
60
|
+
const toIdentity = "AFZPUAIYVPNUYGJRQVLUKOPPVLHAZQTGLYAAUUNBXFTVTAMSBKQBLEIEPCVJ";
|
|
61
|
+
|
|
62
|
+
const p1 = transactions.sendQueued({
|
|
63
|
+
fromSeed: seed,
|
|
64
|
+
toIdentity,
|
|
65
|
+
amount: 1n,
|
|
66
|
+
targetTick: 10n,
|
|
67
|
+
});
|
|
68
|
+
const p2 = transactions.sendQueued({
|
|
69
|
+
fromSeed: seed,
|
|
70
|
+
toIdentity,
|
|
71
|
+
amount: 1n,
|
|
72
|
+
targetTick: 11n,
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
await waitFor(() => broadcastOrder.length === 1);
|
|
76
|
+
expect(broadcastOrder).toEqual(["tx1"]);
|
|
77
|
+
|
|
78
|
+
mustGet(confirmations, "tx1").resolve();
|
|
79
|
+
const r1 = await p1;
|
|
80
|
+
expect(r1.networkTxId).toBe("tx1");
|
|
81
|
+
|
|
82
|
+
await waitFor(() => broadcastOrder.length === 2);
|
|
83
|
+
mustGet(confirmations, "tx2").resolve();
|
|
84
|
+
const r2 = await p2;
|
|
85
|
+
expect(r2.networkTxId).toBe("tx2");
|
|
86
|
+
expect(broadcastOrder).toEqual(["tx1", "tx2"]);
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
async function waitFor(condition: () => boolean, timeoutMs = 1000): Promise<void> {
|
|
91
|
+
const start = Date.now();
|
|
92
|
+
while (!condition()) {
|
|
93
|
+
if (Date.now() - start > timeoutMs) throw new Error("Timed out waiting for condition");
|
|
94
|
+
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function mustGet<K, V>(map: ReadonlyMap<K, V>, key: K): V {
|
|
99
|
+
const value = map.get(key);
|
|
100
|
+
if (!value) throw new Error(`Missing key: ${String(key)}`);
|
|
101
|
+
return value;
|
|
102
|
+
}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import { describe, expect, it } from "bun:test";
|
|
2
|
+
import {
|
|
3
|
+
buildSignedTransaction,
|
|
4
|
+
privateKeyFromSeed,
|
|
5
|
+
publicKeyFromIdentity,
|
|
6
|
+
publicKeyFromSeed,
|
|
7
|
+
transactionId,
|
|
8
|
+
} from "@qubic.ts/core";
|
|
9
|
+
import type { TickHelpers } from "./tick.js";
|
|
10
|
+
import { createTransactionHelpers } from "./transactions.js";
|
|
11
|
+
import type { TxHelpers } from "./tx/tx.js";
|
|
12
|
+
|
|
13
|
+
describe("transactions", () => {
|
|
14
|
+
it("builds the same signed tx as core (generic inputType + bytes)", async () => {
|
|
15
|
+
const seed = "jvhbyzjinlyutyuhsweuxiwootqoevjqwqmdhjeohrytxjxidpbcfyg";
|
|
16
|
+
const toIdentity = "AFZPUAIYVPNUYGJRQVLUKOPPVLHAZQTGLYAAUUNBXFTVTAMSBKQBLEIEPCVJ";
|
|
17
|
+
const targetTick = 12345n;
|
|
18
|
+
const inputType = 7;
|
|
19
|
+
const inputBytes = new Uint8Array([1, 2, 3, 4]);
|
|
20
|
+
|
|
21
|
+
const tick: TickHelpers = {
|
|
22
|
+
async getSuggestedTargetTick() {
|
|
23
|
+
return 999n;
|
|
24
|
+
},
|
|
25
|
+
};
|
|
26
|
+
const tx: TxHelpers = {
|
|
27
|
+
async broadcastSigned() {
|
|
28
|
+
throw new Error("not used");
|
|
29
|
+
},
|
|
30
|
+
async waitForConfirmation() {
|
|
31
|
+
throw new Error("not used");
|
|
32
|
+
},
|
|
33
|
+
async waitForConfirmedTransaction() {
|
|
34
|
+
throw new Error("not used");
|
|
35
|
+
},
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
const transactions = createTransactionHelpers({ tick, tx });
|
|
39
|
+
const built = await transactions.buildSigned({
|
|
40
|
+
fromSeed: seed,
|
|
41
|
+
toIdentity,
|
|
42
|
+
amount: 1n,
|
|
43
|
+
targetTick,
|
|
44
|
+
inputType,
|
|
45
|
+
inputBytes,
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
const sourcePublicKey32 = await publicKeyFromSeed(seed);
|
|
49
|
+
const destinationPublicKey32 = publicKeyFromIdentity(toIdentity);
|
|
50
|
+
const secretKey32 = await privateKeyFromSeed(seed);
|
|
51
|
+
const expected = await buildSignedTransaction(
|
|
52
|
+
{
|
|
53
|
+
sourcePublicKey32,
|
|
54
|
+
destinationPublicKey32,
|
|
55
|
+
amount: 1n,
|
|
56
|
+
tick: 12345,
|
|
57
|
+
inputType,
|
|
58
|
+
inputBytes,
|
|
59
|
+
},
|
|
60
|
+
secretKey32,
|
|
61
|
+
);
|
|
62
|
+
const expectedId = await transactionId(expected);
|
|
63
|
+
|
|
64
|
+
expect(built.targetTick).toBe(targetTick);
|
|
65
|
+
expect(built.txBytes).toEqual(expected);
|
|
66
|
+
expect(built.txId).toBe(expectedId);
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
it("accepts fromVault source inputs", async () => {
|
|
70
|
+
const seed = "jvhbyzjinlyutyuhsweuxiwootqoevjqwqmdhjeohrytxjxidpbcfyg";
|
|
71
|
+
const toIdentity = "AFZPUAIYVPNUYGJRQVLUKOPPVLHAZQTGLYAAUUNBXFTVTAMSBKQBLEIEPCVJ";
|
|
72
|
+
|
|
73
|
+
const tick: TickHelpers = {
|
|
74
|
+
async getSuggestedTargetTick() {
|
|
75
|
+
return 123n;
|
|
76
|
+
},
|
|
77
|
+
};
|
|
78
|
+
const tx: TxHelpers = {
|
|
79
|
+
async broadcastSigned() {
|
|
80
|
+
throw new Error("not used");
|
|
81
|
+
},
|
|
82
|
+
async waitForConfirmation() {
|
|
83
|
+
throw new Error("not used");
|
|
84
|
+
},
|
|
85
|
+
async waitForConfirmedTransaction() {
|
|
86
|
+
throw new Error("not used");
|
|
87
|
+
},
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
const transactions = createTransactionHelpers({
|
|
91
|
+
tick,
|
|
92
|
+
tx,
|
|
93
|
+
vault: {
|
|
94
|
+
path: "vault.json",
|
|
95
|
+
list() {
|
|
96
|
+
return [];
|
|
97
|
+
},
|
|
98
|
+
getEntry() {
|
|
99
|
+
throw new Error("not used");
|
|
100
|
+
},
|
|
101
|
+
getIdentity() {
|
|
102
|
+
return "IDENTITY";
|
|
103
|
+
},
|
|
104
|
+
signer() {
|
|
105
|
+
return { fromVault: "main" };
|
|
106
|
+
},
|
|
107
|
+
async getSeed() {
|
|
108
|
+
return seed;
|
|
109
|
+
},
|
|
110
|
+
async addSeed() {
|
|
111
|
+
throw new Error("not used");
|
|
112
|
+
},
|
|
113
|
+
async remove() {
|
|
114
|
+
throw new Error("not used");
|
|
115
|
+
},
|
|
116
|
+
async rotatePassphrase() {
|
|
117
|
+
throw new Error("not used");
|
|
118
|
+
},
|
|
119
|
+
exportEncrypted() {
|
|
120
|
+
throw new Error("not used");
|
|
121
|
+
},
|
|
122
|
+
exportJson() {
|
|
123
|
+
throw new Error("not used");
|
|
124
|
+
},
|
|
125
|
+
async importEncrypted() {
|
|
126
|
+
throw new Error("not used");
|
|
127
|
+
},
|
|
128
|
+
async getSeedSource() {
|
|
129
|
+
return { fromSeed: seed };
|
|
130
|
+
},
|
|
131
|
+
async save() {
|
|
132
|
+
throw new Error("not used");
|
|
133
|
+
},
|
|
134
|
+
async close() {
|
|
135
|
+
throw new Error("not used");
|
|
136
|
+
},
|
|
137
|
+
},
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
const built = await transactions.buildSigned({
|
|
141
|
+
fromVault: "main",
|
|
142
|
+
toIdentity,
|
|
143
|
+
amount: 1n,
|
|
144
|
+
targetTick: 123n,
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
expect(built.txBytes.length).toBeGreaterThan(0);
|
|
148
|
+
});
|
|
149
|
+
});
|