@xona-labs/xpay 0.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/LICENSE +21 -0
- package/README.md +226 -0
- package/dist/cli/accounts.d.ts +13 -0
- package/dist/cli/accounts.d.ts.map +1 -0
- package/dist/cli/accounts.js +66 -0
- package/dist/cli/accounts.js.map +1 -0
- package/dist/cli/balance.d.ts +14 -0
- package/dist/cli/balance.d.ts.map +1 -0
- package/dist/cli/balance.js +60 -0
- package/dist/cli/balance.js.map +1 -0
- package/dist/cli/common.d.ts +20 -0
- package/dist/cli/common.d.ts.map +1 -0
- package/dist/cli/common.js +58 -0
- package/dist/cli/common.js.map +1 -0
- package/dist/cli/discover.d.ts +12 -0
- package/dist/cli/discover.d.ts.map +1 -0
- package/dist/cli/discover.js +69 -0
- package/dist/cli/discover.js.map +1 -0
- package/dist/cli/guardrail.d.ts +16 -0
- package/dist/cli/guardrail.d.ts.map +1 -0
- package/dist/cli/guardrail.js +71 -0
- package/dist/cli/guardrail.js.map +1 -0
- package/dist/cli/history.d.ts +16 -0
- package/dist/cli/history.d.ts.map +1 -0
- package/dist/cli/history.js +59 -0
- package/dist/cli/history.js.map +1 -0
- package/dist/cli/index.d.ts +17 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +165 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/init.d.ts +23 -0
- package/dist/cli/init.d.ts.map +1 -0
- package/dist/cli/init.js +114 -0
- package/dist/cli/init.js.map +1 -0
- package/dist/cli/mcp-server.d.ts +26 -0
- package/dist/cli/mcp-server.d.ts.map +1 -0
- package/dist/cli/mcp-server.js +112 -0
- package/dist/cli/mcp-server.js.map +1 -0
- package/dist/cli/pay.d.ts +15 -0
- package/dist/cli/pay.d.ts.map +1 -0
- package/dist/cli/pay.js +76 -0
- package/dist/cli/pay.js.map +1 -0
- package/dist/cli/transfer.d.ts +19 -0
- package/dist/cli/transfer.d.ts.map +1 -0
- package/dist/cli/transfer.js +66 -0
- package/dist/cli/transfer.js.map +1 -0
- package/dist/discover/cache.d.ts +24 -0
- package/dist/discover/cache.d.ts.map +1 -0
- package/dist/discover/cache.js +94 -0
- package/dist/discover/cache.js.map +1 -0
- package/dist/discover/index.d.ts +21 -0
- package/dist/discover/index.d.ts.map +1 -0
- package/dist/discover/index.js +88 -0
- package/dist/discover/index.js.map +1 -0
- package/dist/discover/payai.d.ts +18 -0
- package/dist/discover/payai.d.ts.map +1 -0
- package/dist/discover/payai.js +56 -0
- package/dist/discover/payai.js.map +1 -0
- package/dist/do/index.d.ts +17 -0
- package/dist/do/index.d.ts.map +1 -0
- package/dist/do/index.js +32 -0
- package/dist/do/index.js.map +1 -0
- package/dist/guardrail/index.d.ts +47 -0
- package/dist/guardrail/index.d.ts.map +1 -0
- package/dist/guardrail/index.js +99 -0
- package/dist/guardrail/index.js.map +1 -0
- package/dist/history/evm.d.ts +21 -0
- package/dist/history/evm.d.ts.map +1 -0
- package/dist/history/evm.js +118 -0
- package/dist/history/evm.js.map +1 -0
- package/dist/history/index.d.ts +19 -0
- package/dist/history/index.d.ts.map +1 -0
- package/dist/history/index.js +45 -0
- package/dist/history/index.js.map +1 -0
- package/dist/history/solana.d.ts +20 -0
- package/dist/history/solana.d.ts.map +1 -0
- package/dist/history/solana.js +97 -0
- package/dist/history/solana.js.map +1 -0
- package/dist/history/types.d.ts +26 -0
- package/dist/history/types.d.ts.map +1 -0
- package/dist/history/types.js +10 -0
- package/dist/history/types.js.map +1 -0
- package/dist/index.d.ts +94 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +74 -0
- package/dist/index.js.map +1 -0
- package/dist/profile/derive.d.ts +28 -0
- package/dist/profile/derive.d.ts.map +1 -0
- package/dist/profile/derive.js +75 -0
- package/dist/profile/derive.js.map +1 -0
- package/dist/profile/index.d.ts +74 -0
- package/dist/profile/index.d.ts.map +1 -0
- package/dist/profile/index.js +115 -0
- package/dist/profile/index.js.map +1 -0
- package/dist/profile/storage.d.ts +35 -0
- package/dist/profile/storage.d.ts.map +1 -0
- package/dist/profile/storage.js +162 -0
- package/dist/profile/storage.js.map +1 -0
- package/dist/profile/types.d.ts +69 -0
- package/dist/profile/types.d.ts.map +1 -0
- package/dist/profile/types.js +9 -0
- package/dist/profile/types.js.map +1 -0
- package/dist/signers/index.d.ts +5 -0
- package/dist/signers/index.d.ts.map +1 -0
- package/dist/signers/index.js +5 -0
- package/dist/signers/index.js.map +1 -0
- package/dist/signers/phantom.d.ts +14 -0
- package/dist/signers/phantom.d.ts.map +1 -0
- package/dist/signers/phantom.js +12 -0
- package/dist/signers/phantom.js.map +1 -0
- package/dist/signers/privy.d.ts +20 -0
- package/dist/signers/privy.d.ts.map +1 -0
- package/dist/signers/privy.js +15 -0
- package/dist/signers/privy.js.map +1 -0
- package/dist/signers/raw-evm.d.ts +15 -0
- package/dist/signers/raw-evm.d.ts.map +1 -0
- package/dist/signers/raw-evm.js +70 -0
- package/dist/signers/raw-evm.js.map +1 -0
- package/dist/signers/raw-solana.d.ts +15 -0
- package/dist/signers/raw-solana.d.ts.map +1 -0
- package/dist/signers/raw-solana.js +88 -0
- package/dist/signers/raw-solana.js.map +1 -0
- package/dist/tools/index.d.ts +48 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +164 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/transfer/index.d.ts +30 -0
- package/dist/transfer/index.d.ts.map +1 -0
- package/dist/transfer/index.js +86 -0
- package/dist/transfer/index.js.map +1 -0
- package/dist/types.d.ts +203 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +56 -0
- package/dist/types.js.map +1 -0
- package/dist/use/index.d.ts +38 -0
- package/dist/use/index.d.ts.map +1 -0
- package/dist/use/index.js +173 -0
- package/dist/use/index.js.map +1 -0
- package/dist/wallet/index.d.ts +31 -0
- package/dist/wallet/index.d.ts.map +1 -0
- package/dist/wallet/index.js +56 -0
- package/dist/wallet/index.js.map +1 -0
- package/package.json +70 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"payai.js","sourceRoot":"","sources":["../../src/discover/payai.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,cAAc,EAAiB,MAAM,aAAa,CAAC;AAE5D,MAAM,gBAAgB,GAAG,uDAAuD,CAAC;AACjF;mCACmC;AACnC,MAAM,SAAS,GAAG,IAAI,CAAC;AAgBvB,MAAM,CAAC,KAAK,UAAU,mBAAmB,CAAC,OAA2B,EAAE;IACrE,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,IAAI,gBAAgB,CAAC;IACnD,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,IAAI,SAAS,EAAE,SAAS,CAAC,CAAC;IAC3D,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,IAAI,QAAQ,CAAC;IAC3C,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC;IAEtC,MAAM,GAAG,GAAe,EAAE,CAAC;IAC3B,IAAI,MAAM,GAAG,CAAC,CAAC;IACf,IAAI,KAAK,GAAG,QAAQ,CAAC;IAErB,yEAAyE;IACzE,qDAAqD;IACrD,KAAK,IAAI,IAAI,GAAG,CAAC,EAAE,IAAI,GAAG,GAAG,IAAI,MAAM,GAAG,KAAK,IAAI,GAAG,CAAC,MAAM,GAAG,QAAQ,EAAE,IAAI,EAAE,EAAE,CAAC;QACjF,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,CAAC;QAC9B,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,OAAO,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;QAC7C,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC;QAE/C,MAAM,GAAG,GAAG,MAAM,SAAS,CAAC,GAAG,CAAC,QAAQ,EAAE,EAAE;YAC1C,OAAO,EAAE,EAAE,MAAM,EAAE,kBAAkB,EAAE;SACxC,CAAC,CAAC;QACH,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;YACZ,MAAM,IAAI,KAAK,CAAC,2BAA2B,GAAG,CAAC,MAAM,IAAI,GAAG,CAAC,UAAU,EAAE,CAAC,CAAC;QAC7E,CAAC;QACD,MAAM,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAkB,CAAC;QAEjD,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC;QAClC,KAAK,MAAM,GAAG,IAAI,QAAQ,EAAE,CAAC;YAC3B,MAAM,MAAM,GAAG,cAAc,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;YAC7C,IAAI,MAAM,CAAC,OAAO;gBAAE,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;YAC1C,IAAI,GAAG,CAAC,MAAM,IAAI,QAAQ;gBAAE,OAAO,GAAG,CAAC;QACzC,CAAC;QAED,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;YACpB,KAAK,GAAG,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC;YAC9B,MAAM,GAAG,IAAI,CAAC,UAAU,CAAC,MAAM,GAAG,QAAQ,CAAC,MAAM,CAAC;QACpD,CAAC;aAAM,CAAC;YACN,4CAA4C;YAC5C,MAAM;QACR,CAAC;QACD,+DAA+D;QAC/D,IAAI,QAAQ,CAAC,MAAM,GAAG,KAAK;YAAE,MAAM;IACrC,CAAC;IAED,OAAO,GAAG,CAAC;AACb,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Do — the thesis in one method. Discover by intent, pick the top result, use it.
|
|
3
|
+
*
|
|
4
|
+
* This is the API normies (and most agents) actually want. Power users compose
|
|
5
|
+
* {@link discover} + {@link use} manually when they need control over picking.
|
|
6
|
+
*/
|
|
7
|
+
import type { UseResult } from "../types.js";
|
|
8
|
+
import type { Wallet } from "../wallet/index.js";
|
|
9
|
+
import type { Guardrail } from "../guardrail/index.js";
|
|
10
|
+
export interface DoArgs {
|
|
11
|
+
query: string;
|
|
12
|
+
wallet: Wallet;
|
|
13
|
+
guardrail: Guardrail;
|
|
14
|
+
body?: unknown;
|
|
15
|
+
}
|
|
16
|
+
export declare function doIt(args: DoArgs): Promise<UseResult>;
|
|
17
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/do/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAG7C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAEvD,MAAM,WAAW,MAAM;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,SAAS,CAAC;IACrB,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED,wBAAsB,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC,CA2B3D"}
|
package/dist/do/index.js
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Do — the thesis in one method. Discover by intent, pick the top result, use it.
|
|
3
|
+
*
|
|
4
|
+
* This is the API normies (and most agents) actually want. Power users compose
|
|
5
|
+
* {@link discover} + {@link use} manually when they need control over picking.
|
|
6
|
+
*/
|
|
7
|
+
import { discover } from "../discover/index.js";
|
|
8
|
+
import { use } from "../use/index.js";
|
|
9
|
+
export async function doIt(args) {
|
|
10
|
+
const candidates = await discover({
|
|
11
|
+
query: args.query,
|
|
12
|
+
networks: args.wallet.networks,
|
|
13
|
+
limit: 5,
|
|
14
|
+
});
|
|
15
|
+
if (candidates.length === 0) {
|
|
16
|
+
throw new Error(`xpay.do: no services found for "${args.query}"`);
|
|
17
|
+
}
|
|
18
|
+
// v0 picks the top-ranked match the wallet can actually pay. v0.2 should
|
|
19
|
+
// rerank by reliability + price; v1 should learn from user history.
|
|
20
|
+
for (const candidate of candidates) {
|
|
21
|
+
if (args.wallet.pickRequirement(candidate.accepts)) {
|
|
22
|
+
return use({
|
|
23
|
+
resource: candidate,
|
|
24
|
+
wallet: args.wallet,
|
|
25
|
+
guardrail: args.guardrail,
|
|
26
|
+
body: args.body,
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
throw new Error(`xpay.do: found ${candidates.length} services for "${args.query}" but none accept payment on configured networks (${args.wallet.networks.join(", ")})`);
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/do/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAChD,OAAO,EAAE,GAAG,EAAE,MAAM,iBAAiB,CAAC;AAWtC,MAAM,CAAC,KAAK,UAAU,IAAI,CAAC,IAAY;IACrC,MAAM,UAAU,GAAG,MAAM,QAAQ,CAAC;QAChC,KAAK,EAAE,IAAI,CAAC,KAAK;QACjB,QAAQ,EAAE,IAAI,CAAC,MAAM,CAAC,QAAQ;QAC9B,KAAK,EAAE,CAAC;KACT,CAAC,CAAC;IAEH,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC5B,MAAM,IAAI,KAAK,CAAC,mCAAmC,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC;IACpE,CAAC;IAED,yEAAyE;IACzE,oEAAoE;IACpE,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;QACnC,IAAI,IAAI,CAAC,MAAM,CAAC,eAAe,CAAC,SAAS,CAAC,OAAO,CAAC,EAAE,CAAC;YACnD,OAAO,GAAG,CAAC;gBACT,QAAQ,EAAE,SAAS;gBACnB,MAAM,EAAE,IAAI,CAAC,MAAM;gBACnB,SAAS,EAAE,IAAI,CAAC,SAAS;gBACzB,IAAI,EAAE,IAAI,CAAC,IAAI;aAChB,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,MAAM,IAAI,KAAK,CACb,kBAAkB,UAAU,CAAC,MAAM,kBAAkB,IAAI,CAAC,KAAK,qDAAqD,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CACvJ,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Spending guardrail — enforced *before* signing so a hallucinating agent
|
|
3
|
+
* can't sneak past it. This is the security primitive that makes xPay
|
|
4
|
+
* "agentic" rather than just "an SDK with a wallet".
|
|
5
|
+
*
|
|
6
|
+
* v0 implements: per-tx cap, per-day cap, allowed host list. v0.2 adds
|
|
7
|
+
* per-counterparty caps and a biometric-required threshold.
|
|
8
|
+
*/
|
|
9
|
+
import type { PaymentRequirement, Resource } from "../types.js";
|
|
10
|
+
export interface GuardrailConfig {
|
|
11
|
+
/** Max USD per single call. */
|
|
12
|
+
maxPerTx?: number;
|
|
13
|
+
/** Max USD across a rolling 24h window. */
|
|
14
|
+
maxPerDay?: number;
|
|
15
|
+
/** Glob-style host whitelist. `["*"]` allows everything. */
|
|
16
|
+
allowedHosts?: string[];
|
|
17
|
+
/** Calls above this USD threshold require an external approval hook. */
|
|
18
|
+
requireApprovalAbove?: number;
|
|
19
|
+
/**
|
|
20
|
+
* Optional callback invoked when {@link GuardrailConfig.requireApprovalAbove}
|
|
21
|
+
* is hit. Implementor decides how to surface the prompt (biometric, push,
|
|
22
|
+
* webhook). Resolve `true` to allow, `false` to deny.
|
|
23
|
+
*/
|
|
24
|
+
onApprovalRequired?: (ctx: {
|
|
25
|
+
resource: Resource;
|
|
26
|
+
usd: number;
|
|
27
|
+
}) => Promise<boolean>;
|
|
28
|
+
}
|
|
29
|
+
export declare class Guardrail {
|
|
30
|
+
private readonly config;
|
|
31
|
+
private readonly history;
|
|
32
|
+
constructor(config?: GuardrailConfig);
|
|
33
|
+
/**
|
|
34
|
+
* Check a pending call. Throws if blocked.
|
|
35
|
+
* Called by {@link use} before any on-chain action.
|
|
36
|
+
*/
|
|
37
|
+
check(args: {
|
|
38
|
+
resource: Resource;
|
|
39
|
+
requirement: PaymentRequirement;
|
|
40
|
+
}): Promise<void>;
|
|
41
|
+
/** Sum of recent spend, in USD, within the last 24h. */
|
|
42
|
+
recentSpend(): number;
|
|
43
|
+
}
|
|
44
|
+
export declare class GuardrailError extends Error {
|
|
45
|
+
constructor(message: string);
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/guardrail/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,kBAAkB,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAEhE,MAAM,WAAW,eAAe;IAC9B,+BAA+B;IAC/B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,2CAA2C;IAC3C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,4DAA4D;IAC5D,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,wEAAwE;IACxE,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B;;;;OAIG;IACH,kBAAkB,CAAC,EAAE,CAAC,GAAG,EAAE;QAAE,QAAQ,EAAE,QAAQ,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;CACrF;AAOD,qBAAa,SAAS;IACpB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAkB;IACzC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAoB;gBAEhC,MAAM,GAAE,eAAoB;IAIxC;;;OAGG;IACG,KAAK,CAAC,IAAI,EAAE;QAAE,QAAQ,EAAE,QAAQ,CAAC;QAAC,WAAW,EAAE,kBAAkB,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAyDzF,wDAAwD;IACxD,WAAW,IAAI,MAAM;CAItB;AAED,qBAAa,cAAe,SAAQ,KAAK;gBAC3B,OAAO,EAAE,MAAM;CAI5B"}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Spending guardrail — enforced *before* signing so a hallucinating agent
|
|
3
|
+
* can't sneak past it. This is the security primitive that makes xPay
|
|
4
|
+
* "agentic" rather than just "an SDK with a wallet".
|
|
5
|
+
*
|
|
6
|
+
* v0 implements: per-tx cap, per-day cap, allowed host list. v0.2 adds
|
|
7
|
+
* per-counterparty caps and a biometric-required threshold.
|
|
8
|
+
*/
|
|
9
|
+
export class Guardrail {
|
|
10
|
+
config;
|
|
11
|
+
history = [];
|
|
12
|
+
constructor(config = {}) {
|
|
13
|
+
this.config = config;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Check a pending call. Throws if blocked.
|
|
17
|
+
* Called by {@link use} before any on-chain action.
|
|
18
|
+
*/
|
|
19
|
+
async check(args) {
|
|
20
|
+
const usd = estimateUsd(args.requirement);
|
|
21
|
+
// Host whitelist. Skipped for direct transfers (they target addresses, not
|
|
22
|
+
// hosts) — amount caps still apply, so a leaked CLI can't drain the wallet.
|
|
23
|
+
if (args.resource.type !== "transfer" &&
|
|
24
|
+
this.config.allowedHosts &&
|
|
25
|
+
this.config.allowedHosts.length > 0) {
|
|
26
|
+
const allowed = this.config.allowedHosts;
|
|
27
|
+
if (!allowed.includes("*")) {
|
|
28
|
+
const host = safeHost(args.resource.resource);
|
|
29
|
+
const ok = allowed.some((pattern) => hostMatches(host, pattern));
|
|
30
|
+
if (!ok) {
|
|
31
|
+
throw new GuardrailError(`Host "${host}" is not in the allowed list`);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
// Per-tx cap.
|
|
36
|
+
if (this.config.maxPerTx !== undefined && usd > this.config.maxPerTx) {
|
|
37
|
+
throw new GuardrailError(`Single call would spend $${usd.toFixed(4)}, exceeds maxPerTx $${this.config.maxPerTx}`);
|
|
38
|
+
}
|
|
39
|
+
// Per-day cap.
|
|
40
|
+
if (this.config.maxPerDay !== undefined) {
|
|
41
|
+
const dayAgo = Date.now() - 24 * 60 * 60 * 1000;
|
|
42
|
+
const spent = this.history.filter((h) => h.at >= dayAgo).reduce((s, h) => s + h.usd, 0);
|
|
43
|
+
if (spent + usd > this.config.maxPerDay) {
|
|
44
|
+
throw new GuardrailError(`Daily spend $${(spent + usd).toFixed(4)} would exceed maxPerDay $${this.config.maxPerDay}`);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
// Approval gate.
|
|
48
|
+
if (this.config.requireApprovalAbove !== undefined &&
|
|
49
|
+
usd >= this.config.requireApprovalAbove) {
|
|
50
|
+
if (!this.config.onApprovalRequired) {
|
|
51
|
+
throw new GuardrailError(`Call requires approval ($${usd.toFixed(4)} >= $${this.config.requireApprovalAbove}) but no onApprovalRequired hook is configured`);
|
|
52
|
+
}
|
|
53
|
+
const approved = await this.config.onApprovalRequired({ resource: args.resource, usd });
|
|
54
|
+
if (!approved) {
|
|
55
|
+
throw new GuardrailError(`Call denied by approval hook`);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
this.history.push({ at: Date.now(), usd });
|
|
59
|
+
}
|
|
60
|
+
/** Sum of recent spend, in USD, within the last 24h. */
|
|
61
|
+
recentSpend() {
|
|
62
|
+
const dayAgo = Date.now() - 24 * 60 * 60 * 1000;
|
|
63
|
+
return this.history.filter((h) => h.at >= dayAgo).reduce((s, h) => s + h.usd, 0);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
export class GuardrailError extends Error {
|
|
67
|
+
constructor(message) {
|
|
68
|
+
super(`xpay guardrail: ${message}`);
|
|
69
|
+
this.name = "GuardrailError";
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Best-effort USD estimate. Assumes USDC (6 decimals) on Solana, USDC (6) on
|
|
74
|
+
* Base/EVM. Future versions should consult a price oracle for non-USDC assets.
|
|
75
|
+
*/
|
|
76
|
+
function estimateUsd(req) {
|
|
77
|
+
if (!req.amount)
|
|
78
|
+
return 0;
|
|
79
|
+
// USDC has 6 decimals on every chain we currently support.
|
|
80
|
+
return Number(req.amount) / 1_000_000;
|
|
81
|
+
}
|
|
82
|
+
function safeHost(url) {
|
|
83
|
+
try {
|
|
84
|
+
return new URL(url).host;
|
|
85
|
+
}
|
|
86
|
+
catch {
|
|
87
|
+
return "";
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
function hostMatches(host, pattern) {
|
|
91
|
+
if (pattern === host)
|
|
92
|
+
return true;
|
|
93
|
+
if (pattern.startsWith("*.")) {
|
|
94
|
+
const suffix = pattern.slice(1); // ".example.com"
|
|
95
|
+
return host.endsWith(suffix);
|
|
96
|
+
}
|
|
97
|
+
return false;
|
|
98
|
+
}
|
|
99
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/guardrail/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* EVM USDC history via ERC-20 Transfer event logs.
|
|
3
|
+
*
|
|
4
|
+
* Strategy: scan a recent block window for `Transfer` events on the USDC
|
|
5
|
+
* contract where `from` or `to` is the wallet. Public RPCs typically allow a
|
|
6
|
+
* window of ~5k–10k blocks per `eth_getLogs` call; we paginate if needed.
|
|
7
|
+
*
|
|
8
|
+
* Good enough for the v1 history view. For production / large windows, swap
|
|
9
|
+
* the RPC for an indexer (Basescan/Alchemy/Covalent) by passing `rpcUrl`.
|
|
10
|
+
*/
|
|
11
|
+
import type { HistoryEntry } from "./types.js";
|
|
12
|
+
import type { Network } from "../types.js";
|
|
13
|
+
export interface EvmHistoryOptions {
|
|
14
|
+
address: string;
|
|
15
|
+
network: Network;
|
|
16
|
+
limit?: number;
|
|
17
|
+
blockWindow?: number;
|
|
18
|
+
rpcUrl?: string;
|
|
19
|
+
}
|
|
20
|
+
export declare function fetchEvmHistory(opts: EvmHistoryOptions): Promise<HistoryEntry[]>;
|
|
21
|
+
//# sourceMappingURL=evm.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"evm.d.ts","sourceRoot":"","sources":["../../src/history/evm.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC/C,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAsB3C,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAID,wBAAsB,eAAe,CAAC,IAAI,EAAE,iBAAiB,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,CAyFtF"}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* EVM USDC history via ERC-20 Transfer event logs.
|
|
3
|
+
*
|
|
4
|
+
* Strategy: scan a recent block window for `Transfer` events on the USDC
|
|
5
|
+
* contract where `from` or `to` is the wallet. Public RPCs typically allow a
|
|
6
|
+
* window of ~5k–10k blocks per `eth_getLogs` call; we paginate if needed.
|
|
7
|
+
*
|
|
8
|
+
* Good enough for the v1 history view. For production / large windows, swap
|
|
9
|
+
* the RPC for an indexer (Basescan/Alchemy/Covalent) by passing `rpcUrl`.
|
|
10
|
+
*/
|
|
11
|
+
import { Contract, JsonRpcProvider, ZeroAddress, hexlify, toBeHex, zeroPadValue } from "ethers";
|
|
12
|
+
const USDC_CONTRACTS = {
|
|
13
|
+
base: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
|
|
14
|
+
ethereum: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
|
|
15
|
+
arbitrum: "0xaf88d065e77c8cC2239327C5EDb3A432268e5831",
|
|
16
|
+
optimism: "0x0b2C639c533813f4Aa9D7837CAf62653d097Ff85",
|
|
17
|
+
};
|
|
18
|
+
const DEFAULT_RPCS = {
|
|
19
|
+
base: "https://mainnet.base.org",
|
|
20
|
+
ethereum: "https://eth.llamarpc.com",
|
|
21
|
+
arbitrum: "https://arb1.arbitrum.io/rpc",
|
|
22
|
+
optimism: "https://mainnet.optimism.io",
|
|
23
|
+
};
|
|
24
|
+
/** Window (in blocks) scanned for transfer history. ~2 days at 2s block times. */
|
|
25
|
+
const DEFAULT_BLOCK_WINDOW = 100_000;
|
|
26
|
+
/** Public RPCs commonly cap getLogs at 10k blocks. Stay under it. */
|
|
27
|
+
const MAX_LOG_RANGE = 9_500;
|
|
28
|
+
const TRANSFER_TOPIC = "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef";
|
|
29
|
+
const TRANSFER_IFACE = ["event Transfer(address indexed from, address indexed to, uint256 value)"];
|
|
30
|
+
export async function fetchEvmHistory(opts) {
|
|
31
|
+
const usdc = USDC_CONTRACTS[opts.network];
|
|
32
|
+
const rpc = opts.rpcUrl ?? DEFAULT_RPCS[opts.network];
|
|
33
|
+
if (!usdc || !rpc) {
|
|
34
|
+
throw new Error(`fetchEvmHistory: no USDC contract / RPC for network "${opts.network}"`);
|
|
35
|
+
}
|
|
36
|
+
const provider = new JsonRpcProvider(rpc);
|
|
37
|
+
const latest = await provider.getBlockNumber();
|
|
38
|
+
const from = Math.max(0, latest - (opts.blockWindow ?? DEFAULT_BLOCK_WINDOW));
|
|
39
|
+
const padded = zeroPadValue(opts.address, 32);
|
|
40
|
+
/** Chunked getLogs — public RPCs cap range, so we walk backwards in MAX_LOG_RANGE
|
|
41
|
+
* windows and stop early once we have enough hits for the requested limit. */
|
|
42
|
+
async function chunkedLogs(topics) {
|
|
43
|
+
const all = [];
|
|
44
|
+
let end = latest;
|
|
45
|
+
while (end > from) {
|
|
46
|
+
const start = Math.max(from, end - MAX_LOG_RANGE);
|
|
47
|
+
try {
|
|
48
|
+
const batch = await provider.getLogs({
|
|
49
|
+
address: usdc,
|
|
50
|
+
topics,
|
|
51
|
+
fromBlock: start,
|
|
52
|
+
toBlock: end,
|
|
53
|
+
});
|
|
54
|
+
all.push(...batch);
|
|
55
|
+
}
|
|
56
|
+
catch (err) {
|
|
57
|
+
// Tolerate per-chunk failures (rate limits) — keep what we have.
|
|
58
|
+
// eslint-disable-next-line no-console
|
|
59
|
+
console.warn(`[xpay] evm history chunk ${start}-${end} failed:`, err.message);
|
|
60
|
+
}
|
|
61
|
+
if (opts.limit && all.length >= opts.limit)
|
|
62
|
+
break;
|
|
63
|
+
end = start - 1;
|
|
64
|
+
}
|
|
65
|
+
return all;
|
|
66
|
+
}
|
|
67
|
+
const [outgoing, incoming] = await Promise.all([
|
|
68
|
+
chunkedLogs([TRANSFER_TOPIC, padded, null]),
|
|
69
|
+
chunkedLogs([TRANSFER_TOPIC, null, padded]),
|
|
70
|
+
]);
|
|
71
|
+
const erc20 = new Contract(usdc, TRANSFER_IFACE, provider);
|
|
72
|
+
const logs = [...outgoing, ...incoming];
|
|
73
|
+
const seen = new Set();
|
|
74
|
+
// Pull block timestamps for each unique block in the result.
|
|
75
|
+
const blockNumbers = [...new Set(logs.map((l) => l.blockNumber))];
|
|
76
|
+
const blocks = new Map();
|
|
77
|
+
await Promise.all(blockNumbers.map(async (bn) => {
|
|
78
|
+
try {
|
|
79
|
+
const b = await provider.getBlock(bn);
|
|
80
|
+
if (b?.timestamp)
|
|
81
|
+
blocks.set(bn, b.timestamp * 1000);
|
|
82
|
+
}
|
|
83
|
+
catch {
|
|
84
|
+
/* skip */
|
|
85
|
+
}
|
|
86
|
+
}));
|
|
87
|
+
const out = [];
|
|
88
|
+
for (const log of logs) {
|
|
89
|
+
const key = `${log.transactionHash}:${log.index}`;
|
|
90
|
+
if (seen.has(key))
|
|
91
|
+
continue;
|
|
92
|
+
seen.add(key);
|
|
93
|
+
const parsed = erc20.interface.parseLog({ topics: [...log.topics], data: log.data });
|
|
94
|
+
if (!parsed)
|
|
95
|
+
continue;
|
|
96
|
+
const fromAddr = parsed.args[0].toLowerCase();
|
|
97
|
+
const toAddr = parsed.args[1].toLowerCase();
|
|
98
|
+
const value = parsed.args[2];
|
|
99
|
+
const isSend = fromAddr === opts.address.toLowerCase();
|
|
100
|
+
out.push({
|
|
101
|
+
timestamp: blocks.get(log.blockNumber) ?? null,
|
|
102
|
+
network: opts.network,
|
|
103
|
+
signature: log.transactionHash,
|
|
104
|
+
direction: isSend ? "send" : "receive",
|
|
105
|
+
counterparty: isSend ? toAddr : fromAddr,
|
|
106
|
+
amountUsdc: Number(value) / 1_000_000,
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
out.sort((a, b) => (b.timestamp ?? 0) - (a.timestamp ?? 0));
|
|
110
|
+
if (opts.limit)
|
|
111
|
+
return out.slice(0, opts.limit);
|
|
112
|
+
return out;
|
|
113
|
+
}
|
|
114
|
+
// hint to tree-shakers: keep this import live (used in JSDoc only otherwise)
|
|
115
|
+
void hexlify;
|
|
116
|
+
void toBeHex;
|
|
117
|
+
void ZeroAddress;
|
|
118
|
+
//# sourceMappingURL=evm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"evm.js","sourceRoot":"","sources":["../../src/history/evm.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unified history — merges Solana + EVM USDC activity into a single sorted feed.
|
|
3
|
+
*/
|
|
4
|
+
import type { Network } from "../types.js";
|
|
5
|
+
import type { Wallet } from "../wallet/index.js";
|
|
6
|
+
import type { HistoryEntry } from "./types.js";
|
|
7
|
+
export * from "./types.js";
|
|
8
|
+
export interface HistoryOptions {
|
|
9
|
+
/** Restrict to specific networks. Defaults to all the wallet supports. */
|
|
10
|
+
networks?: Network[];
|
|
11
|
+
/** Max entries to return (after merge + sort). */
|
|
12
|
+
limit?: number;
|
|
13
|
+
/** Per-network block window for EVM scans. */
|
|
14
|
+
evmBlockWindow?: number;
|
|
15
|
+
/** Per-network RPC overrides. */
|
|
16
|
+
rpcs?: Partial<Record<Network, string>>;
|
|
17
|
+
}
|
|
18
|
+
export declare function getHistory(wallet: Wallet, opts?: HistoryOptions): Promise<HistoryEntry[]>;
|
|
19
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/history/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAGjD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE/C,cAAc,YAAY,CAAC;AAE3B,MAAM,WAAW,cAAc;IAC7B,0EAA0E;IAC1E,QAAQ,CAAC,EAAE,OAAO,EAAE,CAAC;IACrB,kDAAkD;IAClD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,8CAA8C;IAC9C,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,iCAAiC;IACjC,IAAI,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC;CACzC;AAID,wBAAsB,UAAU,CAC9B,MAAM,EAAE,MAAM,EACd,IAAI,GAAE,cAAmB,GACxB,OAAO,CAAC,YAAY,EAAE,CAAC,CAqCzB"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unified history — merges Solana + EVM USDC activity into a single sorted feed.
|
|
3
|
+
*/
|
|
4
|
+
import { fetchSolanaHistory } from "./solana.js";
|
|
5
|
+
import { fetchEvmHistory } from "./evm.js";
|
|
6
|
+
export * from "./types.js";
|
|
7
|
+
const EVM_NETWORKS = ["base", "ethereum", "arbitrum", "optimism"];
|
|
8
|
+
export async function getHistory(wallet, opts = {}) {
|
|
9
|
+
const networks = opts.networks ?? wallet.networks;
|
|
10
|
+
const perNetwork = Math.max(opts.limit ?? 25, 25);
|
|
11
|
+
const results = await Promise.all(networks.map(async (net) => {
|
|
12
|
+
if (!wallet.has(net))
|
|
13
|
+
return [];
|
|
14
|
+
const address = wallet.address(net);
|
|
15
|
+
try {
|
|
16
|
+
if (net === "solana") {
|
|
17
|
+
return await fetchSolanaHistory({
|
|
18
|
+
address,
|
|
19
|
+
limit: perNetwork,
|
|
20
|
+
rpcUrl: opts.rpcs?.solana,
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
if (EVM_NETWORKS.includes(net)) {
|
|
24
|
+
return await fetchEvmHistory({
|
|
25
|
+
address,
|
|
26
|
+
network: net,
|
|
27
|
+
limit: perNetwork,
|
|
28
|
+
blockWindow: opts.evmBlockWindow,
|
|
29
|
+
rpcUrl: opts.rpcs?.[net],
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
catch (err) {
|
|
34
|
+
// One bad network shouldn't kill history. Log and continue.
|
|
35
|
+
// eslint-disable-next-line no-console
|
|
36
|
+
console.warn(`[xpay] history fetch failed for ${net}:`, err.message);
|
|
37
|
+
}
|
|
38
|
+
return [];
|
|
39
|
+
}));
|
|
40
|
+
const merged = results.flat().sort((a, b) => (b.timestamp ?? 0) - (a.timestamp ?? 0));
|
|
41
|
+
if (opts.limit)
|
|
42
|
+
return merged.slice(0, opts.limit);
|
|
43
|
+
return merged;
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/history/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAG3C,cAAc,YAAY,CAAC;AAa3B,MAAM,YAAY,GAAc,CAAC,MAAM,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,CAAC,CAAC;AAE7E,MAAM,CAAC,KAAK,UAAU,UAAU,CAC9B,MAAc,EACd,OAAuB,EAAE;IAEzB,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC;IAClD,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC;IAElD,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,GAAG,CAC/B,QAAQ,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE;QACzB,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC;YAAE,OAAO,EAAE,CAAC;QAChC,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QACpC,IAAI,CAAC;YACH,IAAI,GAAG,KAAK,QAAQ,EAAE,CAAC;gBACrB,OAAO,MAAM,kBAAkB,CAAC;oBAC9B,OAAO;oBACP,KAAK,EAAE,UAAU;oBACjB,MAAM,EAAE,IAAI,CAAC,IAAI,EAAE,MAAM;iBAC1B,CAAC,CAAC;YACL,CAAC;YACD,IAAI,YAAY,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;gBAC/B,OAAO,MAAM,eAAe,CAAC;oBAC3B,OAAO;oBACP,OAAO,EAAE,GAAG;oBACZ,KAAK,EAAE,UAAU;oBACjB,WAAW,EAAE,IAAI,CAAC,cAAc;oBAChC,MAAM,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC;iBACzB,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,4DAA4D;YAC5D,sCAAsC;YACtC,OAAO,CAAC,IAAI,CAAC,mCAAmC,GAAG,GAAG,EAAG,GAAa,CAAC,OAAO,CAAC,CAAC;QAClF,CAAC;QACD,OAAO,EAAE,CAAC;IACZ,CAAC,CAAC,CACH,CAAC;IAEF,MAAM,MAAM,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,IAAI,CAAC,CAAC,CAAC,CAAC;IACtF,IAAI,IAAI,CAAC,KAAK;QAAE,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;IACnD,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Solana USDC history via standard JSON-RPC.
|
|
3
|
+
*
|
|
4
|
+
* Strategy:
|
|
5
|
+
* 1. `getSignaturesForAddress` on the wallet's USDC associated token account
|
|
6
|
+
* (ATA), not the wallet itself — token-program txs are addressed to the
|
|
7
|
+
* ATA, not the owner.
|
|
8
|
+
* 2. `getParsedTransactions` (batched) to extract amounts + counterparties.
|
|
9
|
+
*
|
|
10
|
+
* Works on free public RPC for small `limit` values. For prod scale, drop in
|
|
11
|
+
* a Helius / Triton RPC via the `rpcUrl` arg.
|
|
12
|
+
*/
|
|
13
|
+
import type { HistoryEntry } from "./types.js";
|
|
14
|
+
export interface SolanaHistoryOptions {
|
|
15
|
+
address: string;
|
|
16
|
+
limit?: number;
|
|
17
|
+
rpcUrl?: string;
|
|
18
|
+
}
|
|
19
|
+
export declare function fetchSolanaHistory(opts: SolanaHistoryOptions): Promise<HistoryEntry[]>;
|
|
20
|
+
//# sourceMappingURL=solana.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"solana.d.ts","sourceRoot":"","sources":["../../src/history/solana.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AASH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAK/C,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,wBAAsB,kBAAkB,CAAC,IAAI,EAAE,oBAAoB,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,CAgC5F"}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Solana USDC history via standard JSON-RPC.
|
|
3
|
+
*
|
|
4
|
+
* Strategy:
|
|
5
|
+
* 1. `getSignaturesForAddress` on the wallet's USDC associated token account
|
|
6
|
+
* (ATA), not the wallet itself — token-program txs are addressed to the
|
|
7
|
+
* ATA, not the owner.
|
|
8
|
+
* 2. `getParsedTransactions` (batched) to extract amounts + counterparties.
|
|
9
|
+
*
|
|
10
|
+
* Works on free public RPC for small `limit` values. For prod scale, drop in
|
|
11
|
+
* a Helius / Triton RPC via the `rpcUrl` arg.
|
|
12
|
+
*/
|
|
13
|
+
import { Connection, PublicKey, } from "@solana/web3.js";
|
|
14
|
+
import { getAssociatedTokenAddress } from "@solana/spl-token";
|
|
15
|
+
const USDC_MINT = "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v";
|
|
16
|
+
const DEFAULT_RPC = "https://api.mainnet-beta.solana.com";
|
|
17
|
+
export async function fetchSolanaHistory(opts) {
|
|
18
|
+
const limit = Math.min(opts.limit ?? 25, 1000);
|
|
19
|
+
const connection = new Connection(opts.rpcUrl ?? DEFAULT_RPC, "confirmed");
|
|
20
|
+
const owner = new PublicKey(opts.address);
|
|
21
|
+
const ata = await getAssociatedTokenAddress(new PublicKey(USDC_MINT), owner);
|
|
22
|
+
const sigs = await connection.getSignaturesForAddress(ata, { limit });
|
|
23
|
+
if (sigs.length === 0)
|
|
24
|
+
return [];
|
|
25
|
+
// Batch-fetch parsed txs (RPC supports up to ~100 per batch via single calls,
|
|
26
|
+
// but the helper here just fires Promise.all on individual calls — public RPC
|
|
27
|
+
// tolerates this at small limits).
|
|
28
|
+
const parsed = await Promise.all(sigs.map((s) => connection
|
|
29
|
+
.getParsedTransaction(s.signature, { maxSupportedTransactionVersion: 0 })
|
|
30
|
+
.catch(() => null)));
|
|
31
|
+
const out = [];
|
|
32
|
+
for (let i = 0; i < sigs.length; i++) {
|
|
33
|
+
const sig = sigs[i];
|
|
34
|
+
const tx = parsed[i];
|
|
35
|
+
const entry = extractTransferEntry(tx, sig.signature, opts.address);
|
|
36
|
+
if (!entry)
|
|
37
|
+
continue;
|
|
38
|
+
entry.timestamp = sig.blockTime ? sig.blockTime * 1000 : null;
|
|
39
|
+
entry.status = sig.err ? "failed" : sig.confirmationStatus ?? "confirmed";
|
|
40
|
+
out.push(entry);
|
|
41
|
+
}
|
|
42
|
+
return out;
|
|
43
|
+
}
|
|
44
|
+
function extractTransferEntry(tx, signature, ownerAddress) {
|
|
45
|
+
if (!tx?.meta || tx.meta.err) {
|
|
46
|
+
// Still emit failed tx so users can see them.
|
|
47
|
+
return tx
|
|
48
|
+
? {
|
|
49
|
+
timestamp: null,
|
|
50
|
+
network: "solana",
|
|
51
|
+
signature,
|
|
52
|
+
direction: "send",
|
|
53
|
+
counterparty: "",
|
|
54
|
+
amountUsdc: 0,
|
|
55
|
+
}
|
|
56
|
+
: null;
|
|
57
|
+
}
|
|
58
|
+
for (const ix of tx.transaction.message.instructions) {
|
|
59
|
+
const parsed = ix;
|
|
60
|
+
if (parsed.program !== "spl-token")
|
|
61
|
+
continue;
|
|
62
|
+
const info = parsed.parsed?.info;
|
|
63
|
+
if (!info)
|
|
64
|
+
continue;
|
|
65
|
+
const type = parsed.parsed?.type;
|
|
66
|
+
if (type !== "transfer" && type !== "transferChecked")
|
|
67
|
+
continue;
|
|
68
|
+
// For SPL transfers we need to map source/dest token accounts back to owners.
|
|
69
|
+
// The pre/post token balances expose this cleanly.
|
|
70
|
+
const owners = (tx.meta.postTokenBalances ?? []).reduce((acc, b) => {
|
|
71
|
+
if (b.owner)
|
|
72
|
+
acc[b.accountIndex] = b.owner;
|
|
73
|
+
return acc;
|
|
74
|
+
}, {});
|
|
75
|
+
const sourceIdx = tx.transaction.message.accountKeys.findIndex((k) => k.pubkey.toBase58() === info.source);
|
|
76
|
+
const destIdx = tx.transaction.message.accountKeys.findIndex((k) => k.pubkey.toBase58() === info.destination);
|
|
77
|
+
const sourceOwner = sourceIdx >= 0 ? owners[sourceIdx] ?? info.source : info.source;
|
|
78
|
+
const destOwner = destIdx >= 0 ? owners[destIdx] ?? info.destination : info.destination;
|
|
79
|
+
const isSend = info.authority === ownerAddress || sourceOwner === ownerAddress;
|
|
80
|
+
const isReceive = destOwner === ownerAddress;
|
|
81
|
+
if (!isSend && !isReceive)
|
|
82
|
+
continue;
|
|
83
|
+
const rawAmount = info.tokenAmount?.amount ?? info.amount ?? "0";
|
|
84
|
+
const decimals = info.tokenAmount?.decimals ?? 6;
|
|
85
|
+
const amount = Number(rawAmount) / 10 ** decimals;
|
|
86
|
+
return {
|
|
87
|
+
timestamp: null, // filled in by caller
|
|
88
|
+
network: "solana",
|
|
89
|
+
signature,
|
|
90
|
+
direction: isSend ? "send" : "receive",
|
|
91
|
+
counterparty: isSend ? destOwner ?? "" : sourceOwner ?? "",
|
|
92
|
+
amountUsdc: amount,
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
return null;
|
|
96
|
+
}
|
|
97
|
+
//# sourceMappingURL=solana.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"solana.js","sourceRoot":"","sources":["../../src/history/solana.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EACL,UAAU,EACV,SAAS,GAGV,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,yBAAyB,EAAE,MAAM,mBAAmB,CAAC;AAG9D,MAAM,SAAS,GAAG,8CAA8C,CAAC;AACjE,MAAM,WAAW,GAAG,qCAAqC,CAAC;AAQ1D,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,IAA0B;IACjE,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,IAAI,EAAE,EAAE,IAAI,CAAC,CAAC;IAC/C,MAAM,UAAU,GAAG,IAAI,UAAU,CAAC,IAAI,CAAC,MAAM,IAAI,WAAW,EAAE,WAAW,CAAC,CAAC;IAE3E,MAAM,KAAK,GAAG,IAAI,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAC1C,MAAM,GAAG,GAAG,MAAM,yBAAyB,CAAC,IAAI,SAAS,CAAC,SAAS,CAAC,EAAE,KAAK,CAAC,CAAC;IAE7E,MAAM,IAAI,GAAG,MAAM,UAAU,CAAC,uBAAuB,CAAC,GAAG,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC;IACtE,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAEjC,8EAA8E;IAC9E,8EAA8E;IAC9E,mCAAmC;IACnC,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,GAAG,CAC9B,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CACb,UAAU;SACP,oBAAoB,CAAC,CAAC,CAAC,SAAS,EAAE,EAAE,8BAA8B,EAAE,CAAC,EAAE,CAAC;SACxE,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CACrB,CACF,CAAC;IAEF,MAAM,GAAG,GAAmB,EAAE,CAAC;IAC/B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACrC,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,CAAE,CAAC;QACrB,MAAM,EAAE,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;QACrB,MAAM,KAAK,GAAG,oBAAoB,CAAC,EAAE,EAAE,GAAG,CAAC,SAAS,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;QACpE,IAAI,CAAC,KAAK;YAAE,SAAS;QACrB,KAAK,CAAC,SAAS,GAAG,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC,SAAS,GAAG,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;QAC9D,KAAK,CAAC,MAAM,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,kBAAkB,IAAI,WAAW,CAAC;QAC1E,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAClB,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,SAAS,oBAAoB,CAC3B,EAAoC,EACpC,SAAiB,EACjB,YAAoB;IAEpB,IAAI,CAAC,EAAE,EAAE,IAAI,IAAI,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC;QAC7B,8CAA8C;QAC9C,OAAO,EAAE;YACP,CAAC,CAAC;gBACE,SAAS,EAAE,IAAI;gBACf,OAAO,EAAE,QAAQ;gBACjB,SAAS;gBACT,SAAS,EAAE,MAAM;gBACjB,YAAY,EAAE,EAAE;gBAChB,UAAU,EAAE,CAAC;aACd;YACH,CAAC,CAAC,IAAI,CAAC;IACX,CAAC;IAED,KAAK,MAAM,EAAE,IAAI,EAAE,CAAC,WAAW,CAAC,OAAO,CAAC,YAAY,EAAE,CAAC;QACrD,MAAM,MAAM,GAAG,EAAuB,CAAC;QACvC,IAAI,MAAM,CAAC,OAAO,KAAK,WAAW;YAAE,SAAS;QAC7C,MAAM,IAAI,GAAG,MAAM,CAAC,MAAM,EAAE,IAQf,CAAC;QACd,IAAI,CAAC,IAAI;YAAE,SAAS;QAEpB,MAAM,IAAI,GAAG,MAAM,CAAC,MAAM,EAAE,IAA0B,CAAC;QACvD,IAAI,IAAI,KAAK,UAAU,IAAI,IAAI,KAAK,iBAAiB;YAAE,SAAS;QAEhE,8EAA8E;QAC9E,mDAAmD;QACnD,MAAM,MAAM,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,iBAAiB,IAAI,EAAE,CAAC,CAAC,MAAM,CAAyB,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE;YACzF,IAAI,CAAC,CAAC,KAAK;gBAAE,GAAG,CAAC,CAAC,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC;YAC3C,OAAO,GAAG,CAAC;QACb,CAAC,EAAE,EAAE,CAAC,CAAC;QAEP,MAAM,SAAS,GAAG,EAAE,CAAC,WAAW,CAAC,OAAO,CAAC,WAAW,CAAC,SAAS,CAC5D,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,EAAE,KAAK,IAAI,CAAC,MAAM,CAC3C,CAAC;QACF,MAAM,OAAO,GAAG,EAAE,CAAC,WAAW,CAAC,OAAO,CAAC,WAAW,CAAC,SAAS,CAC1D,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,EAAE,KAAK,IAAI,CAAC,WAAW,CAChD,CAAC;QACF,MAAM,WAAW,GAAG,SAAS,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,IAAI,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC;QACpF,MAAM,SAAS,GAAG,OAAO,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC;QAExF,MAAM,MAAM,GAAG,IAAI,CAAC,SAAS,KAAK,YAAY,IAAI,WAAW,KAAK,YAAY,CAAC;QAC/E,MAAM,SAAS,GAAG,SAAS,KAAK,YAAY,CAAC;QAC7C,IAAI,CAAC,MAAM,IAAI,CAAC,SAAS;YAAE,SAAS;QAEpC,MAAM,SAAS,GAAG,IAAI,CAAC,WAAW,EAAE,MAAM,IAAI,IAAI,CAAC,MAAM,IAAI,GAAG,CAAC;QACjE,MAAM,QAAQ,GAAG,IAAI,CAAC,WAAW,EAAE,QAAQ,IAAI,CAAC,CAAC;QACjD,MAAM,MAAM,GAAG,MAAM,CAAC,SAAS,CAAC,GAAG,EAAE,IAAI,QAAQ,CAAC;QAElD,OAAO;YACL,SAAS,EAAE,IAAI,EAAE,sBAAsB;YACvC,OAAO,EAAE,QAAQ;YACjB,SAAS;YACT,SAAS,EAAE,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS;YACtC,YAAY,EAAE,MAAM,CAAC,CAAC,CAAC,SAAS,IAAI,EAAE,CAAC,CAAC,CAAC,WAAW,IAAI,EAAE;YAC1D,UAAU,EAAE,MAAM;SACnB,CAAC;IACJ,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unified history shape across networks. One entry per USDC transfer in or
|
|
3
|
+
* out of the wallet.
|
|
4
|
+
*
|
|
5
|
+
* v1 only surfaces USDC because that's what xPay actually transacts in
|
|
6
|
+
* (x402 is USDC-denominated). Future versions can extend `asset` to other
|
|
7
|
+
* tokens or even non-fungible payments.
|
|
8
|
+
*/
|
|
9
|
+
import type { Network } from "../types.js";
|
|
10
|
+
export interface HistoryEntry {
|
|
11
|
+
/** Unix ms timestamp the tx was confirmed (best-effort). */
|
|
12
|
+
timestamp: number | null;
|
|
13
|
+
/** Network the tx happened on. */
|
|
14
|
+
network: Network;
|
|
15
|
+
/** Settlement signature / tx hash. */
|
|
16
|
+
signature: string;
|
|
17
|
+
/** "send" when wallet was the sender, "receive" when the receiver. */
|
|
18
|
+
direction: "send" | "receive";
|
|
19
|
+
/** Other side of the transfer. */
|
|
20
|
+
counterparty: string;
|
|
21
|
+
/** Human USDC amount (positive, with 6-decimal precision). */
|
|
22
|
+
amountUsdc: number;
|
|
23
|
+
/** "confirmed" / "finalized" / "failed" — best-effort, may be undefined. */
|
|
24
|
+
status?: string;
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/history/types.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAE3C,MAAM,WAAW,YAAY;IAC3B,4DAA4D;IAC5D,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,kCAAkC;IAClC,OAAO,EAAE,OAAO,CAAC;IACjB,sCAAsC;IACtC,SAAS,EAAE,MAAM,CAAC;IAClB,sEAAsE;IACtE,SAAS,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B,kCAAkC;IAClC,YAAY,EAAE,MAAM,CAAC;IACrB,8DAA8D;IAC9D,UAAU,EAAE,MAAM,CAAC;IACnB,4EAA4E;IAC5E,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unified history shape across networks. One entry per USDC transfer in or
|
|
3
|
+
* out of the wallet.
|
|
4
|
+
*
|
|
5
|
+
* v1 only surfaces USDC because that's what xPay actually transacts in
|
|
6
|
+
* (x402 is USDC-denominated). Future versions can extend `asset` to other
|
|
7
|
+
* tokens or even non-fungible payments.
|
|
8
|
+
*/
|
|
9
|
+
export {};
|
|
10
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/history/types.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG"}
|