@atumlabs/payment-gateway-client 3.0.1 → 4.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/CHANGELOG.md +37 -0
- package/README.md +27 -6
- package/dist/cli/approve-permit2.js +6174 -1070
- package/dist/cli/payment-status.js +5968 -1075
- package/dist/cli/quote-status.js +5954 -1074
- package/dist/cli/request-quote.js +5954 -1074
- package/dist/cli/send-payment.js +6372 -1230
- package/dist/index.d.ts +294 -403
- package/dist/index.js +6650 -1260
- package/dist/{sender-auth-verify-C-Q-zvAO.d.ts → sender-auth-verify-CEf7FN6s.d.ts} +349 -46
- package/dist/signing.d.ts +2 -2
- package/dist/signing.js +14987 -1519
- package/docs/idempotency.md +6 -4
- package/docs/signing.md +45 -42
- package/package.json +8 -6
package/docs/idempotency.md
CHANGED
|
@@ -129,8 +129,7 @@ altogether is from a gateway predating it.
|
|
|
129
129
|
|
|
130
130
|
## Reading the outcome (payments)
|
|
131
131
|
|
|
132
|
-
`status` is on every payment response, and
|
|
133
|
-
retry:
|
|
132
|
+
`status` is on every payment response, and its endings mean different things for a retry:
|
|
134
133
|
|
|
135
134
|
| `status` | What it means | What to do |
|
|
136
135
|
| ---------------------- | --------------------------------- | ------------------------------------------------------ |
|
|
@@ -138,13 +137,16 @@ retry:
|
|
|
138
137
|
| `pending` | Accepted, still settling. | Re-submit the **same** `request_id`, or read the status endpoint. Do not start a new payment. |
|
|
139
138
|
| `finalizing` | Paid on chain, collecting confirmations. Not final. | As `pending`. Do not treat it as delivered. |
|
|
140
139
|
| `failed` | Terminal — it can never complete. | A fresh attempt needs a **new** `request_id`. |
|
|
140
|
+
| `refunding` | Not delivered, the escrowed funds are being returned. Not final. | As `pending`. |
|
|
141
|
+
| `refund_available` | Not delivered, funds still in escrow. The status endpoint returns `refund_signature`. Not final. | Submit `refund_signature` to the source escrow to return the funds. Do not start a new payment until it is `refunded`: a late delivery can still complete it. |
|
|
142
|
+
| `refunded` | Terminal, not delivered. The funds were returned. | A fresh attempt needs a **new** `request_id`. |
|
|
141
143
|
|
|
142
144
|
`pending` is not success. Cross-chain settlement can outrun the gateway's
|
|
143
145
|
synchronous window, so a payment that has been accepted may still have no result
|
|
144
146
|
when you get your response.
|
|
145
147
|
|
|
146
|
-
A terminal
|
|
147
|
-
same
|
|
148
|
+
A terminal payment **keeps** its `request_id`. Re-submitting that id returns the
|
|
149
|
+
same payment for good, which is why recovering from one means minting a
|
|
148
150
|
new id — the opposite of what a pending payment needs. Getting these two the
|
|
149
151
|
wrong way round is how a caller either pays twice or waits for something that
|
|
150
152
|
will never happen.
|
package/docs/signing.md
CHANGED
|
@@ -15,10 +15,9 @@ unidentified originator. The reverse identifies an originator who has authorized
|
|
|
15
15
|
integrations need the first two; the third applies once the originator holds credentials about
|
|
16
16
|
itself.
|
|
17
17
|
|
|
18
|
-
> The
|
|
19
|
-
>
|
|
20
|
-
>
|
|
21
|
-
> in the Go client.
|
|
18
|
+
> The underlying declaration library also names its document signer `signPaymentRequest`. This
|
|
19
|
+
> package exports it as `signDeclaration`, matching `SignDeclaration` in the Go client, so the two
|
|
20
|
+
> cannot be confused.
|
|
22
21
|
|
|
23
22
|
## Keys never reach this package
|
|
24
23
|
|
|
@@ -83,18 +82,13 @@ await new PaymentGatewayClient({ BASE: gateway }).payments.submitPayment({ reque
|
|
|
83
82
|
|
|
84
83
|
## Check what you are signing
|
|
85
84
|
|
|
86
|
-
`signPaymentRequest` signs **every** entry in `sender_auth.signed_messages[]` as given
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
spender, escrow and amounts come from the gateway's chain defaults.
|
|
85
|
+
`signPaymentRequest` signs **every** entry in `sender_auth.signed_messages[]` as given, in both
|
|
86
|
+
the TypeScript and Go clients. The permit's spender, escrow and amounts come from the gateway's
|
|
87
|
+
chain defaults, and the signer has no notion of what you intended.
|
|
90
88
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
If you are signing on behalf of someone else's funds, bind the signed permit to the terms **you**
|
|
96
|
-
agreed before the request leaves your process. `verifyPaymentRequest` recovers every
|
|
97
|
-
`signed_messages[]` entry and checks the terms it actually commits to:
|
|
89
|
+
Bind the signed permit to the terms **you** agreed before the request leaves your process.
|
|
90
|
+
`verifyPaymentRequest` recovers every `signed_messages[]` entry and checks the terms it commits
|
|
91
|
+
to:
|
|
98
92
|
|
|
99
93
|
```ts
|
|
100
94
|
import { verifyPaymentRequest } from '@atum-labs/payment-gateway-client/signing';
|
|
@@ -107,22 +101,40 @@ const { recoveredAccount } = verifyPaymentRequest(signed, {
|
|
|
107
101
|
});
|
|
108
102
|
```
|
|
109
103
|
|
|
110
|
-
`sourceAsset` is the **bare token address**, not
|
|
111
|
-
|
|
112
|
-
|
|
104
|
+
`sourceAsset` is the **bare token address**, not the CAIP-19 identifier used in the request's
|
|
105
|
+
`source.asset_identifier`. Passing the CAIP form fails to match.
|
|
106
|
+
|
|
107
|
+
**Pass those three fields.** Without them, `verifyPaymentRequest` takes the token, network and
|
|
108
|
+
amount from the request itself, which proves only that the signatures are consistent with the
|
|
109
|
+
request's own fields.
|
|
110
|
+
|
|
111
|
+
It always checks the payee: the deposit must commit to the request's own `destination` and
|
|
112
|
+
`request_id`, so a request whose payee or request id was changed after signing is refused.
|
|
113
113
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
114
|
+
If you hold the request as JSON text, call `verifyPaymentRequestJSON(json, expected)` instead. It
|
|
115
|
+
also refuses a repeated member name, including names that differ only in letter case, where it is
|
|
116
|
+
read: any top-level name, or inside `source`, `destination`, `request_id` or `sender_auth`.
|
|
117
|
+
On a refusal, `commitmentResultOf(error)` returns the outcome (for example
|
|
118
|
+
`destination_mismatch`) and both copies of the payee, ready to log. A verified entry carries the
|
|
119
|
+
same result as `results[i].commitment`.
|
|
119
120
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
121
|
+
**Contract-account payers.** `verifyPaymentRequest` recovers each signer, so it refuses a payer
|
|
122
|
+
that is a contract account (ERC-1271, such as a Safe): its signature comes from an owner key, never
|
|
123
|
+
from the account itself. For such a payer, call `verifyRequestCommitment(json)`. It checks the
|
|
124
|
+
payee and request id the deposit commits to without recovering the signer; Permit2 checks the
|
|
125
|
+
signature on chain when the deposit is made.
|
|
123
126
|
|
|
124
|
-
|
|
125
|
-
|
|
127
|
+
Every entry must be a bindable permit; a malformed entry throws. A caller with mixed messages
|
|
128
|
+
(for example an EVM setup approval alongside the permit) composes the per-entry adapter calls
|
|
129
|
+
itself.
|
|
130
|
+
|
|
131
|
+
In Go, `senderauth.VerifyRequestCommitment(raw, solanaDomain)` is the payee check alone,
|
|
132
|
+
`senderauth.VerifyPaymentRequestJSON(raw, expected)` and
|
|
133
|
+
`senderauth.VerifyPaymentRequest(request, expected)` run the same checks,
|
|
134
|
+
`senderauth.CommitmentResultOf(err)` reads the outcome from an error, and
|
|
135
|
+
`senderauth.GetChainAdapter(caip2).RecoverAndVerify(signed, source, commitment, expected)` checks
|
|
136
|
+
one signed message against a `CommitmentExpectation` built from the request's `destination` and
|
|
137
|
+
`request_id`.
|
|
126
138
|
|
|
127
139
|
A custodial signer is the natural place to enforce this: it is the component that can refuse.
|
|
128
140
|
|
|
@@ -170,21 +182,13 @@ loader in place of its built-in fetcher. A document whose `@context` names an un
|
|
|
170
182
|
refused rather than resolved, since an attacker-served context could otherwise change what each
|
|
171
183
|
term means, and therefore what the signature covers.
|
|
172
184
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
reads from local disk, never the network, and nothing in normal operation sets it — but if it is
|
|
176
|
-
set, the library now says so on first use rather than substituting the contexts silently.
|
|
177
|
-
|
|
178
|
-
This is structural: there is no HTTP client in the signing libraries, and the JSON-LD processor
|
|
179
|
-
is always handed the local loader in place of its built-in fetcher.
|
|
185
|
+
For development against a modified snapshot, an environment variable can override the embedded
|
|
186
|
+
copies. It reads from local disk only, and the library reports it on first use when it is set.
|
|
180
187
|
|
|
181
188
|
## The identity envelope
|
|
182
189
|
|
|
183
|
-
**
|
|
184
|
-
|
|
185
|
-
empty bag, so until issuance exists this surface cannot be exercised end to end. It
|
|
186
|
-
is documented because the shape is stable and the signing half is done, not because it is
|
|
187
|
-
callable today.
|
|
190
|
+
**Prerequisite: at least one issuer-signed credential about the originator.** The schema rejects
|
|
191
|
+
an envelope without one.
|
|
188
192
|
|
|
189
193
|
`buildEnvelope` wraps the originator's issuer-signed credentials in a holder-signed
|
|
190
194
|
PaymentRequestEnvelope. It takes the same kind of signer as the other surfaces, so a custodial
|
|
@@ -207,8 +211,7 @@ const envelope = await buildEnvelopeForAccount('eip155:1', wallet.address.toLowe
|
|
|
207
211
|
|
|
208
212
|
Three things the verifier enforces, so they are not optional:
|
|
209
213
|
|
|
210
|
-
- **At least one credential.**
|
|
211
|
-
prerequisite above.
|
|
214
|
+
- **At least one credential.** An empty bag is rejected.
|
|
212
215
|
- **The challenge binds one request** and **the domain binds one environment**. Both are checked
|
|
213
216
|
against the values the gateway expects, so an envelope cannot be replayed across either.
|
|
214
217
|
- **The declaration type is bound into the signature**, not merely present in the document —
|
package/package.json
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atumlabs/payment-gateway-client",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "4.0.0",
|
|
4
4
|
"description": "TypeScript client for Atum Payment Gateway API",
|
|
5
5
|
"author": "Atum Labs, Inc.",
|
|
6
|
-
"homepage": "https://github.com/Atum-Labs/protocol/tree/main/payment-gateway-client#readme",
|
|
6
|
+
"homepage": "https://github.com/Atum-Labs/protocol/tree/main/schemas/apis/payment-gateway/v1/bindings/payment-gateway-client#readme",
|
|
7
7
|
"repository": {
|
|
8
8
|
"type": "git",
|
|
9
9
|
"url": "git+https://github.com/Atum-Labs/protocol.git",
|
|
10
|
-
"directory": "payment-gateway-client"
|
|
10
|
+
"directory": "schemas/apis/payment-gateway/v1/bindings/payment-gateway-client"
|
|
11
11
|
},
|
|
12
12
|
"bugs": {
|
|
13
13
|
"url": "https://github.com/Atum-Labs/protocol/issues"
|
|
@@ -50,9 +50,9 @@
|
|
|
50
50
|
"approve-permit2": "./dist/cli/approve-permit2.js"
|
|
51
51
|
},
|
|
52
52
|
"scripts": {
|
|
53
|
-
"generate": "openapi-ts --input
|
|
53
|
+
"generate": "openapi-ts --input ../../openapi.yaml --output \"${PGC_GEN_OUT:-./src/generated}\" --client axios --name PaymentGatewayClient --useOptions",
|
|
54
54
|
"lint": "eslint . --max-warnings 0",
|
|
55
|
-
"prebuild:deps": "node -e \"if(!require('fs').existsSync('
|
|
55
|
+
"prebuild:deps": "node -e \"if(!require('fs').existsSync('../../../../../../pnpm-workspace.yaml')){console.error('protocol workspace not found at ../../../../../../pnpm-workspace.yaml. Is this checked out inside the protocol monorepo?');process.exit(1)}\"",
|
|
56
56
|
"build:deps": "pnpm --filter \"@atum-labs/payment-gateway-client^...\" run build",
|
|
57
57
|
"build": "tsup && chmod +x dist/cli/*.js && node scripts/stamp-entry-headers.mjs",
|
|
58
58
|
"typecheck:tests": "tsc -p tsconfig.test.json",
|
|
@@ -73,6 +73,7 @@
|
|
|
73
73
|
"dotenv": "^16.6.1",
|
|
74
74
|
"ethers": "^6.11.0",
|
|
75
75
|
"jsonld": "8.3.3",
|
|
76
|
+
"rdf-canonize": "3.4.0",
|
|
76
77
|
"tweetnacl": "^1.0.3",
|
|
77
78
|
"zod": "^3.25.0"
|
|
78
79
|
},
|
|
@@ -85,6 +86,7 @@
|
|
|
85
86
|
"@atum-labs/payment-request-sender-auth": "workspace:*",
|
|
86
87
|
"@atum-labs/payment-request-token-approval": "workspace:*",
|
|
87
88
|
"@atum-labs/publish-guard": "workspace:*",
|
|
89
|
+
"@atum-labs/schema-declarations": "workspace:*",
|
|
88
90
|
"@atum-labs/solana-escrow-encoding": "workspace:*",
|
|
89
91
|
"@atum-labs/turnkey-signer": "workspace:*",
|
|
90
92
|
"@atum-labs/tvm-escrow-encoding": "workspace:*",
|
|
@@ -98,7 +100,7 @@
|
|
|
98
100
|
"ts-jest": "^29.1.1",
|
|
99
101
|
"tsup": "^8.5.1",
|
|
100
102
|
"typescript": "^5.0.0",
|
|
101
|
-
"uuid": "^
|
|
103
|
+
"uuid": "^11.1.1"
|
|
102
104
|
},
|
|
103
105
|
"files": [
|
|
104
106
|
"dist/**/*",
|