@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.
Files changed (96) hide show
  1. package/dist/clients/typescript/src/__tests__/instruction-parsers.test.d.ts +1 -0
  2. package/dist/clients/typescript/src/__tests__/voucher-numeric-safety.test.d.ts +1 -0
  3. package/dist/clients/typescript/src/__tests__/voucher-types.test-d.d.ts +1 -0
  4. package/dist/clients/typescript/src/generated/accounts/channel.d.ts +59 -0
  5. package/dist/clients/typescript/src/generated/accounts/index.d.ts +8 -0
  6. package/dist/clients/typescript/src/generated/errors/index.d.ts +8 -0
  7. package/dist/clients/typescript/src/generated/errors/paymentChannels.d.ts +84 -0
  8. package/dist/clients/typescript/src/generated/index.d.ts +13 -0
  9. package/dist/clients/typescript/src/generated/instructions/distribute.d.ts +90 -0
  10. package/dist/clients/typescript/src/generated/instructions/emitEvent.d.ts +42 -0
  11. package/dist/clients/typescript/src/generated/instructions/index.d.ts +17 -0
  12. package/dist/clients/typescript/src/generated/instructions/open.d.ts +100 -0
  13. package/dist/clients/typescript/src/generated/instructions/reclaim.d.ts +39 -0
  14. package/dist/clients/typescript/src/generated/instructions/requestClose.d.ts +39 -0
  15. package/dist/clients/typescript/src/generated/instructions/seal.d.ts +36 -0
  16. package/dist/clients/typescript/src/generated/instructions/settle.d.ts +39 -0
  17. package/dist/clients/typescript/src/generated/instructions/settleAndSeal.d.ts +47 -0
  18. package/dist/clients/typescript/src/generated/instructions/topUp.d.ts +56 -0
  19. package/dist/clients/typescript/src/generated/instructions/withdrawPayer.d.ts +51 -0
  20. package/dist/clients/typescript/src/generated/pdas/eventAuthority.d.ts +11 -0
  21. package/dist/clients/typescript/src/generated/pdas/index.d.ts +8 -0
  22. package/dist/clients/typescript/src/generated/programs/index.d.ts +8 -0
  23. package/dist/clients/typescript/src/generated/programs/paymentChannels.d.ts +80 -0
  24. package/dist/clients/typescript/src/generated/types/accountDiscriminator.d.ts +16 -0
  25. package/dist/clients/typescript/src/generated/types/channelStatus.d.ts +18 -0
  26. package/dist/clients/typescript/src/generated/types/distributeArgs.d.ts +18 -0
  27. package/dist/clients/typescript/src/generated/types/distributionEntry.d.ts +16 -0
  28. package/dist/clients/typescript/src/generated/types/index.d.ts +20 -0
  29. package/dist/clients/typescript/src/generated/types/openArgs.d.ts +26 -0
  30. package/dist/clients/typescript/src/generated/types/opened.d.ts +19 -0
  31. package/dist/clients/typescript/src/generated/types/payoutBeneficiary.d.ts +17 -0
  32. package/dist/clients/typescript/src/generated/types/payoutRedirected.d.ts +26 -0
  33. package/dist/clients/typescript/src/generated/types/redirectReason.d.ts +18 -0
  34. package/dist/clients/typescript/src/generated/types/settleAndSealArgs.d.ts +15 -0
  35. package/dist/clients/typescript/src/generated/types/settlementWatermarks.d.ts +19 -0
  36. package/dist/clients/typescript/src/generated/types/topUpArgs.d.ts +17 -0
  37. package/dist/clients/typescript/src/generated/types/voucherArgs.d.ts +23 -0
  38. package/dist/clients/typescript/src/index.d.ts +1 -0
  39. package/dist/clients/typescript/src/safe-codecs.d.ts +6 -0
  40. package/dist/clients/typescript/tsup.config.d.ts +2 -0
  41. package/dist/index.cjs +1399 -0
  42. package/dist/index.d.ts +4 -0
  43. package/dist/index.js +1549 -0
  44. package/dist/sdk/channel.d.ts +10 -0
  45. package/dist/sdk/client.d.ts +31 -0
  46. package/dist/sdk/utils.d.ts +3 -0
  47. package/dist/sdk/voucher.d.ts +14 -0
  48. package/package.json +36 -0
  49. package/src/clients/typescript/package.json +32 -0
  50. package/src/clients/typescript/src/__tests__/instruction-parsers.test.ts +81 -0
  51. package/src/clients/typescript/src/__tests__/voucher-numeric-safety.test.ts +176 -0
  52. package/src/clients/typescript/src/__tests__/voucher-types.test-d.ts +8 -0
  53. package/src/clients/typescript/src/generated/accounts/channel.ts +192 -0
  54. package/src/clients/typescript/src/generated/accounts/index.ts +9 -0
  55. package/src/clients/typescript/src/generated/errors/index.ts +9 -0
  56. package/src/clients/typescript/src/generated/errors/paymentChannels.ts +251 -0
  57. package/src/clients/typescript/src/generated/index.ts +14 -0
  58. package/src/clients/typescript/src/generated/instructions/distribute.ts +517 -0
  59. package/src/clients/typescript/src/generated/instructions/emitEvent.ts +194 -0
  60. package/src/clients/typescript/src/generated/instructions/index.ts +18 -0
  61. package/src/clients/typescript/src/generated/instructions/open.ts +577 -0
  62. package/src/clients/typescript/src/generated/instructions/reclaim.ts +165 -0
  63. package/src/clients/typescript/src/generated/instructions/requestClose.ts +173 -0
  64. package/src/clients/typescript/src/generated/instructions/seal.ts +151 -0
  65. package/src/clients/typescript/src/generated/instructions/settle.ts +180 -0
  66. package/src/clients/typescript/src/generated/instructions/settleAndSeal.ts +224 -0
  67. package/src/clients/typescript/src/generated/instructions/topUp.ts +267 -0
  68. package/src/clients/typescript/src/generated/instructions/withdrawPayer.ts +246 -0
  69. package/src/clients/typescript/src/generated/pdas/eventAuthority.ts +26 -0
  70. package/src/clients/typescript/src/generated/pdas/index.ts +9 -0
  71. package/src/clients/typescript/src/generated/programs/index.ts +9 -0
  72. package/src/clients/typescript/src/generated/programs/paymentChannels.ts +366 -0
  73. package/src/clients/typescript/src/generated/types/accountDiscriminator.ts +41 -0
  74. package/src/clients/typescript/src/generated/types/channelStatus.ts +40 -0
  75. package/src/clients/typescript/src/generated/types/distributeArgs.ts +47 -0
  76. package/src/clients/typescript/src/generated/types/distributionEntry.ts +48 -0
  77. package/src/clients/typescript/src/generated/types/index.ts +21 -0
  78. package/src/clients/typescript/src/generated/types/openArgs.ts +70 -0
  79. package/src/clients/typescript/src/generated/types/opened.ts +42 -0
  80. package/src/clients/typescript/src/generated/types/payoutBeneficiary.ts +42 -0
  81. package/src/clients/typescript/src/generated/types/payoutRedirected.ts +76 -0
  82. package/src/clients/typescript/src/generated/types/redirectReason.ts +40 -0
  83. package/src/clients/typescript/src/generated/types/settleAndSealArgs.ts +39 -0
  84. package/src/clients/typescript/src/generated/types/settlementWatermarks.ts +48 -0
  85. package/src/clients/typescript/src/generated/types/topUpArgs.ts +33 -0
  86. package/src/clients/typescript/src/generated/types/voucherArgs.ts +68 -0
  87. package/src/clients/typescript/src/index.ts +1 -0
  88. package/src/clients/typescript/src/safe-codecs.ts +82 -0
  89. package/src/clients/typescript/tsconfig.json +11 -0
  90. package/src/clients/typescript/tsup.config.ts +9 -0
  91. package/src/index.ts +4 -0
  92. package/src/sdk/channel.ts +128 -0
  93. package/src/sdk/client.ts +22 -0
  94. package/src/sdk/utils.ts +29 -0
  95. package/src/sdk/voucher.ts +50 -0
  96. 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
+ }
@@ -0,0 +1,11 @@
1
+ {
2
+ "extends": "../../../tsconfig.json",
3
+ "compilerOptions": {
4
+ "outDir": "./dist",
5
+ "rootDir": "./src",
6
+ "declaration": true,
7
+ "declarationMap": true
8
+ },
9
+ "include": ["src/**/*"],
10
+ "exclude": ["node_modules", "dist"]
11
+ }
@@ -0,0 +1,9 @@
1
+ import { defineConfig } from 'tsup';
2
+
3
+ export default defineConfig({
4
+ entry: ['src/index.ts'],
5
+ format: ['esm'],
6
+ dts: true,
7
+ clean: true,
8
+ sourcemap: true,
9
+ });
package/src/index.ts ADDED
@@ -0,0 +1,4 @@
1
+ export * from './sdk/utils.js';
2
+ export * from './sdk/client.js';
3
+ export * from './sdk/channel.js';
4
+ export * from './sdk/voucher.js';
@@ -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";
@@ -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
+ }