@pulsepairs/sdk 0.2.0 → 0.3.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/README.md +41 -0
- package/dist/accountKit.d.ts +68 -1
- package/dist/accountKit.js +146 -61
- package/dist/index.d.ts +1 -0
- package/dist/index.js +5 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -138,6 +138,45 @@ const signOrder = bareErc1271Signer((td) => rainSmartWalletClient.signTypedData(
|
|
|
138
138
|
const signature = await signOrder(buildOrderTypedData({ cfg, settlementAddress, message }));
|
|
139
139
|
```
|
|
140
140
|
|
|
141
|
+
### Low-level "raw tx" tier (v0.3.0) — send with your own AA session
|
|
142
|
+
|
|
143
|
+
If you run your own Account-Abstraction send path (like rain.trade's `sendTxs`
|
|
144
|
+
through their root session), use the **transport-free primitives** instead of the
|
|
145
|
+
signer class. They return rain's exact `RawTransaction` shape (`{ to, data, value? }`)
|
|
146
|
+
for the on-chain setup, and sign orders **locally** with the popup-less
|
|
147
|
+
order-session key — the part your send-only session structurally cannot do
|
|
148
|
+
(a root session packs the *owner* entity → `isValidSignature` returns `0xffffffff`).
|
|
149
|
+
|
|
150
|
+
The one mental-model flip: **placing an order is not a transaction.** It is an
|
|
151
|
+
off-chain EIP-712 signature POSTed to the matcher; the relayer transacts the fill.
|
|
152
|
+
So there is no `buildPlaceOrderTx` — you `signWithOrderSession(...)` and `postOrder`.
|
|
153
|
+
|
|
154
|
+
```ts
|
|
155
|
+
import {
|
|
156
|
+
buildApproveSettlementTx, buildInstallOrderSessionTx, signWithOrderSession,
|
|
157
|
+
buildOrderTypedData,
|
|
158
|
+
} from "@pulsepairs/sdk";
|
|
159
|
+
import { arbitrum } from "viem/chains";
|
|
160
|
+
|
|
161
|
+
// Onboard once — batch both raw txs into ONE userOp through YOUR session:
|
|
162
|
+
const approveTx = buildApproveSettlementTx({ usdt: cfg.usdtAddress, settlement });
|
|
163
|
+
const { tx: installTx, session } = await buildInstallOrderSessionTx({ sca, chain: arbitrum });
|
|
164
|
+
await sendTxs([approveTx, installTx]); // your batched, gasless send
|
|
165
|
+
persist(session); // { v, privateKey, entityId, expirySec }
|
|
166
|
+
|
|
167
|
+
// Every order after that — no chain, no gas, no popup:
|
|
168
|
+
const typedData = buildOrderTypedData({ cfg, settlementAddress, message /* maker: sca, maxFee, … */ });
|
|
169
|
+
const signature = await signWithOrderSession({ session, sca, chain: arbitrum, alchemyApiKey, typedData });
|
|
170
|
+
await api.postOrder({ maker: sca, /* … */, signature });
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
Two tiers, adopt in order: **MVP** = `approve` (1 raw tx) + `bareErc1271Signer`
|
|
174
|
+
owner-path (1 popup/order, zero new code) → **Production** = `approve` + install
|
|
175
|
+
(batched) + `signWithOrderSession` (popup-less). Full walkthrough in
|
|
176
|
+
[`examples/rain-taker.ts`](examples/rain-taker.ts); rationale in
|
|
177
|
+
`UPDOWN_RAIN_RAWTX_SDK_DESIGN.md`. The on-chain acceptance of these bytes on
|
|
178
|
+
rain's exact MA-v2 impl is proven by `updown-contracts/test/OrderSessionForkTest.t.sol`.
|
|
179
|
+
|
|
141
180
|
---
|
|
142
181
|
|
|
143
182
|
## Account Kit: the two rules you cannot break
|
|
@@ -231,6 +270,8 @@ Account Kit UpDownAccountKitSigner (connect, onboard, approve, withdraw,
|
|
|
231
270
|
signTypedDataBare, signWsAuth, isDeployed, grantSession,
|
|
232
271
|
ensureOrderSession, revokeOrderSession, hasOrderSession),
|
|
233
272
|
bareErc1271Signer, stripErc6492Wrapper, isErc6492Signature
|
|
273
|
+
Raw-tx tier buildApproveSettlementTx, buildInstallOrderSessionTx,
|
|
274
|
+
(v0.3.0) signWithOrderSession, RawTransaction, OrderSessionRecord
|
|
234
275
|
L2 HMAC auth CLOB_AUTH_TYPES, buildClobAuthTypedData, buildHmacSignature, HMAC_HEADERS
|
|
235
276
|
Enums/types OrderType, OrderSide, Option, ApiConfig, PairConfig, PostOrderBody, …
|
|
236
277
|
```
|
package/dist/accountKit.d.ts
CHANGED
|
@@ -64,6 +64,17 @@ export declare function isErc6492Signature(signature: Hex): boolean;
|
|
|
64
64
|
*/
|
|
65
65
|
export declare function stripErc6492Wrapper(signature: Hex): Hex;
|
|
66
66
|
export type RawTypedDataSigner = (typedData: TypedDataDefinition) => Promise<Hex>;
|
|
67
|
+
/**
|
|
68
|
+
* A pending on-chain call, shaped EXACTLY like rain.trade's `RawTransaction`
|
|
69
|
+
* (`rain-sdk/tx/*` → `{ to, data, value? }`) so the low-level builders below
|
|
70
|
+
* drop straight into their `sendTxs`/`sendCalls` without any adapter. `value`
|
|
71
|
+
* is optional and defaults to 0 for the UpDown setup calls (approve / install).
|
|
72
|
+
*/
|
|
73
|
+
export type RawTransaction = {
|
|
74
|
+
to: Address;
|
|
75
|
+
data: Hex;
|
|
76
|
+
value?: bigint;
|
|
77
|
+
};
|
|
67
78
|
/**
|
|
68
79
|
* Wrap ANY raw typed-data signer so its output is a BARE ERC-1271 signature
|
|
69
80
|
* the UpDown settlement can verify. Use this when the host app already owns an
|
|
@@ -126,6 +137,17 @@ export type GrantSessionResult = {
|
|
|
126
137
|
context: Hex;
|
|
127
138
|
expirySec: number;
|
|
128
139
|
};
|
|
140
|
+
export type OrderSessionRecord = {
|
|
141
|
+
v: 1;
|
|
142
|
+
/** Session private key — browser/host custody, same trust class as RainAA's
|
|
143
|
+
* IndexedDB session keys but with a strictly narrower blast radius (1271
|
|
144
|
+
* signing only, no UserOp execution). */
|
|
145
|
+
privateKey: Hex;
|
|
146
|
+
/** MA-v2 validation entity id the key is installed under on the SCA. */
|
|
147
|
+
entityId: number;
|
|
148
|
+
/** Client-side expiry (unix sec). NOT enforced on-chain. */
|
|
149
|
+
expirySec: number;
|
|
150
|
+
};
|
|
129
151
|
/**
|
|
130
152
|
* Owner-key ERC-1271 order signer + gasless custody sends on an Alchemy SCA.
|
|
131
153
|
*
|
|
@@ -202,7 +224,9 @@ export declare class UpDownAccountKitSigner {
|
|
|
202
224
|
/**
|
|
203
225
|
* Build the `installValidation` self-call that registers a fresh session
|
|
204
226
|
* key on the SCA as a signature-validation-ONLY entity (validated flow:
|
|
205
|
-
* updown-frontend/scripts/poc-session-key-fe-flow.mjs).
|
|
227
|
+
* updown-frontend/scripts/poc-session-key-fe-flow.mjs). Delegates to the
|
|
228
|
+
* shared, transport-free `buildOrderSessionInstall(...)` so the class and the
|
|
229
|
+
* standalone `buildInstallOrderSessionTx(...)` emit byte-identical calldata.
|
|
206
230
|
*/
|
|
207
231
|
private buildOrderSessionInstallCall;
|
|
208
232
|
/** The @account-kit/infra chain (Alchemy RPC config baked in) for MA-v2 clients. */
|
|
@@ -263,3 +287,46 @@ export declare class UpDownAccountKitSigner {
|
|
|
263
287
|
/** Clear in-memory state (persisted sessions, if any, are left intact). */
|
|
264
288
|
disconnect(): void;
|
|
265
289
|
}
|
|
290
|
+
/**
|
|
291
|
+
* Raw `approve(settlement, amount)` on the USDT contract as a `RawTransaction`.
|
|
292
|
+
* Defaults to an unlimited (MAX_UINT256) allowance — the amount `enterPosition`
|
|
293
|
+
* needs — matching what `UpDownAccountKitSigner.onboard/approve` send. Push it
|
|
294
|
+
* straight into rain's `sendTxs` (batched with `buildInstallOrderSessionTx`).
|
|
295
|
+
* Pure calldata: synchronous, no peer deps, no network.
|
|
296
|
+
*/
|
|
297
|
+
export declare function buildApproveSettlementTx(args: {
|
|
298
|
+
usdt: Address;
|
|
299
|
+
settlement: Address;
|
|
300
|
+
amount?: bigint;
|
|
301
|
+
}): RawTransaction;
|
|
302
|
+
/**
|
|
303
|
+
* Build the one-time popup-less-order-session install as a `RawTransaction`
|
|
304
|
+
* (the `installValidation` self-call) plus the `OrderSessionRecord` the host
|
|
305
|
+
* must persist and later feed to `signWithOrderSession`. Send `tx` through the
|
|
306
|
+
* host's own AA session — batched with `buildApproveSettlementTx` it costs one
|
|
307
|
+
* userOp. Requires the `@account-kit/*` peer deps (lazy-imported). The `sca`
|
|
308
|
+
* MUST be the account the session installs on (order.maker); `chain` is the
|
|
309
|
+
* viem chain the SCA lives on (Arbitrum One / Sepolia).
|
|
310
|
+
*/
|
|
311
|
+
export declare function buildInstallOrderSessionTx(args: {
|
|
312
|
+
sca: Address;
|
|
313
|
+
chain: Chain;
|
|
314
|
+
}): Promise<{
|
|
315
|
+
tx: RawTransaction;
|
|
316
|
+
session: OrderSessionRecord;
|
|
317
|
+
}>;
|
|
318
|
+
/**
|
|
319
|
+
* Sign EIP-712 typed data (an Order / Cancel / WS-auth) LOCALLY with a
|
|
320
|
+
* persisted order-session key, yielding the BARE ERC-1271 signature the UpDown
|
|
321
|
+
* matcher accepts. Pure local ECDSA over a MA-v2 `signerEntity` — no bundler,
|
|
322
|
+
* gas, popup, or network. The `sca` must be deployed and carry the session
|
|
323
|
+
* entity (via `buildInstallOrderSessionTx`'s tx) before the signature is used
|
|
324
|
+
* in a fill. This is the piece rain's send-only session structurally cannot do.
|
|
325
|
+
*/
|
|
326
|
+
export declare function signWithOrderSession(args: {
|
|
327
|
+
session: OrderSessionRecord;
|
|
328
|
+
sca: Address;
|
|
329
|
+
chain: Chain;
|
|
330
|
+
alchemyApiKey: string;
|
|
331
|
+
typedData: TypedDataDefinition;
|
|
332
|
+
}): Promise<Hex>;
|
package/dist/accountKit.js
CHANGED
|
@@ -356,24 +356,12 @@ export class UpDownAccountKitSigner {
|
|
|
356
356
|
}
|
|
357
357
|
this._orderSession = rec;
|
|
358
358
|
if (!this._orderSessionClient) {
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
import("@account-kit/infra"),
|
|
366
|
-
]);
|
|
367
|
-
const { LocalAccountSigner } = aaCore;
|
|
368
|
-
const { createModularAccountV2Client } = scMod;
|
|
369
|
-
const { alchemy } = infraMod;
|
|
370
|
-
this._orderSessionClient = await createModularAccountV2Client({
|
|
371
|
-
mode: "default",
|
|
372
|
-
chain: await this.infraChain(),
|
|
373
|
-
transport: alchemy({ apiKey: this.config.alchemyApiKey }),
|
|
374
|
-
signer: LocalAccountSigner.privateKeyToAccountSigner(rec.privateKey),
|
|
375
|
-
accountAddress: this._address,
|
|
376
|
-
signerEntity: { entityId: rec.entityId, isGlobalValidation: false },
|
|
359
|
+
this._orderSessionClient = await buildOrderSessionClient({
|
|
360
|
+
sca: this._address,
|
|
361
|
+
chainId: this.config.chain.id,
|
|
362
|
+
alchemyApiKey: this.config.alchemyApiKey,
|
|
363
|
+
privateKey: rec.privateKey,
|
|
364
|
+
entityId: rec.entityId,
|
|
377
365
|
});
|
|
378
366
|
}
|
|
379
367
|
return this._orderSessionClient.account;
|
|
@@ -400,51 +388,17 @@ export class UpDownAccountKitSigner {
|
|
|
400
388
|
/**
|
|
401
389
|
* Build the `installValidation` self-call that registers a fresh session
|
|
402
390
|
* key on the SCA as a signature-validation-ONLY entity (validated flow:
|
|
403
|
-
* updown-frontend/scripts/poc-session-key-fe-flow.mjs).
|
|
391
|
+
* updown-frontend/scripts/poc-session-key-fe-flow.mjs). Delegates to the
|
|
392
|
+
* shared, transport-free `buildOrderSessionInstall(...)` so the class and the
|
|
393
|
+
* standalone `buildInstallOrderSessionTx(...)` emit byte-identical calldata.
|
|
404
394
|
*/
|
|
405
395
|
async buildOrderSessionInstallCall() {
|
|
406
|
-
const
|
|
407
|
-
|
|
408
|
-
import("viem/accounts"),
|
|
409
|
-
// @ts-ignore peer dep
|
|
410
|
-
import("@account-kit/smart-contracts/experimental"),
|
|
411
|
-
// @ts-ignore viem
|
|
412
|
-
import("viem"),
|
|
413
|
-
]);
|
|
414
|
-
const { generatePrivateKey, privateKeyToAccount } = viemAccounts;
|
|
415
|
-
const { getDefaultSingleSignerValidationModuleAddress, SingleSignerValidationModule, serializeValidationConfig, semiModularAccountBytecodeAbi, } = expMod;
|
|
416
|
-
const privateKey = generatePrivateKey();
|
|
417
|
-
const sessionAddress = privateKeyToAccount(privateKey).address;
|
|
418
|
-
// Random 4-byte entity id (≥2): 0 is the owner entity, and installing an
|
|
419
|
-
// id that already exists on the account reverts — random keeps collisions
|
|
420
|
-
// with prior sessions (lost storage, other hosts) vanishingly unlikely.
|
|
421
|
-
const entityId = 2 + Math.floor(Math.random() * 0x7ffffff0);
|
|
422
|
-
const data = viemMod.encodeFunctionData({
|
|
423
|
-
abi: semiModularAccountBytecodeAbi,
|
|
424
|
-
functionName: "installValidation",
|
|
425
|
-
args: [
|
|
426
|
-
serializeValidationConfig({
|
|
427
|
-
moduleAddress: getDefaultSingleSignerValidationModuleAddress(await this.infraChain()),
|
|
428
|
-
entityId,
|
|
429
|
-
isGlobal: false,
|
|
430
|
-
isSignatureValidation: true, // can answer ERC-1271…
|
|
431
|
-
isUserOpValidation: false, // …but can never execute a UserOp
|
|
432
|
-
}),
|
|
433
|
-
[],
|
|
434
|
-
SingleSignerValidationModule.encodeOnInstallData({ entityId, signer: sessionAddress }),
|
|
435
|
-
[],
|
|
436
|
-
],
|
|
437
|
-
});
|
|
438
|
-
return {
|
|
439
|
-
call: { to: this.address, data },
|
|
440
|
-
record: { v: 1, privateKey, entityId, expirySec: Math.floor(Date.now() / 1000) + ORDER_SESSION_TTL_SEC },
|
|
441
|
-
};
|
|
396
|
+
const { tx, session } = await buildOrderSessionInstall(this.address, await this.infraChain());
|
|
397
|
+
return { call: { to: tx.to, data: tx.data }, record: session };
|
|
442
398
|
}
|
|
443
399
|
/** The @account-kit/infra chain (Alchemy RPC config baked in) for MA-v2 clients. */
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
const infra = (await import("@account-kit/infra"));
|
|
447
|
-
return this.config.chain.id === 421614 ? infra.arbitrumSepolia : infra.arbitrum;
|
|
400
|
+
infraChain() {
|
|
401
|
+
return infraChainFor(this.config.chain.id);
|
|
448
402
|
}
|
|
449
403
|
/**
|
|
450
404
|
* Build + owner-sign a WS-auth handshake and package it as `WsAuthCredentials`
|
|
@@ -621,11 +575,142 @@ export class UpDownAccountKitSigner {
|
|
|
621
575
|
this._mods = null;
|
|
622
576
|
}
|
|
623
577
|
}
|
|
578
|
+
/* ═══════════════════════════════════════════════════════════════════════
|
|
579
|
+
* Low-level ("raw tx") tier — transport-free primitives (design doc §4)
|
|
580
|
+
*
|
|
581
|
+
* These surface the exact calldata + local-signing logic the
|
|
582
|
+
* `UpDownAccountKitSigner` class uses privately, so a host that owns its own
|
|
583
|
+
* Account-Abstraction send path (rain.trade's shared session) can:
|
|
584
|
+
* 1. get UpDown's setup calls as `RawTransaction`s and push them through
|
|
585
|
+
* ITS batched userOp (`sendTxs`), and
|
|
586
|
+
* 2. sign UpDown orders LOCALLY with the popup-less order-session key.
|
|
587
|
+
* The class delegates to the same `buildOrderSessionInstall` /
|
|
588
|
+
* `buildOrderSessionClient` helpers, guaranteeing identical bytes.
|
|
589
|
+
* ═══════════════════════════════════════════════════════════════════════ */
|
|
590
|
+
/** The @account-kit/infra chain (Alchemy RPC baked in) for MA-v2 clients. */
|
|
591
|
+
async function infraChainFor(chainId) {
|
|
592
|
+
// @ts-ignore peer dep
|
|
593
|
+
const infra = (await import("@account-kit/infra"));
|
|
594
|
+
return chainId === 421614 ? infra.arbitrumSepolia : infra.arbitrum;
|
|
595
|
+
}
|
|
596
|
+
/**
|
|
597
|
+
* Build the `installValidation` self-call that registers a fresh order-session
|
|
598
|
+
* key on `sca` as a signature-validation-ONLY MA-v2 entity, plus the session
|
|
599
|
+
* material to persist. Transport-free: pure local key-gen + calldata encoding —
|
|
600
|
+
* no bundler, gas, popup, or network. `moduleChain` only selects the
|
|
601
|
+
* `SingleSignerValidationModule` address (a constant across chains today), so
|
|
602
|
+
* either an `@account-kit/infra` chain or a viem `Chain` works.
|
|
603
|
+
*/
|
|
604
|
+
async function buildOrderSessionInstall(sca, moduleChain) {
|
|
605
|
+
const [viemAccounts, expMod, viemMod] = await Promise.all([
|
|
606
|
+
// @ts-ignore viem subpath
|
|
607
|
+
import("viem/accounts"),
|
|
608
|
+
// @ts-ignore peer dep
|
|
609
|
+
import("@account-kit/smart-contracts/experimental"),
|
|
610
|
+
// @ts-ignore viem
|
|
611
|
+
import("viem"),
|
|
612
|
+
]);
|
|
613
|
+
const { generatePrivateKey, privateKeyToAccount } = viemAccounts;
|
|
614
|
+
const { getDefaultSingleSignerValidationModuleAddress, SingleSignerValidationModule, serializeValidationConfig, semiModularAccountBytecodeAbi, } = expMod;
|
|
615
|
+
const privateKey = generatePrivateKey();
|
|
616
|
+
const sessionAddress = privateKeyToAccount(privateKey).address;
|
|
617
|
+
// Random 4-byte entity id (≥2): 0 is the owner entity, and installing an
|
|
618
|
+
// id that already exists on the account reverts — random keeps collisions
|
|
619
|
+
// with prior sessions (lost storage, other hosts) vanishingly unlikely.
|
|
620
|
+
const entityId = 2 + Math.floor(Math.random() * 0x7ffffff0);
|
|
621
|
+
const data = viemMod.encodeFunctionData({
|
|
622
|
+
abi: semiModularAccountBytecodeAbi,
|
|
623
|
+
functionName: "installValidation",
|
|
624
|
+
args: [
|
|
625
|
+
serializeValidationConfig({
|
|
626
|
+
moduleAddress: getDefaultSingleSignerValidationModuleAddress(moduleChain),
|
|
627
|
+
entityId,
|
|
628
|
+
isGlobal: false,
|
|
629
|
+
isSignatureValidation: true, // can answer ERC-1271…
|
|
630
|
+
isUserOpValidation: false, // …but can never execute a UserOp
|
|
631
|
+
}),
|
|
632
|
+
[],
|
|
633
|
+
SingleSignerValidationModule.encodeOnInstallData({ entityId, signer: sessionAddress }),
|
|
634
|
+
[],
|
|
635
|
+
],
|
|
636
|
+
});
|
|
637
|
+
return {
|
|
638
|
+
tx: { to: sca, data },
|
|
639
|
+
session: { v: 1, privateKey, entityId, expirySec: Math.floor(Date.now() / 1000) + ORDER_SESSION_TTL_SEC },
|
|
640
|
+
};
|
|
641
|
+
}
|
|
642
|
+
/**
|
|
643
|
+
* Build a MA-v2 smart-wallet client bound to an order-session key's validation
|
|
644
|
+
* entity. Used only for LOCAL ERC-1271 signing (`account.signTypedData`) — the
|
|
645
|
+
* entity cannot execute UserOps — so no bundler/gas/network is exercised by the
|
|
646
|
+
* signing path. Shared by the class and the standalone `signWithOrderSession`.
|
|
647
|
+
*/
|
|
648
|
+
async function buildOrderSessionClient(args) {
|
|
649
|
+
const [aaCore, scMod, infraMod] = await Promise.all([
|
|
650
|
+
// @ts-ignore peer dep
|
|
651
|
+
import("@aa-sdk/core"),
|
|
652
|
+
// @ts-ignore peer dep
|
|
653
|
+
import("@account-kit/smart-contracts"),
|
|
654
|
+
// @ts-ignore peer dep
|
|
655
|
+
import("@account-kit/infra"),
|
|
656
|
+
]);
|
|
657
|
+
const { LocalAccountSigner } = aaCore;
|
|
658
|
+
const { createModularAccountV2Client } = scMod;
|
|
659
|
+
const { alchemy } = infraMod;
|
|
660
|
+
return createModularAccountV2Client({
|
|
661
|
+
mode: "default",
|
|
662
|
+
chain: await infraChainFor(args.chainId),
|
|
663
|
+
transport: alchemy({ apiKey: args.alchemyApiKey }),
|
|
664
|
+
signer: LocalAccountSigner.privateKeyToAccountSigner(args.privateKey),
|
|
665
|
+
accountAddress: args.sca,
|
|
666
|
+
signerEntity: { entityId: args.entityId, isGlobalValidation: false },
|
|
667
|
+
});
|
|
668
|
+
}
|
|
669
|
+
/**
|
|
670
|
+
* Raw `approve(settlement, amount)` on the USDT contract as a `RawTransaction`.
|
|
671
|
+
* Defaults to an unlimited (MAX_UINT256) allowance — the amount `enterPosition`
|
|
672
|
+
* needs — matching what `UpDownAccountKitSigner.onboard/approve` send. Push it
|
|
673
|
+
* straight into rain's `sendTxs` (batched with `buildInstallOrderSessionTx`).
|
|
674
|
+
* Pure calldata: synchronous, no peer deps, no network.
|
|
675
|
+
*/
|
|
676
|
+
export function buildApproveSettlementTx(args) {
|
|
677
|
+
return { to: args.usdt, data: encodeApprove(args.settlement, args.amount ?? MAX_UINT256) };
|
|
678
|
+
}
|
|
679
|
+
/**
|
|
680
|
+
* Build the one-time popup-less-order-session install as a `RawTransaction`
|
|
681
|
+
* (the `installValidation` self-call) plus the `OrderSessionRecord` the host
|
|
682
|
+
* must persist and later feed to `signWithOrderSession`. Send `tx` through the
|
|
683
|
+
* host's own AA session — batched with `buildApproveSettlementTx` it costs one
|
|
684
|
+
* userOp. Requires the `@account-kit/*` peer deps (lazy-imported). The `sca`
|
|
685
|
+
* MUST be the account the session installs on (order.maker); `chain` is the
|
|
686
|
+
* viem chain the SCA lives on (Arbitrum One / Sepolia).
|
|
687
|
+
*/
|
|
688
|
+
export function buildInstallOrderSessionTx(args) {
|
|
689
|
+
return buildOrderSessionInstall(args.sca, args.chain);
|
|
690
|
+
}
|
|
691
|
+
/**
|
|
692
|
+
* Sign EIP-712 typed data (an Order / Cancel / WS-auth) LOCALLY with a
|
|
693
|
+
* persisted order-session key, yielding the BARE ERC-1271 signature the UpDown
|
|
694
|
+
* matcher accepts. Pure local ECDSA over a MA-v2 `signerEntity` — no bundler,
|
|
695
|
+
* gas, popup, or network. The `sca` must be deployed and carry the session
|
|
696
|
+
* entity (via `buildInstallOrderSessionTx`'s tx) before the signature is used
|
|
697
|
+
* in a fill. This is the piece rain's send-only session structurally cannot do.
|
|
698
|
+
*/
|
|
699
|
+
export async function signWithOrderSession(args) {
|
|
700
|
+
const client = await buildOrderSessionClient({
|
|
701
|
+
sca: args.sca,
|
|
702
|
+
chainId: args.chain.id,
|
|
703
|
+
alchemyApiKey: args.alchemyApiKey,
|
|
704
|
+
privateKey: args.session.privateKey,
|
|
705
|
+
entityId: args.session.entityId,
|
|
706
|
+
});
|
|
707
|
+
return (await client.account.signTypedData(args.typedData));
|
|
708
|
+
}
|
|
624
709
|
/* ───────────────────────── calldata encoders ───────────────────────── */
|
|
625
710
|
const MAX_UINT256 = (1n << 256n) - 1n;
|
|
626
|
-
function encodeApprove(spender) {
|
|
711
|
+
function encodeApprove(spender, amount = MAX_UINT256) {
|
|
627
712
|
// approve(address,uint256) selector 0x095ea7b3
|
|
628
|
-
return ("0x095ea7b3" + pad(spender) + pad(
|
|
713
|
+
return ("0x095ea7b3" + pad(spender) + pad(amount));
|
|
629
714
|
}
|
|
630
715
|
function encodeTransfer(to, amount) {
|
|
631
716
|
// transfer(address,uint256) selector 0xa9059cbb
|
package/dist/index.d.ts
CHANGED
|
@@ -4,4 +4,5 @@ export { ORDER_TYPES, CANCEL_TYPES, WS_AUTH_TYPES, buildOrderTypedData, buildCan
|
|
|
4
4
|
export { CLOB_AUTH_TYPES, CLOB_AUTH_MESSAGE, buildClobAuthTypedData, buildHmacSignature, HMAC_HEADERS, type ClobAuthDomain, type ClobAuthMessage, } from "./auth.js";
|
|
5
5
|
export { ensureSettlementAllowance, MAX_UINT256, type EnsureAllowanceResult, } from "./approve.js";
|
|
6
6
|
export { UpDownAccountKitSigner, bareErc1271Signer, stripErc6492Wrapper, isErc6492Signature, type UpDownAccountKitConfig, type Eip1193Provider, type GrantSessionResult, type RawTypedDataSigner, } from "./accountKit.js";
|
|
7
|
+
export { buildApproveSettlementTx, buildInstallOrderSessionTx, signWithOrderSession, type RawTransaction, type OrderSessionRecord, } from "./accountKit.js";
|
|
7
8
|
export { OrderType, OrderSide, Option, type ApiConfig, type Balance, type CancelOrderBody, type Eip712Domain, type MarketDetail, type MarketListItem, type OptionValue, type OrderBookFull, type OrderBookLevel, type OrderBookSide, type OrderRow, type OrderSideKey, type OrderSideValue, type OrderStatus, type OrderTypeKey, type OrderTypeValue, type OrdersResponse, type PairConfig, type PairSymbol, type PostOrderBody, type Position, type Stats, type Trade, type Version, } from "./types.js";
|
package/dist/index.js
CHANGED
|
@@ -11,5 +11,10 @@ export { ensureSettlementAllowance, MAX_UINT256, } from "./approve.js";
|
|
|
11
11
|
// Peer deps (@account-kit/*, @aa-sdk/core) are lazy-imported; importing this
|
|
12
12
|
// module does NOT require them unless you construct/connect the signer.
|
|
13
13
|
export { UpDownAccountKitSigner, bareErc1271Signer, stripErc6492Wrapper, isErc6492Signature, } from "./accountKit.js";
|
|
14
|
+
// Low-level "raw tx" tier (design doc §4) — transport-free primitives for hosts
|
|
15
|
+
// that own their own Account-Abstraction send path (e.g. rain.trade's shared
|
|
16
|
+
// session): on-chain setup builders → rain's exact `RawTransaction` shape, plus
|
|
17
|
+
// a local order-session signer for the off-chain sigs their session can't make.
|
|
18
|
+
export { buildApproveSettlementTx, buildInstallOrderSessionTx, signWithOrderSession, } from "./accountKit.js";
|
|
14
19
|
// Types
|
|
15
20
|
export { OrderType, OrderSide, Option, } from "./types.js";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pulsepairs/sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Standalone SDK for the UpDown (PulsePairs) up/down prediction markets — matcher REST/WS client, EIP-712 order signing, trade-math, and Alchemy Account Kit (smart-account) order signing for rain.trade integration.",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"type": "module",
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
"scripts": {
|
|
22
22
|
"clean": "node -e \"fs.rmSync('dist',{recursive:true,force:true})\"",
|
|
23
23
|
"build": "npm run clean && tsc",
|
|
24
|
-
"test": "node scripts/eip712-golden.test.mjs",
|
|
24
|
+
"test": "node scripts/eip712-golden.test.mjs && node scripts/rawtx-tier.test.mjs",
|
|
25
25
|
"prepublishOnly": "npm run build && npm test",
|
|
26
26
|
"example:taker": "npx tsx examples/simple-taker.ts",
|
|
27
27
|
"example:maker": "npx tsx examples/simple-maker.ts",
|