@atumlabs/payment-gateway-client 1.0.2 → 2.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/CHANGELOG.md +39 -0
- package/README.md +127 -51
- package/THIRD-PARTY-NOTICES.txt +45 -0
- package/dist/cli/payment-status.js +1288 -668
- package/dist/cli/quote-status.js +1288 -668
- package/dist/cli/request-quote.js +1289 -669
- package/dist/cli/send-payment.js +1339 -687
- package/dist/index.d.ts +242 -174
- package/dist/index.js +1371 -648
- package/docs/idempotency.md +62 -0
- package/package.json +17 -6
- /package/{LICENSE.md → LICENSE} +0 -0
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# Payment idempotency
|
|
2
|
+
|
|
3
|
+
Submit the same payment twice — a retry, a timeout, a network blip — and you
|
|
4
|
+
should end up with **one** payment, not two, and receive the **same** answer both
|
|
5
|
+
times. The key to both properties is the `request_id` you send with each payment.
|
|
6
|
+
|
|
7
|
+
## Using the SDK
|
|
8
|
+
|
|
9
|
+
With `@atumlabs/payment-gateway-client` this is automatic. Pass a stable
|
|
10
|
+
`request_id` and reuse it on retry. `request_id` is required on the payment path
|
|
11
|
+
(`preparePaymentRequest`); the SDK derives the on-chain deposit nonce
|
|
12
|
+
deterministically from it, so both guarantees below line up on their own. You
|
|
13
|
+
never manage nonces — `request_id` is the only value you control.
|
|
14
|
+
|
|
15
|
+
Reuse the same `request_id` across attempts of the same logical payment. Use a
|
|
16
|
+
fresh `request_id` only for a genuinely new payment.
|
|
17
|
+
|
|
18
|
+
## The two guarantees
|
|
19
|
+
|
|
20
|
+
### 1. Gateway dedup — enforced for every caller
|
|
21
|
+
|
|
22
|
+
The gateway records your `request_id` (scoped to your source account and signing
|
|
23
|
+
identity). If the same `request_id` arrives again, the gateway returns the
|
|
24
|
+
original payment — same `payment_id`, same status and receipt — and never creates
|
|
25
|
+
a second payment or broadcasts a second deposit. This holds whether you use the
|
|
26
|
+
SDK or call the API directly, as long as you send a stable `request_id` and reuse
|
|
27
|
+
it on retry.
|
|
28
|
+
|
|
29
|
+
### 2. On-chain single-settlement — enforced by the blockchain
|
|
30
|
+
|
|
31
|
+
Each deposit authorization carries a nonce, and the chain guarantees a given
|
|
32
|
+
nonce can settle at most once. This ties your retries together on-chain **only
|
|
33
|
+
if** each retry carries the **same** nonce. The SDK derives that nonce from your
|
|
34
|
+
`request_id`, so retries reuse it automatically. A direct caller sets the nonce
|
|
35
|
+
themselves in the signed permit.
|
|
36
|
+
|
|
37
|
+
The caveat runs in both directions. A changing `request_id` defeats both
|
|
38
|
+
guarantees, because each attempt is then treated as a different payment — keep it
|
|
39
|
+
stable and reuse it on retry. Equally, reusing a `request_id` with different terms
|
|
40
|
+
(a corrected amount, a different token) returns the **original** payment rather
|
|
41
|
+
than an error, so the new terms are silently dropped. A genuinely new payment
|
|
42
|
+
always needs a new id.
|
|
43
|
+
|
|
44
|
+
## Chain-specific behavior
|
|
45
|
+
|
|
46
|
+
The SDK gives you the same guarantee on every chain; the on-chain half works
|
|
47
|
+
slightly differently underneath:
|
|
48
|
+
|
|
49
|
+
- **EVM / Tron:** the on-chain nonce is spent permanently, so guarantee 2 lasts
|
|
50
|
+
indefinitely.
|
|
51
|
+
- **Solana:** the on-chain guard covers only a short, bounded window (roughly two
|
|
52
|
+
minutes). Beyond that window the durable protection is guarantee 1 (the
|
|
53
|
+
gateway's `request_id` record). The SDK keeps a rebuild inside the window by
|
|
54
|
+
pinning `issued_at` through its Solana clock reader, so you do not have to.
|
|
55
|
+
|
|
56
|
+
Either way, a stable `request_id` keeps you safe on every chain.
|
|
57
|
+
|
|
58
|
+
## A note on addresses
|
|
59
|
+
|
|
60
|
+
EVM `0x` addresses are case-insensitive, so casing never affects your payment.
|
|
61
|
+
Solana and Tron base58 addresses **are** case-sensitive — pass them exactly as
|
|
62
|
+
issued.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atumlabs/payment-gateway-client",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "2.1.0",
|
|
4
4
|
"description": "TypeScript client for Atum Payment Gateway API",
|
|
5
5
|
"author": "Atum Labs, Inc.",
|
|
6
6
|
"homepage": "https://github.com/Atum-Labs/protocol/tree/main/payment-gateway-client#readme",
|
|
@@ -40,12 +40,13 @@
|
|
|
40
40
|
"scripts": {
|
|
41
41
|
"generate": "openapi-ts --input ../schemas/apis/payment-gateway/v1/openapi.yaml --output ./src/generated --client axios --name PaymentGatewayClient --useOptions",
|
|
42
42
|
"prebuild:deps": "node -e \"if(!require('fs').existsSync('../key-management/common/typescript/tsconfig.json')){console.error('protocol key-management packages not found at ../key-management. Is this checked out inside the protocol monorepo?');process.exit(1)}\"",
|
|
43
|
-
"build:deps": "tsc -p ../key-management/common/typescript/tsconfig.json && tsc -p ../key-management/providers/turnkey/typescript/tsconfig.json && tsc -p ../contracts/svm/escrow-encoding/typescript/tsconfig.json && tsc -p ../contracts/evm/escrow-encoding/typescript/tsconfig.json && tsc -p ../contracts/tvm/escrow-encoding/typescript/tsconfig.json",
|
|
44
|
-
"build": "pnpm run build:deps && tsup && chmod +x dist/cli/*.js",
|
|
43
|
+
"build:deps": "tsc -p ../key-management/common/typescript/tsconfig.json && tsc -p ../key-management/providers/turnkey/typescript/tsconfig.json && tsc -p ../contracts/svm/escrow-encoding/typescript/tsconfig.json && tsc -p ../contracts/evm/escrow-encoding/typescript/tsconfig.json && tsc -p ../contracts/tvm/escrow-encoding/typescript/tsconfig.json && tsc -p ../schemas/declarations/PaymentRequest/v1/bindings/typescript/sender-auth/tsconfig.json",
|
|
44
|
+
"build": "pnpm run build:deps && tsup && chmod +x dist/cli/*.js && node scripts/stamp-entry-headers.mjs",
|
|
45
45
|
"pretest": "pnpm run build:deps",
|
|
46
46
|
"test": "jest",
|
|
47
|
-
"clean": "rm -rf dist ../key-management/common/typescript/dist ../key-management/providers/turnkey/typescript/dist ../contracts/svm/escrow-encoding/typescript/dist ../contracts/evm/escrow-encoding/typescript/dist ../contracts/tvm/escrow-encoding/typescript/dist",
|
|
47
|
+
"clean": "rm -rf dist ../key-management/common/typescript/dist ../key-management/providers/turnkey/typescript/dist ../contracts/svm/escrow-encoding/typescript/dist ../contracts/evm/escrow-encoding/typescript/dist ../contracts/tvm/escrow-encoding/typescript/dist ../schemas/declarations/PaymentRequest/v1/bindings/typescript/sender-auth/dist",
|
|
48
48
|
"check:publishable": "node scripts/check-publishable.mjs",
|
|
49
|
+
"gen:notices": "node scripts/gen-third-party-notices.mjs",
|
|
49
50
|
"prepare": "pnpm run build",
|
|
50
51
|
"prepublishOnly": "pnpm run build && pnpm run check:publishable"
|
|
51
52
|
},
|
|
@@ -54,6 +55,7 @@
|
|
|
54
55
|
"axios": "1.13.2",
|
|
55
56
|
"bs58": "^6.0.0",
|
|
56
57
|
"commander": "^12.0.0",
|
|
58
|
+
"dotenv": "^16.6.1",
|
|
57
59
|
"ethers": "^6.11.0",
|
|
58
60
|
"tweetnacl": "^1.0.3",
|
|
59
61
|
"zod": "^3.25.0"
|
|
@@ -61,6 +63,8 @@
|
|
|
61
63
|
"devDependencies": {
|
|
62
64
|
"@atum-labs/evm-escrow-encoding": "workspace:*",
|
|
63
65
|
"@atum-labs/km-core": "workspace:*",
|
|
66
|
+
"@atum-labs/payment-request-sender-auth": "workspace:*",
|
|
67
|
+
"@atum-labs/publish-guard": "workspace:*",
|
|
64
68
|
"@atum-labs/solana-escrow-encoding": "workspace:*",
|
|
65
69
|
"@atum-labs/turnkey-signer": "workspace:*",
|
|
66
70
|
"@atum-labs/tvm-escrow-encoding": "workspace:*",
|
|
@@ -75,7 +79,14 @@
|
|
|
75
79
|
},
|
|
76
80
|
"files": [
|
|
77
81
|
"dist/**/*",
|
|
78
|
-
"
|
|
82
|
+
"README.md",
|
|
83
|
+
"CHANGELOG.md",
|
|
84
|
+
"docs/**",
|
|
85
|
+
"LICENSE",
|
|
86
|
+
"THIRD-PARTY-NOTICES.txt"
|
|
79
87
|
],
|
|
80
|
-
"license": "
|
|
88
|
+
"license": "SEE LICENSE IN LICENSE",
|
|
89
|
+
"publishConfig": {
|
|
90
|
+
"access": "restricted"
|
|
91
|
+
}
|
|
81
92
|
}
|
/package/{LICENSE.md → LICENSE}
RENAMED
|
File without changes
|