@oobe-protocol-labs/synapse-sap-sdk 0.6.3 → 0.7.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/dist/cjs/constants/seeds.js +7 -0
- package/dist/cjs/constants/seeds.js.map +1 -1
- package/dist/cjs/core/client.js +42 -0
- package/dist/cjs/core/client.js.map +1 -1
- package/dist/cjs/idl/synapse_agent_sap.json +7545 -3501
- package/dist/cjs/index.js +25 -3
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/modules/escrow-v2.js +241 -0
- package/dist/cjs/modules/escrow-v2.js.map +1 -0
- package/dist/cjs/modules/escrow.js +4 -0
- package/dist/cjs/modules/escrow.js.map +1 -1
- package/dist/cjs/modules/index.js +7 -1
- package/dist/cjs/modules/index.js.map +1 -1
- package/dist/cjs/modules/staking.js +94 -0
- package/dist/cjs/modules/staking.js.map +1 -0
- package/dist/cjs/modules/subscription.js +96 -0
- package/dist/cjs/modules/subscription.js.map +1 -0
- package/dist/cjs/pda/index.js +143 -1
- package/dist/cjs/pda/index.js.map +1 -1
- package/dist/cjs/registries/x402.js +88 -51
- package/dist/cjs/registries/x402.js.map +1 -1
- package/dist/cjs/types/enums.js +51 -1
- package/dist/cjs/types/enums.js.map +1 -1
- package/dist/cjs/types/index.js +4 -1
- package/dist/cjs/types/index.js.map +1 -1
- package/dist/cjs/types/instructions.js.map +1 -1
- package/dist/cjs/utils/escrow-validation.js +219 -0
- package/dist/cjs/utils/escrow-validation.js.map +1 -0
- package/dist/cjs/utils/index.js +12 -1
- package/dist/cjs/utils/index.js.map +1 -1
- package/dist/cjs/utils/merchant-validator.js +246 -0
- package/dist/cjs/utils/merchant-validator.js.map +1 -0
- package/dist/cjs/utils/x402-direct.js +231 -0
- package/dist/cjs/utils/x402-direct.js.map +1 -0
- package/dist/esm/constants/seeds.js +7 -0
- package/dist/esm/constants/seeds.js.map +1 -1
- package/dist/esm/core/client.js +42 -0
- package/dist/esm/core/client.js.map +1 -1
- package/dist/esm/idl/synapse_agent_sap.json +7545 -3501
- package/dist/esm/index.js +5 -3
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/modules/escrow-v2.js +237 -0
- package/dist/esm/modules/escrow-v2.js.map +1 -0
- package/dist/esm/modules/escrow.js +4 -0
- package/dist/esm/modules/escrow.js.map +1 -1
- package/dist/esm/modules/index.js +3 -0
- package/dist/esm/modules/index.js.map +1 -1
- package/dist/esm/modules/staking.js +90 -0
- package/dist/esm/modules/staking.js.map +1 -0
- package/dist/esm/modules/subscription.js +92 -0
- package/dist/esm/modules/subscription.js.map +1 -0
- package/dist/esm/pda/index.js +135 -0
- package/dist/esm/pda/index.js.map +1 -1
- package/dist/esm/registries/x402.js +89 -52
- package/dist/esm/registries/x402.js.map +1 -1
- package/dist/esm/types/enums.js +50 -0
- package/dist/esm/types/enums.js.map +1 -1
- package/dist/esm/types/index.js +1 -1
- package/dist/esm/types/index.js.map +1 -1
- package/dist/esm/types/instructions.js.map +1 -1
- package/dist/esm/utils/escrow-validation.js +212 -0
- package/dist/esm/utils/escrow-validation.js.map +1 -0
- package/dist/esm/utils/index.js +4 -0
- package/dist/esm/utils/index.js.map +1 -1
- package/dist/esm/utils/merchant-validator.js +241 -0
- package/dist/esm/utils/merchant-validator.js.map +1 -0
- package/dist/esm/utils/x402-direct.js +228 -0
- package/dist/esm/utils/x402-direct.js.map +1 -0
- package/dist/types/constants/seeds.d.ts +7 -0
- package/dist/types/constants/seeds.d.ts.map +1 -1
- package/dist/types/core/client.d.ts +33 -0
- package/dist/types/core/client.d.ts.map +1 -1
- package/dist/types/index.d.ts +6 -4
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/modules/escrow-v2.d.ts +51 -0
- package/dist/types/modules/escrow-v2.d.ts.map +1 -0
- package/dist/types/modules/escrow.d.ts +4 -0
- package/dist/types/modules/escrow.d.ts.map +1 -1
- package/dist/types/modules/index.d.ts +3 -0
- package/dist/types/modules/index.d.ts.map +1 -1
- package/dist/types/modules/staking.d.ts +32 -0
- package/dist/types/modules/staking.d.ts.map +1 -0
- package/dist/types/modules/subscription.d.ts +33 -0
- package/dist/types/modules/subscription.d.ts.map +1 -0
- package/dist/types/pda/index.d.ts +99 -0
- package/dist/types/pda/index.d.ts.map +1 -1
- package/dist/types/plugin/schemas.d.ts +2 -2
- package/dist/types/registries/x402.d.ts +14 -12
- package/dist/types/registries/x402.d.ts.map +1 -1
- package/dist/types/types/accounts.d.ts +157 -1
- package/dist/types/types/accounts.d.ts.map +1 -1
- package/dist/types/types/enums.d.ts +64 -0
- package/dist/types/types/enums.d.ts.map +1 -1
- package/dist/types/types/index.d.ts +4 -4
- package/dist/types/types/index.d.ts.map +1 -1
- package/dist/types/types/instructions.d.ts +34 -0
- package/dist/types/types/instructions.d.ts.map +1 -1
- package/dist/types/utils/escrow-validation.d.ts +145 -0
- package/dist/types/utils/escrow-validation.d.ts.map +1 -0
- package/dist/types/utils/index.d.ts +6 -0
- package/dist/types/utils/index.d.ts.map +1 -1
- package/dist/types/utils/merchant-validator.d.ts +176 -0
- package/dist/types/utils/merchant-validator.d.ts.map +1 -0
- package/dist/types/utils/x402-direct.d.ts +114 -0
- package/dist/types/utils/x402-direct.d.ts.map +1 -0
- package/package.json +1 -1
- package/src/constants/seeds.ts +7 -0
- package/src/core/client.ts +45 -0
- package/src/idl/synapse_agent_sap.json +7545 -3501
- package/src/index.ts +47 -0
- package/src/modules/escrow-v2.ts +396 -0
- package/src/modules/escrow.ts +4 -0
- package/src/modules/index.ts +3 -0
- package/src/modules/staking.ts +122 -0
- package/src/modules/subscription.ts +147 -0
- package/src/pda/index.ts +196 -0
- package/src/registries/x402.ts +108 -69
- package/src/types/accounts.ts +192 -1
- package/src/types/enums.ts +65 -0
- package/src/types/index.ts +15 -0
- package/src/types/instructions.ts +40 -0
- package/src/utils/escrow-validation.ts +301 -0
- package/src/utils/index.ts +28 -0
- package/src/utils/merchant-validator.ts +359 -0
- package/src/utils/x402-direct.ts +370 -0
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module subscription
|
|
3
|
+
* @description Agent subscription lifecycle — create, fund, cancel,
|
|
4
|
+
* close, and fetch subscription accounts.
|
|
5
|
+
*
|
|
6
|
+
* @category Modules
|
|
7
|
+
* @since v0.7.0
|
|
8
|
+
* @packageDocumentation
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import {
|
|
12
|
+
SystemProgram,
|
|
13
|
+
type PublicKey,
|
|
14
|
+
type TransactionSignature,
|
|
15
|
+
} from "@solana/web3.js";
|
|
16
|
+
import { BN } from "@coral-xyz/anchor";
|
|
17
|
+
import { BaseModule } from "./base";
|
|
18
|
+
import { deriveAgent, deriveSubscription } from "../pda";
|
|
19
|
+
import type { SubscriptionData, CreateSubscriptionArgs } from "../types";
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* @name SubscriptionModule
|
|
23
|
+
* @description Manages recurring subscriptions between subscribers and agents.
|
|
24
|
+
*
|
|
25
|
+
* @category Modules
|
|
26
|
+
* @since v0.7.0
|
|
27
|
+
* @extends BaseModule
|
|
28
|
+
*/
|
|
29
|
+
export class SubscriptionModule extends BaseModule {
|
|
30
|
+
// ── PDA helpers ──────────────────────────────────────
|
|
31
|
+
|
|
32
|
+
private toNum(v: BN | number | bigint): number {
|
|
33
|
+
return BN.isBN(v) ? v.toNumber() : Number(v);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
deriveSubscription(
|
|
37
|
+
agentPda: PublicKey,
|
|
38
|
+
subscriber?: PublicKey,
|
|
39
|
+
subId: BN | number | bigint = 0,
|
|
40
|
+
): readonly [PublicKey, number] {
|
|
41
|
+
return deriveSubscription(
|
|
42
|
+
agentPda,
|
|
43
|
+
subscriber ?? this.walletPubkey,
|
|
44
|
+
this.toNum(subId),
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// ── Instructions ─────────────────────────────────────
|
|
49
|
+
|
|
50
|
+
async create(
|
|
51
|
+
agentWallet: PublicKey,
|
|
52
|
+
args: CreateSubscriptionArgs,
|
|
53
|
+
): Promise<TransactionSignature> {
|
|
54
|
+
const [agentPda] = deriveAgent(agentWallet);
|
|
55
|
+
const [subPda] = this.deriveSubscription(agentPda, undefined, args.subId);
|
|
56
|
+
|
|
57
|
+
return this.methods
|
|
58
|
+
.createSubscription(
|
|
59
|
+
this.bn(args.subId),
|
|
60
|
+
this.bn(args.pricePerInterval),
|
|
61
|
+
args.billingInterval,
|
|
62
|
+
this.bn(args.initialFund),
|
|
63
|
+
)
|
|
64
|
+
.accounts({
|
|
65
|
+
subscriber: this.walletPubkey,
|
|
66
|
+
agent: agentPda,
|
|
67
|
+
subscription: subPda,
|
|
68
|
+
systemProgram: SystemProgram.programId,
|
|
69
|
+
})
|
|
70
|
+
.rpc();
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
async fund(
|
|
74
|
+
agentWallet: PublicKey,
|
|
75
|
+
subId: BN | number | bigint,
|
|
76
|
+
amount: BN | number | bigint,
|
|
77
|
+
): Promise<TransactionSignature> {
|
|
78
|
+
const [agentPda] = deriveAgent(agentWallet);
|
|
79
|
+
const [subPda] = this.deriveSubscription(agentPda, undefined, subId);
|
|
80
|
+
|
|
81
|
+
return this.methods
|
|
82
|
+
.fundSubscription(this.bn(amount))
|
|
83
|
+
.accounts({
|
|
84
|
+
subscriber: this.walletPubkey,
|
|
85
|
+
subscription: subPda,
|
|
86
|
+
systemProgram: SystemProgram.programId,
|
|
87
|
+
})
|
|
88
|
+
.rpc();
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
async cancel(
|
|
92
|
+
agentWallet: PublicKey,
|
|
93
|
+
subId: BN | number | bigint = 0,
|
|
94
|
+
): Promise<TransactionSignature> {
|
|
95
|
+
const [agentPda] = deriveAgent(agentWallet);
|
|
96
|
+
const [subPda] = this.deriveSubscription(agentPda, undefined, subId);
|
|
97
|
+
|
|
98
|
+
return this.methods
|
|
99
|
+
.cancelSubscription()
|
|
100
|
+
.accounts({
|
|
101
|
+
subscriber: this.walletPubkey,
|
|
102
|
+
agentWallet,
|
|
103
|
+
subscription: subPda,
|
|
104
|
+
})
|
|
105
|
+
.rpc();
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
async close(
|
|
109
|
+
agentWallet: PublicKey,
|
|
110
|
+
subId: BN | number | bigint = 0,
|
|
111
|
+
): Promise<TransactionSignature> {
|
|
112
|
+
const [agentPda] = deriveAgent(agentWallet);
|
|
113
|
+
const [subPda] = this.deriveSubscription(agentPda, undefined, subId);
|
|
114
|
+
|
|
115
|
+
return this.methods
|
|
116
|
+
.closeSubscription()
|
|
117
|
+
.accounts({
|
|
118
|
+
subscriber: this.walletPubkey,
|
|
119
|
+
subscription: subPda,
|
|
120
|
+
})
|
|
121
|
+
.rpc();
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// ── Fetchers ─────────────────────────────────────────
|
|
125
|
+
|
|
126
|
+
async fetch(
|
|
127
|
+
agentPda: PublicKey,
|
|
128
|
+
subscriber?: PublicKey,
|
|
129
|
+
subId: BN | number | bigint = 0,
|
|
130
|
+
): Promise<SubscriptionData> {
|
|
131
|
+
const [pda] = this.deriveSubscription(agentPda, subscriber, subId);
|
|
132
|
+
return this.fetchAccount<SubscriptionData>("subscriptionAccount", pda);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
async fetchNullable(
|
|
136
|
+
agentPda: PublicKey,
|
|
137
|
+
subscriber?: PublicKey,
|
|
138
|
+
subId: BN | number | bigint = 0,
|
|
139
|
+
): Promise<SubscriptionData | null> {
|
|
140
|
+
const [pda] = this.deriveSubscription(agentPda, subscriber, subId);
|
|
141
|
+
return this.fetchAccountNullable<SubscriptionData>("subscriptionAccount", pda);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
async fetchByPda(subPda: PublicKey): Promise<SubscriptionData> {
|
|
145
|
+
return this.fetchAccount<SubscriptionData>("subscriptionAccount", subPda);
|
|
146
|
+
}
|
|
147
|
+
}
|
package/src/pda/index.ts
CHANGED
|
@@ -79,6 +79,22 @@ const u32le = (n: number): Buffer => {
|
|
|
79
79
|
return buf;
|
|
80
80
|
};
|
|
81
81
|
|
|
82
|
+
/**
|
|
83
|
+
* Encode an unsigned 64-bit integer as a little-endian `Buffer`.
|
|
84
|
+
*
|
|
85
|
+
* @name u64le
|
|
86
|
+
* @description Produces an 8-byte LE buffer for u64 PDA seed segments (e.g., escrow nonce, sub_id).
|
|
87
|
+
* @param n - The number or bigint to encode.
|
|
88
|
+
* @returns {Buffer} 8-byte little-endian buffer.
|
|
89
|
+
* @category PDA
|
|
90
|
+
* @since v0.5.0
|
|
91
|
+
*/
|
|
92
|
+
const u64le = (n: number | bigint): Buffer => {
|
|
93
|
+
const buf = Buffer.alloc(8);
|
|
94
|
+
buf.writeBigUInt64LE(BigInt(n), 0);
|
|
95
|
+
return buf;
|
|
96
|
+
};
|
|
97
|
+
|
|
82
98
|
// ═════════════════════════════════════════════
|
|
83
99
|
// Core PDAs
|
|
84
100
|
// ═════════════════════════════════════════════
|
|
@@ -421,6 +437,7 @@ export const deriveTool = (
|
|
|
421
437
|
* @returns {PdaResult} `[pda, bump]` tuple.
|
|
422
438
|
* @category PDA
|
|
423
439
|
* @since v0.1.0
|
|
440
|
+
* @deprecated Since v0.7.0 — Use {@link deriveEscrowV2} for V2 escrows with nonce support.
|
|
424
441
|
* @see EscrowAccount
|
|
425
442
|
*/
|
|
426
443
|
export const deriveEscrow = (
|
|
@@ -650,3 +667,182 @@ export const deriveMemoryChunk = (
|
|
|
650
667
|
],
|
|
651
668
|
programId,
|
|
652
669
|
);
|
|
670
|
+
|
|
671
|
+
// ═════════════════════════════════════════════
|
|
672
|
+
// Escrow V2
|
|
673
|
+
// ═════════════════════════════════════════════
|
|
674
|
+
|
|
675
|
+
/**
|
|
676
|
+
* Derive the **EscrowAccountV2** PDA.
|
|
677
|
+
*
|
|
678
|
+
* Seeds: `["sap_escrow_v2", agent_pda, depositor_wallet, nonce_u64_le]`
|
|
679
|
+
*
|
|
680
|
+
* @name deriveEscrowV2
|
|
681
|
+
* @description Computes the V2 escrow PDA supporting nonce-based multi-escrow.
|
|
682
|
+
* @param agentPda - The agent's PDA.
|
|
683
|
+
* @param depositor - The depositor's wallet.
|
|
684
|
+
* @param nonce - Escrow nonce (u64) allowing multiple escrows per pair.
|
|
685
|
+
* @param programId - Override program ID.
|
|
686
|
+
* @returns {PdaResult} `[pda, bump]` tuple.
|
|
687
|
+
* @category PDA
|
|
688
|
+
* @since v0.5.0
|
|
689
|
+
*/
|
|
690
|
+
export const deriveEscrowV2 = (
|
|
691
|
+
agentPda: PublicKey,
|
|
692
|
+
depositor: PublicKey,
|
|
693
|
+
nonce: number | bigint = 0,
|
|
694
|
+
programId = SAP_PROGRAM_ID,
|
|
695
|
+
): PdaResult =>
|
|
696
|
+
findPda(
|
|
697
|
+
[
|
|
698
|
+
toSeedBuf(SEEDS.ESCROW_V2),
|
|
699
|
+
agentPda.toBuffer(),
|
|
700
|
+
depositor.toBuffer(),
|
|
701
|
+
u64le(nonce),
|
|
702
|
+
],
|
|
703
|
+
programId,
|
|
704
|
+
);
|
|
705
|
+
|
|
706
|
+
/**
|
|
707
|
+
* Derive the **PendingSettlement** PDA.
|
|
708
|
+
*
|
|
709
|
+
* Seeds: `["sap_pending", escrow_v2_pda, settlement_index_u64_le]`
|
|
710
|
+
*
|
|
711
|
+
* @name derivePendingSettlement
|
|
712
|
+
* @param escrowV2Pda - The parent V2 escrow PDA.
|
|
713
|
+
* @param settlementIndex - The monotonic settlement index (u64).
|
|
714
|
+
* @param programId - Override program ID.
|
|
715
|
+
* @returns {PdaResult} `[pda, bump]` tuple.
|
|
716
|
+
* @category PDA
|
|
717
|
+
* @since v0.5.0
|
|
718
|
+
*/
|
|
719
|
+
export const derivePendingSettlement = (
|
|
720
|
+
escrowV2Pda: PublicKey,
|
|
721
|
+
settlementIndex: number | bigint,
|
|
722
|
+
programId = SAP_PROGRAM_ID,
|
|
723
|
+
): PdaResult =>
|
|
724
|
+
findPda(
|
|
725
|
+
[
|
|
726
|
+
toSeedBuf(SEEDS.PENDING),
|
|
727
|
+
escrowV2Pda.toBuffer(),
|
|
728
|
+
u64le(settlementIndex),
|
|
729
|
+
],
|
|
730
|
+
programId,
|
|
731
|
+
);
|
|
732
|
+
|
|
733
|
+
/**
|
|
734
|
+
* Derive the **DisputeRecord** PDA.
|
|
735
|
+
*
|
|
736
|
+
* Seeds: `["sap_dispute", pending_settlement_pda]`
|
|
737
|
+
*
|
|
738
|
+
* @name deriveDispute
|
|
739
|
+
* @param pendingSettlementPda - The parent pending settlement PDA.
|
|
740
|
+
* @param programId - Override program ID.
|
|
741
|
+
* @returns {PdaResult} `[pda, bump]` tuple.
|
|
742
|
+
* @category PDA
|
|
743
|
+
* @since v0.5.0
|
|
744
|
+
*/
|
|
745
|
+
export const deriveDispute = (
|
|
746
|
+
pendingSettlementPda: PublicKey,
|
|
747
|
+
programId = SAP_PROGRAM_ID,
|
|
748
|
+
): PdaResult =>
|
|
749
|
+
findPda(
|
|
750
|
+
[toSeedBuf(SEEDS.DISPUTE), pendingSettlementPda.toBuffer()],
|
|
751
|
+
programId,
|
|
752
|
+
);
|
|
753
|
+
|
|
754
|
+
/**
|
|
755
|
+
* Derive the **AgentStake** PDA.
|
|
756
|
+
*
|
|
757
|
+
* Seeds: `["sap_stake", agent_pda]`
|
|
758
|
+
*
|
|
759
|
+
* @name deriveStake
|
|
760
|
+
* @param agentPda - The agent's PDA.
|
|
761
|
+
* @param programId - Override program ID.
|
|
762
|
+
* @returns {PdaResult} `[pda, bump]` tuple.
|
|
763
|
+
* @category PDA
|
|
764
|
+
* @since v0.5.0
|
|
765
|
+
*/
|
|
766
|
+
export const deriveStake = (
|
|
767
|
+
agentPda: PublicKey,
|
|
768
|
+
programId = SAP_PROGRAM_ID,
|
|
769
|
+
): PdaResult =>
|
|
770
|
+
findPda([toSeedBuf(SEEDS.STAKE), agentPda.toBuffer()], programId);
|
|
771
|
+
|
|
772
|
+
/**
|
|
773
|
+
* Derive the **Subscription** PDA.
|
|
774
|
+
*
|
|
775
|
+
* Seeds: `["sap_sub", agent_pda, subscriber_wallet, sub_id_u64_le]`
|
|
776
|
+
*
|
|
777
|
+
* @name deriveSubscription
|
|
778
|
+
* @param agentPda - The agent's PDA.
|
|
779
|
+
* @param subscriber - The subscriber's wallet.
|
|
780
|
+
* @param subId - Subscription ID (u64).
|
|
781
|
+
* @param programId - Override program ID.
|
|
782
|
+
* @returns {PdaResult} `[pda, bump]` tuple.
|
|
783
|
+
* @category PDA
|
|
784
|
+
* @since v0.5.0
|
|
785
|
+
*/
|
|
786
|
+
export const deriveSubscription = (
|
|
787
|
+
agentPda: PublicKey,
|
|
788
|
+
subscriber: PublicKey,
|
|
789
|
+
subId: number | bigint = 0,
|
|
790
|
+
programId = SAP_PROGRAM_ID,
|
|
791
|
+
): PdaResult =>
|
|
792
|
+
findPda(
|
|
793
|
+
[
|
|
794
|
+
toSeedBuf(SEEDS.SUBSCRIPTION),
|
|
795
|
+
agentPda.toBuffer(),
|
|
796
|
+
subscriber.toBuffer(),
|
|
797
|
+
u64le(subId),
|
|
798
|
+
],
|
|
799
|
+
programId,
|
|
800
|
+
);
|
|
801
|
+
|
|
802
|
+
/**
|
|
803
|
+
* Derive the **CounterShard** PDA.
|
|
804
|
+
*
|
|
805
|
+
* Seeds: `["sap_shard", shard_index_u8]`
|
|
806
|
+
*
|
|
807
|
+
* @name deriveShard
|
|
808
|
+
* @param shardIndex - The shard index (0–7).
|
|
809
|
+
* @param programId - Override program ID.
|
|
810
|
+
* @returns {PdaResult} `[pda, bump]` tuple.
|
|
811
|
+
* @category PDA
|
|
812
|
+
* @since v0.5.0
|
|
813
|
+
*/
|
|
814
|
+
export const deriveShard = (
|
|
815
|
+
shardIndex: number,
|
|
816
|
+
programId = SAP_PROGRAM_ID,
|
|
817
|
+
): PdaResult =>
|
|
818
|
+
findPda(
|
|
819
|
+
[toSeedBuf(SEEDS.SHARD), Buffer.from([shardIndex])],
|
|
820
|
+
programId,
|
|
821
|
+
);
|
|
822
|
+
|
|
823
|
+
/**
|
|
824
|
+
* Derive the **IndexPage** PDA.
|
|
825
|
+
*
|
|
826
|
+
* Seeds: `["sap_idx_page", parent_index_pda, page_index_u8]`
|
|
827
|
+
*
|
|
828
|
+
* @name deriveIndexPage
|
|
829
|
+
* @param parentIndexPda - The parent index PDA (CapabilityIndex, ProtocolIndex, etc.).
|
|
830
|
+
* @param pageIndex - The page index (0–255).
|
|
831
|
+
* @param programId - Override program ID.
|
|
832
|
+
* @returns {PdaResult} `[pda, bump]` tuple.
|
|
833
|
+
* @category PDA
|
|
834
|
+
* @since v0.5.0
|
|
835
|
+
*/
|
|
836
|
+
export const deriveIndexPage = (
|
|
837
|
+
parentIndexPda: PublicKey,
|
|
838
|
+
pageIndex: number,
|
|
839
|
+
programId = SAP_PROGRAM_ID,
|
|
840
|
+
): PdaResult =>
|
|
841
|
+
findPda(
|
|
842
|
+
[
|
|
843
|
+
toSeedBuf(SEEDS.INDEX_PAGE),
|
|
844
|
+
parentIndexPda.toBuffer(),
|
|
845
|
+
Buffer.from([pageIndex]),
|
|
846
|
+
],
|
|
847
|
+
programId,
|
|
848
|
+
);
|
package/src/registries/x402.ts
CHANGED
|
@@ -74,12 +74,14 @@ import {
|
|
|
74
74
|
deriveAgent,
|
|
75
75
|
deriveAgentStats,
|
|
76
76
|
deriveEscrow,
|
|
77
|
+
deriveEscrowV2,
|
|
77
78
|
} from "../pda";
|
|
78
79
|
import { sha256, hashToArray } from "../utils";
|
|
79
80
|
import { SapNetwork } from "../constants/network";
|
|
80
81
|
import type { SapNetworkId } from "../constants/network";
|
|
81
82
|
import type {
|
|
82
83
|
EscrowAccountData,
|
|
84
|
+
EscrowAccountV2Data,
|
|
83
85
|
AgentAccountData,
|
|
84
86
|
VolumeCurveBreakpoint,
|
|
85
87
|
Settlement,
|
|
@@ -371,18 +373,14 @@ export class X402Registry {
|
|
|
371
373
|
volumeCurve = opts.volumeCurve ?? [];
|
|
372
374
|
totalBefore = opts.totalCallsBefore ?? 0;
|
|
373
375
|
} else {
|
|
374
|
-
// Try to read from existing escrow
|
|
376
|
+
// Try to read from existing escrow (V2 first, then V1)
|
|
375
377
|
const [agentPda] = deriveAgent(agentWallet);
|
|
376
|
-
const
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
if (escrow) {
|
|
383
|
-
pricePerCall = escrow.pricePerCall;
|
|
384
|
-
volumeCurve = escrow.volumeCurve ?? [];
|
|
385
|
-
totalBefore = escrow.totalCallsSettled.toNumber();
|
|
378
|
+
const resolved = await this.resolveEscrow(agentPda, this.wallet);
|
|
379
|
+
|
|
380
|
+
if (resolved) {
|
|
381
|
+
pricePerCall = resolved.escrow.pricePerCall;
|
|
382
|
+
volumeCurve = resolved.escrow.volumeCurve ?? [];
|
|
383
|
+
totalBefore = resolved.escrow.totalCallsSettled.toNumber();
|
|
386
384
|
} else {
|
|
387
385
|
// Fall back to agent's first pricing tier
|
|
388
386
|
const agent = await this.fetchNullable<AgentAccountData>(
|
|
@@ -493,6 +491,8 @@ export class X402Registry {
|
|
|
493
491
|
* @param opts - Payment options (price, max calls, deposit, etc.).
|
|
494
492
|
* @returns A {@link PaymentContext} with escrow details and transaction signature.
|
|
495
493
|
* @since v0.1.0
|
|
494
|
+
* @deprecated Since v0.7.0 — Creates a V1 escrow. Use `client.escrowV2.create()` for
|
|
495
|
+
* V2 escrows with dispute windows, co-signing, and settlement security.
|
|
496
496
|
*
|
|
497
497
|
* @example
|
|
498
498
|
* ```ts
|
|
@@ -509,7 +509,6 @@ export class X402Registry {
|
|
|
509
509
|
): Promise<PaymentContext> {
|
|
510
510
|
const [agentPda] = deriveAgent(agentWallet);
|
|
511
511
|
const [escrowPda] = deriveEscrow(agentPda, this.wallet);
|
|
512
|
-
const [statsPda] = deriveAgentStats(agentPda);
|
|
513
512
|
|
|
514
513
|
const pricePerCall = new BN(opts.pricePerCall.toString());
|
|
515
514
|
const maxCalls = new BN((opts.maxCalls ?? 0).toString());
|
|
@@ -536,7 +535,6 @@ export class X402Registry {
|
|
|
536
535
|
.accounts({
|
|
537
536
|
depositor: this.wallet,
|
|
538
537
|
agent: agentPda,
|
|
539
|
-
agentStats: statsPda,
|
|
540
538
|
escrow: escrowPda,
|
|
541
539
|
systemProgram: SystemProgram.programId,
|
|
542
540
|
})
|
|
@@ -562,6 +560,7 @@ export class X402Registry {
|
|
|
562
560
|
* @param amount - Amount to deposit in smallest token unit.
|
|
563
561
|
* @returns The transaction signature.
|
|
564
562
|
* @since v0.1.0
|
|
563
|
+
* @deprecated Since v0.7.0 — Operates on V1 escrows only. Use `client.escrowV2.deposit()` instead.
|
|
565
564
|
*/
|
|
566
565
|
async addFunds(
|
|
567
566
|
agentWallet: PublicKey,
|
|
@@ -588,6 +587,7 @@ export class X402Registry {
|
|
|
588
587
|
* @param amount - Amount to withdraw in smallest token unit.
|
|
589
588
|
* @returns The transaction signature.
|
|
590
589
|
* @since v0.1.0
|
|
590
|
+
* @deprecated Since v0.7.0 — Operates on V1 escrows only. Use `client.escrowV2.withdraw()` instead.
|
|
591
591
|
*/
|
|
592
592
|
async withdrawFunds(
|
|
593
593
|
agentWallet: PublicKey,
|
|
@@ -614,6 +614,7 @@ export class X402Registry {
|
|
|
614
614
|
* @param agentWallet - Agent wallet of the escrow.
|
|
615
615
|
* @returns The transaction signature.
|
|
616
616
|
* @since v0.1.0
|
|
617
|
+
* @deprecated Since v0.7.0 — Operates on V1 escrows only. Use `client.escrowV2.close()` instead.
|
|
617
618
|
*/
|
|
618
619
|
async closeEscrow(agentWallet: PublicKey): Promise<TransactionSignature> {
|
|
619
620
|
const [agentPda] = deriveAgent(agentWallet);
|
|
@@ -678,17 +679,14 @@ export class X402Registry {
|
|
|
678
679
|
opts?: { network?: SapNetworkId | string },
|
|
679
680
|
): Promise<X402Headers | null> {
|
|
680
681
|
const [agentPda] = deriveAgent(agentWallet);
|
|
681
|
-
const
|
|
682
|
+
const resolved = await this.resolveEscrow(agentPda, this.wallet);
|
|
683
|
+
if (!resolved) return null;
|
|
682
684
|
|
|
683
|
-
const escrow =
|
|
684
|
-
"escrowAccount",
|
|
685
|
-
escrowPda,
|
|
686
|
-
);
|
|
687
|
-
if (!escrow) return null;
|
|
685
|
+
const escrow = resolved.escrow;
|
|
688
686
|
|
|
689
687
|
return {
|
|
690
688
|
"X-Payment-Protocol": "SAP-x402",
|
|
691
|
-
"X-Payment-Escrow": escrowPda.toBase58(),
|
|
689
|
+
"X-Payment-Escrow": resolved.escrowPda.toBase58(),
|
|
692
690
|
"X-Payment-Agent": agentPda.toBase58(),
|
|
693
691
|
"X-Payment-Depositor": this.wallet.toBase58(),
|
|
694
692
|
"X-Payment-MaxCalls": escrow.maxCalls.toString(),
|
|
@@ -742,14 +740,16 @@ export class X402Registry {
|
|
|
742
740
|
);
|
|
743
741
|
|
|
744
742
|
const [agentPda] = deriveAgent(this.wallet);
|
|
745
|
-
const [escrowPda] = deriveEscrow(agentPda, depositorWallet);
|
|
746
743
|
const [statsPda] = deriveAgentStats(agentPda);
|
|
747
744
|
|
|
748
|
-
//
|
|
749
|
-
const
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
745
|
+
// Auto-detect escrow version
|
|
746
|
+
const resolved = await this.resolveEscrow(agentPda, depositorWallet);
|
|
747
|
+
if (!resolved) {
|
|
748
|
+
throw new Error("No escrow found for this agent + depositor pair");
|
|
749
|
+
}
|
|
750
|
+
|
|
751
|
+
const escrow = resolved.escrow;
|
|
752
|
+
const escrowPda = resolved.escrowPda;
|
|
753
753
|
const estimate = this.calculateCost(
|
|
754
754
|
escrow.pricePerCall,
|
|
755
755
|
escrow.volumeCurve,
|
|
@@ -761,15 +761,29 @@ export class X402Registry {
|
|
|
761
761
|
const preIxs = buildPriorityFeeIxs(opts);
|
|
762
762
|
const rpcOpts = buildRpcOptions(opts);
|
|
763
763
|
|
|
764
|
-
let builder
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
764
|
+
let builder;
|
|
765
|
+
if (resolved.version === 2) {
|
|
766
|
+
// V2: settleCallsV2 requires escrow_nonce (default 0)
|
|
767
|
+
builder = this.methods
|
|
768
|
+
.settleCallsV2(new BN(0), new BN(callsToSettle), serviceHash)
|
|
769
|
+
.accounts({
|
|
770
|
+
wallet: this.wallet,
|
|
771
|
+
agent: agentPda,
|
|
772
|
+
agentStats: statsPda,
|
|
773
|
+
escrow: escrowPda,
|
|
774
|
+
systemProgram: SystemProgram.programId,
|
|
775
|
+
});
|
|
776
|
+
} else {
|
|
777
|
+
builder = this.methods
|
|
778
|
+
.settleCalls(new BN(callsToSettle), serviceHash)
|
|
779
|
+
.accounts({
|
|
780
|
+
wallet: this.wallet,
|
|
781
|
+
agent: agentPda,
|
|
782
|
+
agentStats: statsPda,
|
|
783
|
+
escrow: escrowPda,
|
|
784
|
+
systemProgram: SystemProgram.programId,
|
|
785
|
+
});
|
|
786
|
+
}
|
|
773
787
|
|
|
774
788
|
if (preIxs.length > 0) {
|
|
775
789
|
builder = builder.preInstructions(preIxs);
|
|
@@ -825,14 +839,16 @@ export class X402Registry {
|
|
|
825
839
|
const totalCalls = entries.reduce((sum, e) => sum + e.calls, 0);
|
|
826
840
|
|
|
827
841
|
const [agentPda] = deriveAgent(this.wallet);
|
|
828
|
-
const [escrowPda] = deriveEscrow(agentPda, depositorWallet);
|
|
829
842
|
const [statsPda] = deriveAgentStats(agentPda);
|
|
830
843
|
|
|
831
|
-
//
|
|
832
|
-
const
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
844
|
+
// Auto-detect escrow version
|
|
845
|
+
const resolved = await this.resolveEscrow(agentPda, depositorWallet);
|
|
846
|
+
if (!resolved) {
|
|
847
|
+
throw new Error("No escrow found for this agent + depositor pair");
|
|
848
|
+
}
|
|
849
|
+
|
|
850
|
+
const escrow = resolved.escrow;
|
|
851
|
+
const escrowPda = resolved.escrowPda;
|
|
836
852
|
const estimate = this.calculateCost(
|
|
837
853
|
escrow.pricePerCall,
|
|
838
854
|
escrow.volumeCurve,
|
|
@@ -887,21 +903,17 @@ export class X402Registry {
|
|
|
887
903
|
): Promise<EscrowBalance | null> {
|
|
888
904
|
const [agentPda] = deriveAgent(agentWallet);
|
|
889
905
|
const dep = depositor ?? this.wallet;
|
|
890
|
-
const [escrowPda] = deriveEscrow(agentPda, dep);
|
|
891
906
|
|
|
892
|
-
const
|
|
893
|
-
|
|
894
|
-
escrowPda,
|
|
895
|
-
);
|
|
896
|
-
if (!escrow) return null;
|
|
907
|
+
const resolved = await this.resolveEscrow(agentPda, dep);
|
|
908
|
+
if (!resolved) return null;
|
|
897
909
|
|
|
910
|
+
const escrow = resolved.escrow;
|
|
898
911
|
const now = Math.floor(Date.now() / 1000);
|
|
899
912
|
const isExpired = escrow.expiresAt.toNumber() > 0 && now >= escrow.expiresAt.toNumber();
|
|
900
913
|
const maxCalls = escrow.maxCalls.toNumber();
|
|
901
914
|
const settled = escrow.totalCallsSettled.toNumber();
|
|
902
915
|
const callsRemaining = maxCalls > 0 ? maxCalls - settled : Infinity;
|
|
903
916
|
|
|
904
|
-
// Estimate affordable calls with current balance
|
|
905
917
|
const pricePerCall = escrow.pricePerCall.toNumber();
|
|
906
918
|
const balance = escrow.balance.toNumber();
|
|
907
919
|
const affordableCalls = pricePerCall > 0
|
|
@@ -933,9 +945,18 @@ export class X402Registry {
|
|
|
933
945
|
depositor?: PublicKey,
|
|
934
946
|
): Promise<boolean> {
|
|
935
947
|
const [agentPda] = deriveAgent(agentWallet);
|
|
936
|
-
const
|
|
937
|
-
const
|
|
938
|
-
|
|
948
|
+
const dep = depositor ?? this.wallet;
|
|
949
|
+
const conn = this.program.provider.connection;
|
|
950
|
+
|
|
951
|
+
// Check V2 first (nonce=0)
|
|
952
|
+
const [v2Pda] = deriveEscrowV2(agentPda, dep, 0);
|
|
953
|
+
const v2Info = await conn.getAccountInfo(v2Pda);
|
|
954
|
+
if (v2Info !== null) return true;
|
|
955
|
+
|
|
956
|
+
// Fall back to V1
|
|
957
|
+
const [v1Pda] = deriveEscrow(agentPda, dep);
|
|
958
|
+
const v1Info = await conn.getAccountInfo(v1Pda);
|
|
959
|
+
return v1Info !== null;
|
|
939
960
|
}
|
|
940
961
|
|
|
941
962
|
/**
|
|
@@ -950,11 +971,11 @@ export class X402Registry {
|
|
|
950
971
|
async fetchEscrow(
|
|
951
972
|
agentWallet: PublicKey,
|
|
952
973
|
depositor?: PublicKey,
|
|
953
|
-
): Promise<EscrowAccountData | null> {
|
|
974
|
+
): Promise<EscrowAccountData | EscrowAccountV2Data | null> {
|
|
954
975
|
const [agentPda] = deriveAgent(agentWallet);
|
|
955
976
|
const dep = depositor ?? this.wallet;
|
|
956
|
-
const
|
|
957
|
-
return
|
|
977
|
+
const resolved = await this.resolveEscrow(agentPda, dep);
|
|
978
|
+
return resolved?.escrow ?? null;
|
|
958
979
|
}
|
|
959
980
|
|
|
960
981
|
// ── Internals ────────────────────────────────────────
|
|
@@ -971,21 +992,6 @@ export class X402Registry {
|
|
|
971
992
|
return this.program.methods;
|
|
972
993
|
}
|
|
973
994
|
|
|
974
|
-
/**
|
|
975
|
-
* @name fetch
|
|
976
|
-
* @description Fetch an on-chain account by name and PDA. Throws if not found.
|
|
977
|
-
* @param name - Anchor account discriminator name.
|
|
978
|
-
* @param pda - Account public key to fetch.
|
|
979
|
-
* @returns The deserialized account data.
|
|
980
|
-
* @throws If the account does not exist.
|
|
981
|
-
* @private
|
|
982
|
-
*/
|
|
983
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
984
|
-
private async fetch<T>(name: string, pda: PublicKey): Promise<T> {
|
|
985
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-explicit-any
|
|
986
|
-
return (this.program.account as any)[name].fetch(pda) as Promise<T>;
|
|
987
|
-
}
|
|
988
|
-
|
|
989
995
|
/**
|
|
990
996
|
* @name fetchNullable
|
|
991
997
|
* @description Fetch an on-chain account by name and PDA. Returns `null` if not found.
|
|
@@ -999,4 +1005,37 @@ export class X402Registry {
|
|
|
999
1005
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-explicit-any
|
|
1000
1006
|
return (this.program.account as any)[name].fetchNullable(pda) as Promise<T | null>;
|
|
1001
1007
|
}
|
|
1008
|
+
|
|
1009
|
+
/**
|
|
1010
|
+
* @name resolveEscrow
|
|
1011
|
+
* @description Try to find an escrow: V2 (nonce=0) first, then V1 fallback.
|
|
1012
|
+
* Returns the escrow data, PDA, and version indicator.
|
|
1013
|
+
* @private
|
|
1014
|
+
*/
|
|
1015
|
+
private async resolveEscrow(
|
|
1016
|
+
agentPda: PublicKey,
|
|
1017
|
+
depositor: PublicKey,
|
|
1018
|
+
): Promise<{
|
|
1019
|
+
escrow: EscrowAccountData | EscrowAccountV2Data;
|
|
1020
|
+
escrowPda: PublicKey;
|
|
1021
|
+
version: 1 | 2;
|
|
1022
|
+
} | null> {
|
|
1023
|
+
// Try V2 first (nonce=0 is the default)
|
|
1024
|
+
const [v2Pda] = deriveEscrowV2(agentPda, depositor, 0);
|
|
1025
|
+
const v2 = await this.fetchNullable<EscrowAccountV2Data>(
|
|
1026
|
+
"escrowAccountV2",
|
|
1027
|
+
v2Pda,
|
|
1028
|
+
);
|
|
1029
|
+
if (v2) return { escrow: v2, escrowPda: v2Pda, version: 2 };
|
|
1030
|
+
|
|
1031
|
+
// Fall back to V1
|
|
1032
|
+
const [v1Pda] = deriveEscrow(agentPda, depositor);
|
|
1033
|
+
const v1 = await this.fetchNullable<EscrowAccountData>(
|
|
1034
|
+
"escrowAccount",
|
|
1035
|
+
v1Pda,
|
|
1036
|
+
);
|
|
1037
|
+
if (v1) return { escrow: v1, escrowPda: v1Pda, version: 1 };
|
|
1038
|
+
|
|
1039
|
+
return null;
|
|
1040
|
+
}
|
|
1002
1041
|
}
|