@shunt-network/sdk 1.0.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/dist/clients/typescript/src/__tests__/instruction-parsers.test.d.ts +1 -0
- package/dist/clients/typescript/src/__tests__/voucher-numeric-safety.test.d.ts +1 -0
- package/dist/clients/typescript/src/__tests__/voucher-types.test-d.d.ts +1 -0
- package/dist/clients/typescript/src/generated/accounts/channel.d.ts +59 -0
- package/dist/clients/typescript/src/generated/accounts/index.d.ts +8 -0
- package/dist/clients/typescript/src/generated/errors/index.d.ts +8 -0
- package/dist/clients/typescript/src/generated/errors/paymentChannels.d.ts +84 -0
- package/dist/clients/typescript/src/generated/index.d.ts +13 -0
- package/dist/clients/typescript/src/generated/instructions/distribute.d.ts +90 -0
- package/dist/clients/typescript/src/generated/instructions/emitEvent.d.ts +42 -0
- package/dist/clients/typescript/src/generated/instructions/index.d.ts +17 -0
- package/dist/clients/typescript/src/generated/instructions/open.d.ts +100 -0
- package/dist/clients/typescript/src/generated/instructions/reclaim.d.ts +39 -0
- package/dist/clients/typescript/src/generated/instructions/requestClose.d.ts +39 -0
- package/dist/clients/typescript/src/generated/instructions/seal.d.ts +36 -0
- package/dist/clients/typescript/src/generated/instructions/settle.d.ts +39 -0
- package/dist/clients/typescript/src/generated/instructions/settleAndSeal.d.ts +47 -0
- package/dist/clients/typescript/src/generated/instructions/topUp.d.ts +56 -0
- package/dist/clients/typescript/src/generated/instructions/withdrawPayer.d.ts +51 -0
- package/dist/clients/typescript/src/generated/pdas/eventAuthority.d.ts +11 -0
- package/dist/clients/typescript/src/generated/pdas/index.d.ts +8 -0
- package/dist/clients/typescript/src/generated/programs/index.d.ts +8 -0
- package/dist/clients/typescript/src/generated/programs/paymentChannels.d.ts +80 -0
- package/dist/clients/typescript/src/generated/types/accountDiscriminator.d.ts +16 -0
- package/dist/clients/typescript/src/generated/types/channelStatus.d.ts +18 -0
- package/dist/clients/typescript/src/generated/types/distributeArgs.d.ts +18 -0
- package/dist/clients/typescript/src/generated/types/distributionEntry.d.ts +16 -0
- package/dist/clients/typescript/src/generated/types/index.d.ts +20 -0
- package/dist/clients/typescript/src/generated/types/openArgs.d.ts +26 -0
- package/dist/clients/typescript/src/generated/types/opened.d.ts +19 -0
- package/dist/clients/typescript/src/generated/types/payoutBeneficiary.d.ts +17 -0
- package/dist/clients/typescript/src/generated/types/payoutRedirected.d.ts +26 -0
- package/dist/clients/typescript/src/generated/types/redirectReason.d.ts +18 -0
- package/dist/clients/typescript/src/generated/types/settleAndSealArgs.d.ts +15 -0
- package/dist/clients/typescript/src/generated/types/settlementWatermarks.d.ts +19 -0
- package/dist/clients/typescript/src/generated/types/topUpArgs.d.ts +17 -0
- package/dist/clients/typescript/src/generated/types/voucherArgs.d.ts +23 -0
- package/dist/clients/typescript/src/index.d.ts +1 -0
- package/dist/clients/typescript/src/safe-codecs.d.ts +6 -0
- package/dist/clients/typescript/tsup.config.d.ts +2 -0
- package/dist/index.cjs +1399 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +1549 -0
- package/dist/sdk/channel.d.ts +10 -0
- package/dist/sdk/client.d.ts +31 -0
- package/dist/sdk/utils.d.ts +3 -0
- package/dist/sdk/voucher.d.ts +14 -0
- package/package.json +36 -0
- package/src/clients/typescript/package.json +32 -0
- package/src/clients/typescript/src/__tests__/instruction-parsers.test.ts +81 -0
- package/src/clients/typescript/src/__tests__/voucher-numeric-safety.test.ts +176 -0
- package/src/clients/typescript/src/__tests__/voucher-types.test-d.ts +8 -0
- package/src/clients/typescript/src/generated/accounts/channel.ts +192 -0
- package/src/clients/typescript/src/generated/accounts/index.ts +9 -0
- package/src/clients/typescript/src/generated/errors/index.ts +9 -0
- package/src/clients/typescript/src/generated/errors/paymentChannels.ts +251 -0
- package/src/clients/typescript/src/generated/index.ts +14 -0
- package/src/clients/typescript/src/generated/instructions/distribute.ts +517 -0
- package/src/clients/typescript/src/generated/instructions/emitEvent.ts +194 -0
- package/src/clients/typescript/src/generated/instructions/index.ts +18 -0
- package/src/clients/typescript/src/generated/instructions/open.ts +577 -0
- package/src/clients/typescript/src/generated/instructions/reclaim.ts +165 -0
- package/src/clients/typescript/src/generated/instructions/requestClose.ts +173 -0
- package/src/clients/typescript/src/generated/instructions/seal.ts +151 -0
- package/src/clients/typescript/src/generated/instructions/settle.ts +180 -0
- package/src/clients/typescript/src/generated/instructions/settleAndSeal.ts +224 -0
- package/src/clients/typescript/src/generated/instructions/topUp.ts +267 -0
- package/src/clients/typescript/src/generated/instructions/withdrawPayer.ts +246 -0
- package/src/clients/typescript/src/generated/pdas/eventAuthority.ts +26 -0
- package/src/clients/typescript/src/generated/pdas/index.ts +9 -0
- package/src/clients/typescript/src/generated/programs/index.ts +9 -0
- package/src/clients/typescript/src/generated/programs/paymentChannels.ts +366 -0
- package/src/clients/typescript/src/generated/types/accountDiscriminator.ts +41 -0
- package/src/clients/typescript/src/generated/types/channelStatus.ts +40 -0
- package/src/clients/typescript/src/generated/types/distributeArgs.ts +47 -0
- package/src/clients/typescript/src/generated/types/distributionEntry.ts +48 -0
- package/src/clients/typescript/src/generated/types/index.ts +21 -0
- package/src/clients/typescript/src/generated/types/openArgs.ts +70 -0
- package/src/clients/typescript/src/generated/types/opened.ts +42 -0
- package/src/clients/typescript/src/generated/types/payoutBeneficiary.ts +42 -0
- package/src/clients/typescript/src/generated/types/payoutRedirected.ts +76 -0
- package/src/clients/typescript/src/generated/types/redirectReason.ts +40 -0
- package/src/clients/typescript/src/generated/types/settleAndSealArgs.ts +39 -0
- package/src/clients/typescript/src/generated/types/settlementWatermarks.ts +48 -0
- package/src/clients/typescript/src/generated/types/topUpArgs.ts +33 -0
- package/src/clients/typescript/src/generated/types/voucherArgs.ts +68 -0
- package/src/clients/typescript/src/index.ts +1 -0
- package/src/clients/typescript/src/safe-codecs.ts +82 -0
- package/src/clients/typescript/tsconfig.json +11 -0
- package/src/clients/typescript/tsup.config.ts +9 -0
- package/src/index.ts +4 -0
- package/src/sdk/channel.ts +128 -0
- package/src/sdk/client.ts +22 -0
- package/src/sdk/utils.ts +29 -0
- package/src/sdk/voucher.ts +50 -0
- package/tsconfig.json +15 -0
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
// Drop-in replacement for @solana/kit's number codecs, wired in via
|
|
2
|
+
// codama's dependencyMap. Re-exports everything unchanged except the
|
|
3
|
+
// u64/u128/i64/i128 encoders, which reject unsafe-integer JS numbers
|
|
4
|
+
// at runtime and narrow the input type to plain `bigint`.
|
|
5
|
+
|
|
6
|
+
import {
|
|
7
|
+
type FixedSizeEncoder,
|
|
8
|
+
getI64Encoder as kitI64Encoder,
|
|
9
|
+
getI128Encoder as kitI128Encoder,
|
|
10
|
+
getU64Encoder as kitU64Encoder,
|
|
11
|
+
getU128Encoder as kitU128Encoder,
|
|
12
|
+
} from '@solana/kit';
|
|
13
|
+
|
|
14
|
+
export * from '@solana/kit';
|
|
15
|
+
|
|
16
|
+
const U64_MAX = 0xffffffffffffffffn;
|
|
17
|
+
const U128_MAX = 0xffffffffffffffffffffffffffffffffn;
|
|
18
|
+
const I64_MIN = -0x8000000000000000n;
|
|
19
|
+
const I64_MAX = 0x7fffffffffffffffn;
|
|
20
|
+
const I128_MIN = -0x80000000000000000000000000000000n;
|
|
21
|
+
const I128_MAX = 0x7fffffffffffffffffffffffffffffffn;
|
|
22
|
+
|
|
23
|
+
function coerce(label: string, value: bigint | number, min: bigint, max: bigint): bigint {
|
|
24
|
+
if (typeof value === 'bigint') {
|
|
25
|
+
if (value < min || value > max) {
|
|
26
|
+
throw new RangeError(`${label}: value ${value} out of range [${min}, ${max}]`);
|
|
27
|
+
}
|
|
28
|
+
return value;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (typeof value !== 'number') {
|
|
32
|
+
throw new TypeError(`${label}: expected bigint, got ${typeof value}`);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
if (!Number.isSafeInteger(value)) {
|
|
36
|
+
throw new TypeError(
|
|
37
|
+
`${label}: expected bigint; got number ${value}. ` +
|
|
38
|
+
'JS numbers above 2^53-1 round silently, pass BigInt(...) instead.',
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const bn = BigInt(value);
|
|
43
|
+
if (bn < min || bn > max) {
|
|
44
|
+
throw new RangeError(`${label}: value ${bn} out of range [${min}, ${max}]`);
|
|
45
|
+
}
|
|
46
|
+
return bn;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function guardEncoder<Size extends number>(
|
|
50
|
+
label: string,
|
|
51
|
+
inner: FixedSizeEncoder<bigint | number, Size>,
|
|
52
|
+
min: bigint,
|
|
53
|
+
max: bigint,
|
|
54
|
+
): FixedSizeEncoder<bigint, Size> {
|
|
55
|
+
// Spelled out instead of spreading `inner` so new upstream fields
|
|
56
|
+
// cause a type error rather than silently skipping the guard.
|
|
57
|
+
return {
|
|
58
|
+
fixedSize: inner.fixedSize,
|
|
59
|
+
write(value, bytes, offset) {
|
|
60
|
+
return inner.write(coerce(label, value as bigint | number, min, max), bytes, offset);
|
|
61
|
+
},
|
|
62
|
+
encode(value) {
|
|
63
|
+
return inner.encode(coerce(label, value as bigint | number, min, max));
|
|
64
|
+
},
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export function getU64Encoder(): FixedSizeEncoder<bigint, 8> {
|
|
69
|
+
return guardEncoder('u64', kitU64Encoder(), 0n, U64_MAX);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export function getU128Encoder(): FixedSizeEncoder<bigint, 16> {
|
|
73
|
+
return guardEncoder('u128', kitU128Encoder(), 0n, U128_MAX);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export function getI64Encoder(): FixedSizeEncoder<bigint, 8> {
|
|
77
|
+
return guardEncoder('i64', kitI64Encoder(), I64_MIN, I64_MAX);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export function getI128Encoder(): FixedSizeEncoder<bigint, 16> {
|
|
81
|
+
return guardEncoder('i128', kitI128Encoder(), I128_MIN, I128_MAX);
|
|
82
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import { SHUNT_TREASURY, devnet, type ShuntClient } from "./client.js";
|
|
2
|
+
import { address, getAddressEncoder, getU64Encoder, getProgramDerivedAddress, type Address } from "@solana/kit";
|
|
3
|
+
import { findAssociatedTokenPda, TOKEN_PROGRAM_ADDRESS, ASSOCIATED_TOKEN_PROGRAM_ADDRESS } from "@solana-program/token";
|
|
4
|
+
import { getOpenInstructionAsync } from '../clients/typescript/src/generated/instructions/open.js';
|
|
5
|
+
import { getTopUpInstruction } from '../clients/typescript/src/generated/instructions/topUp.js';
|
|
6
|
+
// import { getTopUpInstruction } from '../clients/typescript/dist/topUp.js';
|
|
7
|
+
import { sendInstructions } from "./utils.js";
|
|
8
|
+
|
|
9
|
+
const USDC_MAINNET = address("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v");
|
|
10
|
+
const USDC_DEVNET = address("4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU");
|
|
11
|
+
|
|
12
|
+
async function findChannelPda(
|
|
13
|
+
client: ShuntClient,
|
|
14
|
+
mint: Address,
|
|
15
|
+
salt: bigint,
|
|
16
|
+
openSlot: bigint
|
|
17
|
+
): Promise<Address> {
|
|
18
|
+
const addressEncoder = getAddressEncoder();
|
|
19
|
+
|
|
20
|
+
const u64Encoder = getU64Encoder();
|
|
21
|
+
|
|
22
|
+
const [pda] = await getProgramDerivedAddress({
|
|
23
|
+
programAddress: address("CHNLxYvVA28MJP9PrFuDXccuoGXAx7jBacfLEkahyGsX"),
|
|
24
|
+
seeds: [
|
|
25
|
+
new TextEncoder().encode("channel"),
|
|
26
|
+
addressEncoder.encode(client.payer.address),
|
|
27
|
+
addressEncoder.encode(address(SHUNT_TREASURY)),
|
|
28
|
+
addressEncoder.encode(mint),
|
|
29
|
+
addressEncoder.encode(client.payer.address),
|
|
30
|
+
u64Encoder.encode(salt),
|
|
31
|
+
u64Encoder.encode(openSlot),
|
|
32
|
+
],
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
return pda;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export async function openPaymentChannel(client: ShuntClient, depositAmount: bigint) {
|
|
39
|
+
const USDC_MINT = devnet ? USDC_DEVNET : USDC_MAINNET;
|
|
40
|
+
const salt = BigInt(Math.floor(Math.random() * 1_000_000_000));
|
|
41
|
+
const gracePeriod = 86400;
|
|
42
|
+
|
|
43
|
+
const currentSlot = await client.rpc.getSlot().send();
|
|
44
|
+
const openSlot = BigInt(currentSlot);
|
|
45
|
+
|
|
46
|
+
const channelPda = await findChannelPda(
|
|
47
|
+
client,
|
|
48
|
+
USDC_MINT,
|
|
49
|
+
salt,
|
|
50
|
+
openSlot
|
|
51
|
+
);
|
|
52
|
+
|
|
53
|
+
const [payerTokenAccount] = await findAssociatedTokenPda({
|
|
54
|
+
owner: client.payer.address,
|
|
55
|
+
mint: USDC_MINT,
|
|
56
|
+
tokenProgram: TOKEN_PROGRAM_ADDRESS,
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
const [channelTokenAccount] = await findAssociatedTokenPda({
|
|
60
|
+
owner: channelPda,
|
|
61
|
+
mint: USDC_MINT,
|
|
62
|
+
tokenProgram: TOKEN_PROGRAM_ADDRESS,
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
const openIx = await getOpenInstructionAsync({
|
|
66
|
+
payer: client.payer,
|
|
67
|
+
rentPayer: client.payer,
|
|
68
|
+
payee: address(SHUNT_TREASURY),
|
|
69
|
+
mint: USDC_MINT,
|
|
70
|
+
authorizedSigner: client.payer.address,
|
|
71
|
+
channel: channelPda,
|
|
72
|
+
payerTokenAccount: payerTokenAccount,
|
|
73
|
+
channelTokenAccount: channelTokenAccount,
|
|
74
|
+
|
|
75
|
+
systemProgram: address("11111111111111111111111111111111"),
|
|
76
|
+
tokenProgram: TOKEN_PROGRAM_ADDRESS,
|
|
77
|
+
associatedTokenProgram: ASSOCIATED_TOKEN_PROGRAM_ADDRESS,
|
|
78
|
+
rent: address("SysvarRent111111111111111111111111111111111"),
|
|
79
|
+
|
|
80
|
+
// Arguments
|
|
81
|
+
openArgs: {
|
|
82
|
+
salt: salt,
|
|
83
|
+
deposit: depositAmount,
|
|
84
|
+
gracePeriod: gracePeriod,
|
|
85
|
+
openSlot: openSlot,
|
|
86
|
+
recipients: [],
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
const signature = await sendInstructions(client, [openIx]);
|
|
91
|
+
|
|
92
|
+
return { channel: channelPda, signature };
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
export async function topUpPaymentChannel(client: ShuntClient, channelAddress: Address, topUpAmount: bigint) {
|
|
98
|
+
const USDC_MINT = devnet ? USDC_DEVNET : USDC_MAINNET;
|
|
99
|
+
|
|
100
|
+
const [payerTokenAccount] = await findAssociatedTokenPda({
|
|
101
|
+
owner: client.payer.address,
|
|
102
|
+
mint: USDC_MINT,
|
|
103
|
+
tokenProgram: TOKEN_PROGRAM_ADDRESS,
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
// 2. Derive the Channel's Escrow Associated Token Account
|
|
107
|
+
const [channelTokenAccount] = await findAssociatedTokenPda({
|
|
108
|
+
owner: channelAddress,
|
|
109
|
+
mint: USDC_MINT,
|
|
110
|
+
tokenProgram: TOKEN_PROGRAM_ADDRESS,
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
const topUpIx = getTopUpInstruction({
|
|
114
|
+
payer: client.payer,
|
|
115
|
+
channel: channelAddress,
|
|
116
|
+
payerTokenAccount: payerTokenAccount,
|
|
117
|
+
channelTokenAccount: channelTokenAccount,
|
|
118
|
+
mint: USDC_MINT,
|
|
119
|
+
tokenProgram: TOKEN_PROGRAM_ADDRESS,
|
|
120
|
+
topUpArgs: {
|
|
121
|
+
amount: topUpAmount,
|
|
122
|
+
},
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
const signature = await sendInstructions(client, [topUpIx]);
|
|
126
|
+
|
|
127
|
+
return { channel: channelAddress, signature };
|
|
128
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { createClient } from "@solana/kit";
|
|
2
|
+
import { solanaMainnetRpc, solanaDevnetRpc } from '@solana/kit-plugin-rpc';
|
|
3
|
+
import { signerFromFile } from '@solana/kit-plugin-signer';
|
|
4
|
+
import { systemProgram } from '@solana-program/system';
|
|
5
|
+
import { tokenProgram } from '@solana-program/token';
|
|
6
|
+
|
|
7
|
+
export const devnet = true;
|
|
8
|
+
|
|
9
|
+
export async function createShuntClient(signerFilePath: string) {
|
|
10
|
+
const rpc = devnet ? solanaDevnetRpc({ rpcUrl: "https://api.devnet.solana.com" }) : solanaMainnetRpc({ rpcUrl: "https://api.mainnet-beta.solana.com" });
|
|
11
|
+
|
|
12
|
+
const client = await createClient()
|
|
13
|
+
.use(signerFromFile(signerFilePath))
|
|
14
|
+
.use(rpc)
|
|
15
|
+
.use(systemProgram())
|
|
16
|
+
.use(tokenProgram());
|
|
17
|
+
|
|
18
|
+
return client;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export type ShuntClient = Awaited<ReturnType<typeof createShuntClient>>;
|
|
22
|
+
export const SHUNT_TREASURY = "4gNrRt7FKoetTTGbJuzp6WYtgqqmKLpjXybPqY3zbVCh";
|
package/src/sdk/utils.ts
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { type ShuntClient } from "./client.js";
|
|
2
|
+
import { pipe, createTransactionMessage, setTransactionMessageFeePayerSigner, setTransactionMessageLifetimeUsingBlockhash, appendTransactionMessageInstructions, signTransactionMessageWithSigners, getSignatureFromTransaction, getBase64EncodedWireTransaction, type Instruction } from "@solana/kit";
|
|
3
|
+
|
|
4
|
+
export async function sendInstructions(
|
|
5
|
+
client: ShuntClient,
|
|
6
|
+
instructions: Instruction[]
|
|
7
|
+
): Promise<string> {
|
|
8
|
+
const { value: latestBlockhash } = await client.rpc.getLatestBlockhash().send();
|
|
9
|
+
|
|
10
|
+
const transactionMessage = pipe(
|
|
11
|
+
createTransactionMessage({ version: 0 }),
|
|
12
|
+
(tx) => setTransactionMessageFeePayerSigner(client.payer, tx),
|
|
13
|
+
(tx) => setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, tx),
|
|
14
|
+
(tx) => appendTransactionMessageInstructions(instructions, tx)
|
|
15
|
+
);
|
|
16
|
+
|
|
17
|
+
const signedTransaction = await signTransactionMessageWithSigners(transactionMessage);
|
|
18
|
+
|
|
19
|
+
const transactionSignature = getSignatureFromTransaction(signedTransaction);
|
|
20
|
+
|
|
21
|
+
const base64WireTransaction = getBase64EncodedWireTransaction(signedTransaction);
|
|
22
|
+
|
|
23
|
+
// 4. Send the base64 string using the RPC client
|
|
24
|
+
await client.rpc.sendTransaction(base64WireTransaction, {
|
|
25
|
+
encoding: "base64",
|
|
26
|
+
}).send();
|
|
27
|
+
|
|
28
|
+
return transactionSignature;
|
|
29
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { type ShuntClient } from "./client.js";
|
|
2
|
+
import { getAddressEncoder, isMessagePartialSigner, getBase58Decoder, type Address } from "@solana/kit";
|
|
3
|
+
|
|
4
|
+
export async function createSignedVoucher(client: ShuntClient, channelAddress: Address, cumulativeAmount: bigint, expiresAtUnixTimestamp?: bigint) {
|
|
5
|
+
if (!client.payer || !isMessagePartialSigner(client.payer)) {
|
|
6
|
+
throw new Error("The client's payer does not support message signing.");
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
const expiresAt = expiresAtUnixTimestamp ?? 0n;
|
|
10
|
+
|
|
11
|
+
const payload = new Uint8Array(50);
|
|
12
|
+
const dataView = new DataView(payload.buffer);
|
|
13
|
+
|
|
14
|
+
// 2. Set Magic Bytes (0x56, 0x01) at offsets 0..2
|
|
15
|
+
// Magic Bytes (0x56, 0x01) at offset 0
|
|
16
|
+
payload.set([0x56, 0x01], 0);
|
|
17
|
+
|
|
18
|
+
// 3. Set Channel Address at offsets 2..34
|
|
19
|
+
const addressEncoder = getAddressEncoder();
|
|
20
|
+
const channelBytes = addressEncoder.encode(channelAddress);
|
|
21
|
+
payload.set(channelBytes, 2);
|
|
22
|
+
|
|
23
|
+
// 4. Set Cumulative Amount at offsets 34..42 (8 bytes, Little-Endian)
|
|
24
|
+
dataView.setBigUint64(34, cumulativeAmount, true);
|
|
25
|
+
|
|
26
|
+
// 5. Set Expires At at offsets 42..50 (8 bytes, Little-Endian)
|
|
27
|
+
dataView.setBigInt64(42, expiresAt, true);
|
|
28
|
+
|
|
29
|
+
const signedMessages = await client.payer.signMessages([{ content: payload, signatures: {} }]);
|
|
30
|
+
const signatureBytes = signedMessages[0][client.payer.address];
|
|
31
|
+
|
|
32
|
+
const base58Decoder = getBase58Decoder();
|
|
33
|
+
|
|
34
|
+
// 7. Construct the HTTP Transport Envelope (SignedVoucher)
|
|
35
|
+
return {
|
|
36
|
+
voucher: {
|
|
37
|
+
voucher: {
|
|
38
|
+
channelId: channelAddress,
|
|
39
|
+
cumulativeAmount: cumulativeAmount.toString(),
|
|
40
|
+
// Only include expiresAt in the JSON if it is non-zero
|
|
41
|
+
...(expiresAt !== 0n && {
|
|
42
|
+
expiresAt: new Date(Number(expiresAt) * 1000).toISOString()
|
|
43
|
+
})
|
|
44
|
+
},
|
|
45
|
+
signer: client.payer.address,
|
|
46
|
+
signature: base58Decoder.decode(signatureBytes),
|
|
47
|
+
signatureType: "ed25519"
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
}
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "esnext",
|
|
5
|
+
"moduleResolution": "bundler",
|
|
6
|
+
"outDir": "./dist",
|
|
7
|
+
"rootDir": "./src",
|
|
8
|
+
"declaration": true, // Generates .d.ts files for your users
|
|
9
|
+
"strict": true,
|
|
10
|
+
"esModuleInterop": true,
|
|
11
|
+
"skipLibCheck": true,
|
|
12
|
+
"forceConsistentCasingInFileNames": true
|
|
13
|
+
},
|
|
14
|
+
"include": ["src/**/*"]
|
|
15
|
+
}
|