@zkp2p/cash 0.4.8 → 0.4.9
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/AGENTS.md +22 -9
- package/README.md +113 -81
- package/dist/{chunk-CSDSJVI7.js → chunk-4LPWKZMW.js} +2 -2
- package/dist/{createCashClient-BJmz3v4_.d.cts → createCashClient-Br7uu4lQ.d.cts} +9 -5
- package/dist/{createCashClient-BJmz3v4_.d.ts → createCashClient-Br7uu4lQ.d.ts} +9 -5
- package/dist/index.cjs +4 -8
- package/dist/index.d.cts +276 -3167
- package/dist/index.d.ts +276 -3167
- package/dist/index.js +4 -8
- package/dist/react.d.cts +1 -1
- package/dist/react.d.ts +1 -1
- package/dist/react.js +1 -1
- package/dist/tools.cjs +2 -2
- package/dist/tools.d.cts +1 -1
- package/dist/tools.d.ts +1 -1
- package/dist/tools.js +2 -2
- package/docs/lifecycle-and-recovery.md +16 -11
- package/examples/agent-tool-use.ts +8 -2
- package/examples/node-cashout.ts +3 -2
- package/llms.txt +12 -6
- package/package.json +12 -12
- package/skills/peer-cash-integration/SKILL.md +26 -6
package/AGENTS.md
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
# @zkp2p/cash - agent integration manual
|
|
2
2
|
|
|
3
|
+
> This file is the shipped manual for agents **using** the package. To
|
|
4
|
+
> contribute to the SDK itself (layout, ground rules, CI, releasing), start at
|
|
5
|
+
> [CLAUDE.md](https://github.com/zkp2p/peer-cash/blob/main/CLAUDE.md).
|
|
6
|
+
|
|
3
7
|
You are integrating Peer Cash: an offramp that routes any Relay-supported EVM
|
|
4
8
|
source asset into Base USDC, then converts Base USDC to fiat (Venmo, Revolut,
|
|
5
9
|
Wise, Zelle, ...) at the live Chainlink market rate. The user whose USDC you
|
|
@@ -18,7 +22,9 @@ can withdraw an unmatched deposit.
|
|
|
18
22
|
(`{ to, data, value, chainId }`) plus same-index `steps[]` labels; inspect
|
|
19
23
|
the plan, submit the transactions in order, and wait for each receipt. After
|
|
20
24
|
`createDeposit` confirms, pass its receipt to `finalizePreparedCashout()` and
|
|
21
|
-
persist the returned `depositId`.
|
|
25
|
+
persist the returned `depositId`. If the original plan set
|
|
26
|
+
`accessPolicyRequired: true`, submit and confirm
|
|
27
|
+
`prepareAccessPolicy(depositId)` with the depositor next.
|
|
22
28
|
3. **You are a tool-use host** (MCP server, CLI) → import the manifest from
|
|
23
29
|
`@zkp2p/cash/tools` and map the tool names to the verbs above. Base-USDC
|
|
24
30
|
mutating tools return unsigned transactions. `cash_source_quote` is a quote,
|
|
@@ -32,9 +38,10 @@ Every transaction (including approves) carries ERC-8021 attribution:
|
|
|
32
38
|
code. The namespaced referral marker gives its Peer Privy wallet the direct
|
|
33
39
|
deposit-level integration share instead of applying maker L1/L2.
|
|
34
40
|
|
|
35
|
-
**Platform caveats
|
|
41
|
+
**Platform caveats:**
|
|
36
42
|
|
|
37
|
-
- **Venmo, Cash App, and PayPal
|
|
43
|
+
- **Venmo, Cash App, and PayPal restrict who can signal intents by default.**
|
|
44
|
+
If any payout leg uses one of these platforms, signed
|
|
38
45
|
`cashout()` confirms `createDeposit`, then submits and confirms the Plus, Pro,
|
|
39
46
|
Peer Makers, and Peer Pay policy using the same viem wallet. This is a
|
|
40
47
|
deliberate non-atomic follow-up with a brief unprotected interval. For
|
|
@@ -44,9 +51,10 @@ deposit-level integration share instead of applying maker L1/L2.
|
|
|
44
51
|
|
|
45
52
|
- **Wise and PayPal** carry `requiresIdentityAttestation: true`. A new curator
|
|
46
53
|
registration needs a signed maker identity attestation this SDK cannot mint
|
|
47
|
-
(it
|
|
48
|
-
reused with bare payee data. A new handle
|
|
49
|
-
`PAYEE_VERIFICATION_REQUIRED` before funds
|
|
54
|
+
(first-party Peer web obtains it through the Peer TEE browser extension).
|
|
55
|
+
An already-registered handle can be reused with bare payee data. A new handle
|
|
56
|
+
without its attestation fails with `PAYEE_VERIFICATION_REQUIRED` before funds
|
|
57
|
+
move on-chain.
|
|
50
58
|
- **Venmo, Revolut, Cash App, Monzo** validate the handle against the live
|
|
51
59
|
platform at registration - the account must exist. The rest (Zelle, Chime,
|
|
52
60
|
etc.) are format-checked only. Match handles to the `payeeHint`.
|
|
@@ -180,6 +188,10 @@ console.log(routed.source?.transactions?.origin, routed.source?.transactions?.de
|
|
|
180
188
|
broadcast; follow its recovery action and inspect wallet/protocol state.
|
|
181
189
|
`TRANSACTION_STATUS_UNKNOWN` means the returned hash may already have
|
|
182
190
|
succeeded. Inspect `err.recovery.transactionHash` first.
|
|
191
|
+
- **Never repeat a cash-out after an access-policy failure.** The deposit
|
|
192
|
+
already exists. If `recovery.transactionHash` is present, inspect that policy
|
|
193
|
+
transaction first; prepare another policy transaction only when the previous
|
|
194
|
+
one is absent or confirmed reverted.
|
|
183
195
|
- **`ORDER_NOT_FOUND` seconds after `cashout()` is indexer lag**, not a lost
|
|
184
196
|
deposit. The tx receipt you hold is the truth. Retry; `watch()` absorbs
|
|
185
197
|
this automatically.
|
|
@@ -214,10 +226,10 @@ Every `CashError` carries `code`, `retryable`, `remediation`. Behavior:
|
|
|
214
226
|
| `INVALID_INTENT_AMOUNT_RANGE` | no | Use a positive min, max at least min, and max no greater than amount |
|
|
215
227
|
| `INVALID_PAYOUT_CURRENCIES` | no | Pass one or more unique currencies listed for the platform |
|
|
216
228
|
| `INVALID_PAYOUT_PLATFORMS` | no | Pass one leg or an array of legs, using each platform at most once |
|
|
217
|
-
| `PAYEE_VERIFICATION_REQUIRED` | no |
|
|
229
|
+
| `PAYEE_VERIFICATION_REQUIRED` | no | Use Peer web + TEE extension for new Wise/PayPal; reuse registered handles |
|
|
218
230
|
| `PAYEE_REGISTRATION_FAILED` | yes | Validate against `payeeHint`, then retry |
|
|
219
231
|
| `ATOMIC_ACCESS_POLICY_REQUIRED` | no | Deprecated compatibility code; current SDK flows never emit it |
|
|
220
|
-
| `ACCESS_POLICY_CONFIGURATION_FAILED` | no | Deposit exists;
|
|
232
|
+
| `ACCESS_POLICY_CONFIGURATION_FAILED` | no | Deposit exists; inspect policy tx first, attach only if needed; never repeat the cash-out. |
|
|
221
233
|
| `SOURCE_ROUTE_UNSUPPORTED_IN_PREPARE` | no | Execute Relay with a signer first, then prepare a Base-USDC cashout |
|
|
222
234
|
| `SOURCE_RECIPIENT_MISMATCH` | no | Route Base USDC to the cashout depositor |
|
|
223
235
|
| `SOURCE_CAPABILITIES_FAILED` | yes | Retry discovery or fall back to Base USDC |
|
|
@@ -257,7 +269,8 @@ and tool results.
|
|
|
257
269
|
Prove your integration against `environment: 'staging'` with a funded test
|
|
258
270
|
wallet. Never wait on a buyer - buyer-side is out of your scope:
|
|
259
271
|
|
|
260
|
-
1. `cashout()` a small amount (1–2 USDC) → capture `depositId
|
|
272
|
+
1. `cashout()` a small amount (1–2 USDC) → capture `depositId` and, for a
|
|
273
|
+
restricted payout, `accessPolicyTxHash`.
|
|
261
274
|
2. `order(depositId)` shows `awaiting-buyer` (retry through indexer lag).
|
|
262
275
|
3. `orders(owner)` includes the deposit.
|
|
263
276
|
4. `withdraw(depositId)` → transaction succeeds.
|
package/README.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# @zkp2p/cash
|
|
2
2
|
|
|
3
|
-
Route any Relay-supported EVM source asset into Base USDC, then cash out to
|
|
4
|
-
on Venmo, Revolut, Wise, Zelle, and more at the live Chainlink market
|
|
5
|
-
with zero spread and no centralized off-ramp provider.
|
|
3
|
+
Route any Relay-supported EVM source asset into Base USDC, then cash out to
|
|
4
|
+
fiat on Venmo, Revolut, Wise, Zelle, and more at the live Chainlink market
|
|
5
|
+
rate, with zero spread and no centralized off-ramp provider.
|
|
6
6
|
|
|
7
7
|
Peer Cash is an **offramp-only** SDK for the [ZKP2P](https://peer.xyz)
|
|
8
8
|
protocol. The cashing-out user is the maker: their USDC becomes a deposit in
|
|
@@ -12,18 +12,13 @@ No hosted widget, no provider custody, no quote engine to maintain.
|
|
|
12
12
|
|
|
13
13
|
**[npm](https://www.npmjs.com/package/@zkp2p/cash)** · **[Lifecycle and recovery](docs/lifecycle-and-recovery.md)** · **[Agent integration manual](AGENTS.md)**
|
|
14
14
|
|
|
15
|
-
##
|
|
16
|
-
|
|
17
|
-
Peer Cash and the general ZKP2P SDK serve different integration depths:
|
|
15
|
+
## Install
|
|
18
16
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
| `@zkp2p/sdk` | You are composing directly with the Peer protocol | General maker and taker operations, deposits, intents, proofs, quotes, vaults, rate managers, referrals, hooks, and API helpers. Your application owns the workflow and protocol choices. |
|
|
17
|
+
```sh
|
|
18
|
+
npm install @zkp2p/cash viem
|
|
19
|
+
```
|
|
23
20
|
|
|
24
|
-
|
|
25
|
-
cannot express custom spreads, buyer-side proof flows, vaults, disputes, or
|
|
26
|
-
arbitrary protocol operations.
|
|
21
|
+
## Quickstart
|
|
27
22
|
|
|
28
23
|
```ts
|
|
29
24
|
import { createCashClient, usdc } from '@zkp2p/cash';
|
|
@@ -43,13 +38,15 @@ const fillStats = await cash.fillStats();
|
|
|
43
38
|
const pairStats = fillStats['venmo:USD'];
|
|
44
39
|
const multiCurrencyStats = fillStats['revolut:EUR+GBP+USD'];
|
|
45
40
|
|
|
46
|
-
const { depositId } = await cash.cashout(
|
|
41
|
+
const { depositId, accessPolicyTxHash } = await cash.cashout(
|
|
47
42
|
{
|
|
48
43
|
amount: usdc(1000),
|
|
49
44
|
receive: { platform: 'venmo', currency: 'USD', payee: '@you' },
|
|
50
45
|
},
|
|
51
46
|
{ signer }, // any viem WalletClient on Base, including an EOA
|
|
52
47
|
);
|
|
48
|
+
// Venmo, Cash App, and PayPal return only after their access policy confirms.
|
|
49
|
+
console.log(depositId, accessPolicyTxHash);
|
|
53
50
|
|
|
54
51
|
// One method can offer several currencies. The buyer chooses the fill
|
|
55
52
|
// currency, and each option resolves at its own live oracle rate.
|
|
@@ -84,52 +81,18 @@ for await (const order of cash.watch(depositId)) {
|
|
|
84
81
|
}
|
|
85
82
|
```
|
|
86
83
|
|
|
87
|
-
##
|
|
88
|
-
|
|
89
|
-
Use the same six-character referral code shown in your Peer mobile or web app.
|
|
90
|
-
No API key, registration transaction, or separate receiving address is needed:
|
|
91
|
-
the referral code already belongs to your Peer Privy wallet.
|
|
92
|
-
|
|
93
|
-
```ts
|
|
94
|
-
const cash = createCashClient({
|
|
95
|
-
environment: 'production',
|
|
96
|
-
referralCode: 'ABC123',
|
|
97
|
-
});
|
|
98
|
-
```
|
|
99
|
-
|
|
100
|
-
The SDK normalizes the value and stamps `peer-ref-ABC123` into ERC-8021
|
|
101
|
-
attribution on the deposit transaction. When that liquidity is filled, Curator
|
|
102
|
-
pays the code owner 50 bps, capped by the configured Peer service fee. This is
|
|
103
|
-
the deposit-level integration path: it replaces the maker L1/L2 referral split
|
|
104
|
-
for that deposit instead of enrolling the cashing-out user as your referee.
|
|
105
|
-
|
|
106
|
-
The mapping is permanent. If you later customize your displayed Peer referral
|
|
107
|
-
code, open deposits carrying the old code still pay the same wallet. Include at
|
|
108
|
-
most one `peer-ref-XXXXXX` marker; an unknown or conflicting marker receives no
|
|
109
|
-
integration share. The existing `referrer` option remains available for
|
|
110
|
-
analytics-only ERC-8021 codes such as `acme-app`.
|
|
84
|
+
## Pick the right SDK
|
|
111
85
|
|
|
112
|
-
|
|
86
|
+
Peer Cash and the general ZKP2P SDK serve different integration depths:
|
|
113
87
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
source: {
|
|
119
|
-
chainId: 1,
|
|
120
|
-
currency: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
|
|
121
|
-
tradeType: 'EXACT_INPUT',
|
|
122
|
-
},
|
|
123
|
-
receive: { platform: 'venmo', currency: 'USD', payee: { offchainId: '@you' } },
|
|
124
|
-
},
|
|
125
|
-
{ signer, sourceSigner },
|
|
126
|
-
);
|
|
88
|
+
| Package | Use it when | Boundary |
|
|
89
|
+
| ------------- | ------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
90
|
+
| `@zkp2p/cash` | Cash-out is the product | Offramp only. The user is always the maker, the destination is Base USDC, pricing is the live Chainlink rate at fill with zero spread, and the SDK owns the resumable order lifecycle. |
|
|
91
|
+
| `@zkp2p/sdk` | You are composing directly with the Peer protocol | General maker and taker operations, deposits, intents, proofs, quotes, vaults, rate managers, referrals, hooks, and API helpers. Your application owns the workflow and protocol choices. |
|
|
127
92
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
console.log(source?.transactions?.origin, source?.transactions?.destination);
|
|
132
|
-
```
|
|
93
|
+
Peer Cash is a narrow facade over `@zkp2p/sdk`, not a replacement for it. It
|
|
94
|
+
cannot express custom spreads, buyer-side proof flows, vaults, disputes, or
|
|
95
|
+
arbitrary protocol operations.
|
|
133
96
|
|
|
134
97
|
## The core verbs
|
|
135
98
|
|
|
@@ -165,32 +128,55 @@ Peer Cash transaction, including approves, carries ERC-8021 attribution:
|
|
|
165
128
|
`peer-cash` first, optional `peer-ref-XXXXXX` from `referralCode` next, and your
|
|
166
129
|
analytics-only `referrer` code(s) after it.
|
|
167
130
|
|
|
131
|
+
Order reads fail closed against the same active catalog. If any method on an
|
|
132
|
+
indexed deposit is unsupported, `orders()` excludes the whole deposit and
|
|
133
|
+
`order()` returns `ORDER_NOT_FOUND`; Peer Cash never partially reclassifies a
|
|
134
|
+
mixed historical deposit.
|
|
135
|
+
|
|
136
|
+
## Payout rails and access policies
|
|
137
|
+
|
|
138
|
+
| Payout rail | Access-policy behavior | New payee registration |
|
|
139
|
+
| --------------------- | -------------------------------------------------------------------------- | -------------------------------------------------------------------------------------- |
|
|
140
|
+
| Venmo / Cash App | Four groups attach after deposit confirmation | Curator validates the live handle |
|
|
141
|
+
| PayPal | Same four-group follow-up | Requires a Peer TEE browser-extension identity attestation |
|
|
142
|
+
| Wise | No access-policy follow-up | Requires a Peer TEE browser-extension identity attestation |
|
|
143
|
+
| Other supported rails | No access-policy follow-up; use `capabilities()` for currencies and format | Follow the `payeeHint`; live-validation behavior is described in the integration guide |
|
|
144
|
+
|
|
168
145
|
No platform requires an atomic access-policy flow. `cashout()` and `prepare()`
|
|
169
146
|
work with any viem `WalletClient`, including a local or externally connected
|
|
170
147
|
EOA; no Privy wallet or signer API is required. The deprecated
|
|
171
148
|
`requiresAtomicAccessPolicy` capability remains for wire compatibility and is
|
|
172
149
|
always `false`.
|
|
173
150
|
|
|
174
|
-
Venmo, Cash App, and PayPal cash-outs
|
|
175
|
-
Pay groups by default.
|
|
176
|
-
|
|
151
|
+
Venmo, Cash App, and PayPal cash-outs restrict intent signaling to Plus, Pro,
|
|
152
|
+
Peer Makers, and Peer Pay groups by default. If any payout leg uses one of
|
|
153
|
+
those platforms, signed `cashout()` creates the deposit first, then uses the
|
|
154
|
+
same wallet to submit and confirm the policy transaction; this intentionally
|
|
177
155
|
leaves a brief non-atomic interval. Prepared integrations receive
|
|
178
|
-
`accessPolicyRequired: true`
|
|
179
|
-
`
|
|
156
|
+
`accessPolicyRequired: true` and, after confirming `createDeposit`, must call
|
|
157
|
+
`finalizePreparedCashout(receipt)` followed by
|
|
180
158
|
`prepareAccessPolicy(depositId)`. Other platforms do not need the follow-up.
|
|
159
|
+
|
|
181
160
|
If policy attachment fails, `ACCESS_POLICY_CONFIGURATION_FAILED.recovery`
|
|
182
|
-
identifies the existing deposit and any submitted policy transaction.
|
|
183
|
-
create another cash-out
|
|
161
|
+
identifies the existing deposit and any submitted policy transaction. Never
|
|
162
|
+
create another cash-out. When `recovery.transactionHash` is present, inspect
|
|
163
|
+
that transaction before resubmitting; otherwise prepare the policy again with
|
|
164
|
+
the same depositor wallet.
|
|
184
165
|
|
|
185
166
|
`capabilities()` presents Zelle as one platform. A cashout with
|
|
186
167
|
`receive.platform: 'zelle'` attaches only the generic Zelle payment method to
|
|
187
168
|
the deposit. Bank-specific capture routing is outside this maker-side SDK and
|
|
188
169
|
never changes the on-chain payment method.
|
|
189
170
|
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
`
|
|
193
|
-
|
|
171
|
+
`capabilities()` tells you which platforms need a verified identity for a new
|
|
172
|
+
payee registration (`requiresIdentityAttestation` - Wise and PayPal today).
|
|
173
|
+
The SDK accepts an `identityAttestation` in structured payee data but does not
|
|
174
|
+
mint one. First-party Peer web obtains it through the Peer TEE browser
|
|
175
|
+
extension. An already-registered Wise or PayPal handle can be reused with bare
|
|
176
|
+
payee data. A new handle without its signed attestation fails during curator
|
|
177
|
+
registration with `PAYEE_VERIFICATION_REQUIRED`, before funds move on-chain.
|
|
178
|
+
|
|
179
|
+
## Source routing (any EVM asset in)
|
|
194
180
|
|
|
195
181
|
The default/minimal flow is unchanged: pass Base USDC base units to
|
|
196
182
|
`estimate()` and `cashout()`. For any other source asset, pass `source` to
|
|
@@ -202,6 +188,27 @@ The destination is always canonical Base USDC
|
|
|
202
188
|
discovered and quoted by `@relayprotocol/relay-sdk`, not a static token
|
|
203
189
|
allowlist.
|
|
204
190
|
|
|
191
|
+
```ts
|
|
192
|
+
const { depositId, accessPolicyTxHash, source } = await cash.cashout(
|
|
193
|
+
{
|
|
194
|
+
amount: 10_000_000n, // exact input: 10 USDC in source-token base units
|
|
195
|
+
source: {
|
|
196
|
+
chainId: 1,
|
|
197
|
+
currency: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
|
|
198
|
+
tradeType: 'EXACT_INPUT',
|
|
199
|
+
},
|
|
200
|
+
receive: { platform: 'venmo', currency: 'USD', payee: { offchainId: '@you' } },
|
|
201
|
+
},
|
|
202
|
+
{ signer, sourceSigner },
|
|
203
|
+
);
|
|
204
|
+
|
|
205
|
+
// source.amount is Relay's guaranteed minimum Base USDC output and the exact
|
|
206
|
+
// amount deposited into the cash-out order. It is not the route's actual output.
|
|
207
|
+
console.log(source?.amount, source?.requestId);
|
|
208
|
+
console.log(source?.transactions?.origin, source?.transactions?.destination);
|
|
209
|
+
console.log(accessPolicyTxHash); // present because this example uses Venmo
|
|
210
|
+
```
|
|
211
|
+
|
|
205
212
|
Routes that submit more than one source-chain transaction (approve, then
|
|
206
213
|
route) require a nonce-managed source signer -
|
|
207
214
|
`privateKeyToAccount(pk, { nonceManager })` from viem. Without one the SDK
|
|
@@ -209,12 +216,6 @@ refuses the route preflight with `SOURCE_NONCE_MANAGER_REQUIRED` instead of
|
|
|
209
216
|
letting the route transaction reuse the approval's nonce and revert
|
|
210
217
|
mid-route. Browser wallets are unaffected.
|
|
211
218
|
|
|
212
|
-
`capabilities()` tells you which platforms need a verified identity for a new
|
|
213
|
-
payee registration (`requiresIdentityAttestation` - Wise and PayPal today).
|
|
214
|
-
An already-registered Wise or PayPal handle can be reused with bare payee data.
|
|
215
|
-
A new handle without its signed attestation fails during curator registration
|
|
216
|
-
with `PAYEE_VERIFICATION_REQUIRED`, before funds move on-chain.
|
|
217
|
-
|
|
218
219
|
## Source-route recovery
|
|
219
220
|
|
|
220
221
|
Persist `depositId`, transaction hashes, and the Relay `requestId` as soon as
|
|
@@ -242,7 +243,9 @@ they are available. A source-routed result includes both a flat
|
|
|
242
243
|
wallet activity and the supplied recovery action before any retry.
|
|
243
244
|
- `ACCESS_POLICY_CONFIGURATION_FAILED`: the deposit exists, but its required
|
|
244
245
|
Venmo, Cash App, or PayPal policy was not confirmed. Do not cash out again;
|
|
245
|
-
|
|
246
|
+
inspect `recovery.transactionHash` when present, then retry
|
|
247
|
+
`prepareAccessPolicy(error.recovery.depositId)` only if the prior policy
|
|
248
|
+
transaction did not succeed.
|
|
246
249
|
|
|
247
250
|
Wallet clients pinned to the wrong chain fail with `SIGNER_CHAIN_MISMATCH`
|
|
248
251
|
before a quote or transaction is submitted. Chainless wallets are checked
|
|
@@ -289,6 +292,31 @@ awaiting-buyer ──────────► matched ───────
|
|
|
289
292
|
|
|
290
293
|
Deep dive: [docs/lifecycle-and-recovery.md](docs/lifecycle-and-recovery.md).
|
|
291
294
|
|
|
295
|
+
## Earn the integration share
|
|
296
|
+
|
|
297
|
+
Use the same six-character referral code shown in your Peer mobile or web app.
|
|
298
|
+
No API key, registration transaction, or separate receiving address is needed:
|
|
299
|
+
the referral code already belongs to your Peer Privy wallet.
|
|
300
|
+
|
|
301
|
+
```ts
|
|
302
|
+
const cash = createCashClient({
|
|
303
|
+
environment: 'production',
|
|
304
|
+
referralCode: 'ABC123',
|
|
305
|
+
});
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
The SDK normalizes the value and stamps `peer-ref-ABC123` into ERC-8021
|
|
309
|
+
attribution on the deposit transaction. When that liquidity is filled, Curator
|
|
310
|
+
pays the code owner 50 bps, capped by the configured Peer service fee. This is
|
|
311
|
+
the deposit-level integration path: it replaces the maker L1/L2 referral split
|
|
312
|
+
for that deposit instead of enrolling the cashing-out user as your referee.
|
|
313
|
+
|
|
314
|
+
The mapping is permanent. If you later customize your displayed Peer referral
|
|
315
|
+
code, open deposits carrying the old code still pay the same wallet. Include at
|
|
316
|
+
most one `peer-ref-XXXXXX` marker; an unknown or conflicting marker receives no
|
|
317
|
+
integration share. The existing `referrer` option remains available for
|
|
318
|
+
analytics-only ERC-8021 codes such as `acme-app`.
|
|
319
|
+
|
|
292
320
|
## For agents
|
|
293
321
|
|
|
294
322
|
- `cashout`/`withdraw`/`topUp` have unsigned counterparts (`prepare`,
|
|
@@ -296,6 +324,9 @@ Deep dive: [docs/lifecycle-and-recovery.md](docs/lifecycle-and-recovery.md).
|
|
|
296
324
|
before signing, then submit the matching `txs[]` in order.
|
|
297
325
|
- Mutating tool calls return unsigned transactions by default; signing stays
|
|
298
326
|
with the host that owns custody, policy, and user approval.
|
|
327
|
+
- After a prepared restricted cash-out confirms, the host adapter must call
|
|
328
|
+
`finalizePreparedCashout(receipt)` and `prepareAccessPolicy(depositId)`; these
|
|
329
|
+
receipt/signing operations are `CashClient` methods, not built-in tool calls.
|
|
299
330
|
- Every error carries `code`, `retryable`, and a `remediation` sentence.
|
|
300
331
|
- Every order carries `nextActions: ('wait' | 'withdraw')[]` - no heuristics.
|
|
301
332
|
- Every wire type has a zod schema + JSON codec - state crosses process
|
|
@@ -326,12 +357,6 @@ defaults to `https://api-staging.zkp2p.xyz`. Indexer, curator, and Relay
|
|
|
326
357
|
options remain overridable via `createCashClient` options. Base USDC on Base
|
|
327
358
|
is the default source and the only destination asset for cashout orders.
|
|
328
359
|
|
|
329
|
-
## Install
|
|
330
|
-
|
|
331
|
-
```sh
|
|
332
|
-
npm install @zkp2p/cash viem
|
|
333
|
-
```
|
|
334
|
-
|
|
335
360
|
## Examples
|
|
336
361
|
|
|
337
362
|
Runnable first-party examples in [`examples/`](examples):
|
|
@@ -346,6 +371,13 @@ dependency currently ships from private source. Onchain custody is enforced by
|
|
|
346
371
|
the protocol: only the contract holds funds, and only the maker can withdraw
|
|
347
372
|
an unmatched deposit.
|
|
348
373
|
|
|
374
|
+
## Contributing
|
|
375
|
+
|
|
376
|
+
[CLAUDE.md](https://github.com/zkp2p/peer-cash/blob/main/CLAUDE.md) is the
|
|
377
|
+
contributor guide: ground rules, repo layout, the `bun run ci` gate, and the
|
|
378
|
+
release/publish process. `AGENTS.md` is the shipped manual for agents using
|
|
379
|
+
the package, not the contributor entry point.
|
|
380
|
+
|
|
349
381
|
## License
|
|
350
382
|
|
|
351
383
|
MIT
|
|
@@ -194,7 +194,7 @@ var errors = {
|
|
|
194
194
|
code: "PAYEE_VERIFICATION_REQUIRED",
|
|
195
195
|
message: `${platform} requires a verified maker identity attestation to register a payee; a bare handle is not accepted.`,
|
|
196
196
|
retryable: false,
|
|
197
|
-
remediation: `Register this ${platform} payee through
|
|
197
|
+
remediation: `Register this ${platform} payee through Peer web and its TEE browser extension, which produces the signed identity attestation, before cashing out. capabilities() flags such platforms with requiresIdentityAttestation: true.`
|
|
198
198
|
},
|
|
199
199
|
{ cause }
|
|
200
200
|
),
|
|
@@ -411,7 +411,7 @@ var errors = {
|
|
|
411
411
|
code: "ACCESS_POLICY_CONFIGURATION_FAILED",
|
|
412
412
|
message: `Cash-out deposit ${depositId} was created, but its access policy could not be confirmed.`,
|
|
413
413
|
retryable: false,
|
|
414
|
-
remediation: `Do not create another cash-out.
|
|
414
|
+
remediation: `Do not create another cash-out. If recovery.transactionHash is present, inspect that policy transaction first. Otherwise, or if it is confirmed reverted, submit and confirm prepareAccessPolicy(recovery.depositId) with the same depositor wallet.`,
|
|
415
415
|
recovery: {
|
|
416
416
|
kind: "configure-cashout-access-policy",
|
|
417
417
|
depositId,
|
|
@@ -306,12 +306,16 @@ interface CashPlatformCapability {
|
|
|
306
306
|
payeeHint: string;
|
|
307
307
|
/**
|
|
308
308
|
* When true, registering a payee for this platform requires a signed maker
|
|
309
|
-
* identity attestation the SDK cannot produce -
|
|
310
|
-
*
|
|
309
|
+
* identity attestation the SDK cannot produce. First-party Peer web obtains
|
|
310
|
+
* it through the Peer TEE browser extension. Existing registrations can be
|
|
311
|
+
* reused with bare payee data; a new bare handle throws
|
|
311
312
|
* `PAYEE_VERIFICATION_REQUIRED`.
|
|
312
313
|
*/
|
|
313
314
|
requiresIdentityAttestation: boolean;
|
|
314
|
-
/**
|
|
315
|
+
/**
|
|
316
|
+
* @deprecated Always false. This does not report the sequential restricted-
|
|
317
|
+
* platform policy; prepared hosts must inspect `PrepareResult.accessPolicyRequired`.
|
|
318
|
+
*/
|
|
315
319
|
requiresAtomicAccessPolicy: boolean;
|
|
316
320
|
}
|
|
317
321
|
interface CashCapabilities {
|
|
@@ -584,7 +588,7 @@ interface CashoutResult {
|
|
|
584
588
|
onchainDepositId: bigint;
|
|
585
589
|
/** Optimistic snapshot (`awaiting-buyer`); poll `order(depositId)` for live state. */
|
|
586
590
|
order: CashOrder;
|
|
587
|
-
/** Confirmed access-policy transaction
|
|
591
|
+
/** Confirmed access-policy transaction when any payout leg is Venmo, Cash App, or PayPal. */
|
|
588
592
|
accessPolicyTxHash?: Hash;
|
|
589
593
|
/** Present when `cashout()` first routed a source asset through Relay. */
|
|
590
594
|
source?: {
|
|
@@ -612,7 +616,7 @@ interface PrepareResult {
|
|
|
612
616
|
register: {
|
|
613
617
|
hashedOnchainIds: string[];
|
|
614
618
|
};
|
|
615
|
-
/** Whether the host must submit
|
|
619
|
+
/** Whether the host must submit and confirm the policy after `createDeposit` confirms. */
|
|
616
620
|
accessPolicyRequired: boolean;
|
|
617
621
|
}
|
|
618
622
|
/** Confirmed createDeposit receipt from an externally executed prepare() plan. */
|
|
@@ -306,12 +306,16 @@ interface CashPlatformCapability {
|
|
|
306
306
|
payeeHint: string;
|
|
307
307
|
/**
|
|
308
308
|
* When true, registering a payee for this platform requires a signed maker
|
|
309
|
-
* identity attestation the SDK cannot produce -
|
|
310
|
-
*
|
|
309
|
+
* identity attestation the SDK cannot produce. First-party Peer web obtains
|
|
310
|
+
* it through the Peer TEE browser extension. Existing registrations can be
|
|
311
|
+
* reused with bare payee data; a new bare handle throws
|
|
311
312
|
* `PAYEE_VERIFICATION_REQUIRED`.
|
|
312
313
|
*/
|
|
313
314
|
requiresIdentityAttestation: boolean;
|
|
314
|
-
/**
|
|
315
|
+
/**
|
|
316
|
+
* @deprecated Always false. This does not report the sequential restricted-
|
|
317
|
+
* platform policy; prepared hosts must inspect `PrepareResult.accessPolicyRequired`.
|
|
318
|
+
*/
|
|
315
319
|
requiresAtomicAccessPolicy: boolean;
|
|
316
320
|
}
|
|
317
321
|
interface CashCapabilities {
|
|
@@ -584,7 +588,7 @@ interface CashoutResult {
|
|
|
584
588
|
onchainDepositId: bigint;
|
|
585
589
|
/** Optimistic snapshot (`awaiting-buyer`); poll `order(depositId)` for live state. */
|
|
586
590
|
order: CashOrder;
|
|
587
|
-
/** Confirmed access-policy transaction
|
|
591
|
+
/** Confirmed access-policy transaction when any payout leg is Venmo, Cash App, or PayPal. */
|
|
588
592
|
accessPolicyTxHash?: Hash;
|
|
589
593
|
/** Present when `cashout()` first routed a source asset through Relay. */
|
|
590
594
|
source?: {
|
|
@@ -612,7 +616,7 @@ interface PrepareResult {
|
|
|
612
616
|
register: {
|
|
613
617
|
hashedOnchainIds: string[];
|
|
614
618
|
};
|
|
615
|
-
/** Whether the host must submit
|
|
619
|
+
/** Whether the host must submit and confirm the policy after `createDeposit` confirms. */
|
|
616
620
|
accessPolicyRequired: boolean;
|
|
617
621
|
}
|
|
618
622
|
/** Confirmed createDeposit receipt from an externally executed prepare() plan. */
|
package/dist/index.cjs
CHANGED
|
@@ -676,7 +676,7 @@ var errors = {
|
|
|
676
676
|
code: "PAYEE_VERIFICATION_REQUIRED",
|
|
677
677
|
message: `${platform} requires a verified maker identity attestation to register a payee; a bare handle is not accepted.`,
|
|
678
678
|
retryable: false,
|
|
679
|
-
remediation: `Register this ${platform} payee through
|
|
679
|
+
remediation: `Register this ${platform} payee through Peer web and its TEE browser extension, which produces the signed identity attestation, before cashing out. capabilities() flags such platforms with requiresIdentityAttestation: true.`
|
|
680
680
|
},
|
|
681
681
|
{ cause }
|
|
682
682
|
),
|
|
@@ -893,7 +893,7 @@ var errors = {
|
|
|
893
893
|
code: "ACCESS_POLICY_CONFIGURATION_FAILED",
|
|
894
894
|
message: `Cash-out deposit ${depositId} was created, but its access policy could not be confirmed.`,
|
|
895
895
|
retryable: false,
|
|
896
|
-
remediation: `Do not create another cash-out.
|
|
896
|
+
remediation: `Do not create another cash-out. If recovery.transactionHash is present, inspect that policy transaction first. Otherwise, or if it is confirmed reverted, submit and confirm prepareAccessPolicy(recovery.depositId) with the same depositor wallet.`,
|
|
897
897
|
recovery: {
|
|
898
898
|
kind: "configure-cashout-access-policy",
|
|
899
899
|
depositId,
|
|
@@ -2272,8 +2272,6 @@ function createCashClient(options) {
|
|
|
2272
2272
|
const payoutInput = validatePayout(input);
|
|
2273
2273
|
const client = await signingClient("cashout", opts);
|
|
2274
2274
|
const owner = opts.signer.account.address;
|
|
2275
|
-
let sourceResult;
|
|
2276
|
-
let cashoutAmount = input.amount;
|
|
2277
2275
|
if (input.source) {
|
|
2278
2276
|
const sourceSigner = opts.sourceSigner ?? (input.source.chainId === BASE_CHAIN_ID ? opts.signer : void 0);
|
|
2279
2277
|
if (!sourceSigner?.account) throw errors.signerRequired("source cashout");
|
|
@@ -2294,7 +2292,7 @@ function createCashClient(options) {
|
|
|
2294
2292
|
if (relayQuote.outputAmount < MIN_CASHOUT_AMOUNT) {
|
|
2295
2293
|
throw errors.amountBelowMinimum(relayQuote.outputAmount, MIN_CASHOUT_AMOUNT);
|
|
2296
2294
|
}
|
|
2297
|
-
cashoutAmount = relayQuote.outputAmount;
|
|
2295
|
+
const cashoutAmount = relayQuote.outputAmount;
|
|
2298
2296
|
const depositInput2 = validateDepositInput(cashoutAmount, input, payoutInput);
|
|
2299
2297
|
const params2 = await buildDepositParams(client, depositInput2);
|
|
2300
2298
|
const escrow2 = client.escrowV2Address ?? client.escrowAddress;
|
|
@@ -2311,7 +2309,6 @@ function createCashClient(options) {
|
|
|
2311
2309
|
txHashes: executed.txHashes,
|
|
2312
2310
|
...executed.transactions ? { transactions: executed.transactions } : {}
|
|
2313
2311
|
};
|
|
2314
|
-
sourceResult = routedSource;
|
|
2315
2312
|
try {
|
|
2316
2313
|
await waitForBaseSignerAfterRelay(
|
|
2317
2314
|
client,
|
|
@@ -2445,8 +2442,7 @@ function createCashClient(options) {
|
|
|
2445
2442
|
escrowAddress: resolved.escrowAddress,
|
|
2446
2443
|
onchainDepositId: resolved.onchainDepositId,
|
|
2447
2444
|
order,
|
|
2448
|
-
...accessPolicyTxHash ? { accessPolicyTxHash } : {}
|
|
2449
|
-
...sourceResult ? { source: sourceResult } : {}
|
|
2445
|
+
...accessPolicyTxHash ? { accessPolicyTxHash } : {}
|
|
2450
2446
|
};
|
|
2451
2447
|
},
|
|
2452
2448
|
async prepare(input) {
|