@vouch-protocol/sdk 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/README.md +87 -0
- package/dist/sdk/src/config.d.ts +18 -0
- package/dist/sdk/src/config.d.ts.map +1 -0
- package/dist/sdk/src/config.js +48 -0
- package/dist/sdk/src/config.js.map +1 -0
- package/dist/sdk/src/constants.d.ts +111 -0
- package/dist/sdk/src/constants.d.ts.map +1 -0
- package/dist/sdk/src/constants.js +123 -0
- package/dist/sdk/src/constants.js.map +1 -0
- package/dist/sdk/src/credentials.d.ts +85 -0
- package/dist/sdk/src/credentials.d.ts.map +1 -0
- package/dist/sdk/src/credentials.js +91 -0
- package/dist/sdk/src/credentials.js.map +1 -0
- package/dist/sdk/src/did.d.ts +68 -0
- package/dist/sdk/src/did.d.ts.map +1 -0
- package/dist/sdk/src/did.js +89 -0
- package/dist/sdk/src/did.js.map +1 -0
- package/dist/sdk/src/index.d.ts +9 -0
- package/dist/sdk/src/index.d.ts.map +1 -0
- package/dist/sdk/src/index.js +28 -0
- package/dist/sdk/src/index.js.map +1 -0
- package/dist/sdk/src/registry.d.ts +69 -0
- package/dist/sdk/src/registry.d.ts.map +1 -0
- package/dist/sdk/src/registry.js +179 -0
- package/dist/sdk/src/registry.js.map +1 -0
- package/dist/sdk/src/types.d.ts +107 -0
- package/dist/sdk/src/types.d.ts.map +1 -0
- package/dist/sdk/src/types.js +46 -0
- package/dist/sdk/src/types.js.map +1 -0
- package/dist/sdk/src/vault.d.ts +51 -0
- package/dist/sdk/src/vault.d.ts.map +1 -0
- package/dist/sdk/src/vault.js +128 -0
- package/dist/sdk/src/vault.js.map +1 -0
- package/dist/target/types/kya.d.ts +5074 -0
- package/dist/target/types/kya.d.ts.map +1 -0
- package/dist/target/types/kya.js +3 -0
- package/dist/target/types/kya.js.map +1 -0
- package/package.json +41 -0
- package/src/config.ts +55 -0
- package/src/constants.ts +134 -0
- package/src/credentials.ts +115 -0
- package/src/did.ts +140 -0
- package/src/index.ts +8 -0
- package/src/registry.ts +287 -0
- package/src/types.ts +129 -0
- package/src/vault.ts +208 -0
package/src/registry.ts
ADDED
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
import { Program, AnchorProvider, BN } from "@coral-xyz/anchor";
|
|
2
|
+
import { PublicKey, SystemProgram } from "@solana/web3.js";
|
|
3
|
+
import { Kya } from "../../target/types/kya";
|
|
4
|
+
import { SEEDS, VOUCH_PROGRAM_ID } from "./constants";
|
|
5
|
+
import type { VouchConfig, AgentIdentity } from "./types";
|
|
6
|
+
import { deriveAgentDid, parseDid, generateDidDocument } from "./did";
|
|
7
|
+
import type { DidDocument } from "./did";
|
|
8
|
+
|
|
9
|
+
export class RegistryClient {
|
|
10
|
+
constructor(
|
|
11
|
+
public readonly program: Program<Kya>,
|
|
12
|
+
public readonly provider: AnchorProvider
|
|
13
|
+
) {}
|
|
14
|
+
|
|
15
|
+
// ── PDA derivation ──
|
|
16
|
+
|
|
17
|
+
static findConfigPda(
|
|
18
|
+
programId: PublicKey = VOUCH_PROGRAM_ID
|
|
19
|
+
): [PublicKey, number] {
|
|
20
|
+
return PublicKey.findProgramAddressSync([SEEDS.VOUCH_CONFIG], programId);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
static findAgentPda(
|
|
24
|
+
owner: PublicKey,
|
|
25
|
+
programId: PublicKey = VOUCH_PROGRAM_ID
|
|
26
|
+
): [PublicKey, number] {
|
|
27
|
+
return PublicKey.findProgramAddressSync(
|
|
28
|
+
[SEEDS.AGENT, owner.toBuffer()],
|
|
29
|
+
programId
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
static findDeactivationRecordPda(
|
|
34
|
+
owner: PublicKey,
|
|
35
|
+
programId: PublicKey = VOUCH_PROGRAM_ID
|
|
36
|
+
): [PublicKey, number] {
|
|
37
|
+
return PublicKey.findProgramAddressSync(
|
|
38
|
+
[SEEDS.DEACTIVATED, owner.toBuffer()],
|
|
39
|
+
programId
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// ── Instructions (agent owner operations) ──
|
|
44
|
+
|
|
45
|
+
async registerAgent(params: {
|
|
46
|
+
owner: PublicKey;
|
|
47
|
+
name: string;
|
|
48
|
+
serviceCategory: Record<string, Record<string, never>>;
|
|
49
|
+
agentCardUrl: string;
|
|
50
|
+
agentCardHash: number[] | Uint8Array;
|
|
51
|
+
}) {
|
|
52
|
+
const [configPda] = RegistryClient.findConfigPda(this.program.programId);
|
|
53
|
+
const [agentPda] = RegistryClient.findAgentPda(
|
|
54
|
+
params.owner,
|
|
55
|
+
this.program.programId
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
return this.program.methods
|
|
59
|
+
.registerAgent(
|
|
60
|
+
params.name,
|
|
61
|
+
params.serviceCategory as any,
|
|
62
|
+
params.agentCardUrl,
|
|
63
|
+
Array.from(params.agentCardHash),
|
|
64
|
+
)
|
|
65
|
+
.accounts({
|
|
66
|
+
owner: params.owner,
|
|
67
|
+
config: configPda,
|
|
68
|
+
agent: agentPda,
|
|
69
|
+
deactivationRecord: PublicKey.findProgramAddressSync(
|
|
70
|
+
[SEEDS.DEACTIVATED, params.owner.toBuffer()],
|
|
71
|
+
this.program.programId,
|
|
72
|
+
)[0],
|
|
73
|
+
systemProgram: SystemProgram.programId,
|
|
74
|
+
} as any)
|
|
75
|
+
.rpc();
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
async updateAgent(params: {
|
|
79
|
+
owner: PublicKey;
|
|
80
|
+
agentPda: PublicKey;
|
|
81
|
+
newCapabilities?: BN | number | null;
|
|
82
|
+
newName?: string | null;
|
|
83
|
+
newServiceCategory?: Record<string, Record<string, never>> | null;
|
|
84
|
+
newVersion?: string | null;
|
|
85
|
+
newAgentCardUrl?: string | null;
|
|
86
|
+
newAgentCardHash?: number[] | Uint8Array | null;
|
|
87
|
+
}) {
|
|
88
|
+
const [configPda] = RegistryClient.findConfigPda(this.program.programId);
|
|
89
|
+
|
|
90
|
+
return this.program.methods
|
|
91
|
+
.updateAgent(
|
|
92
|
+
params.newCapabilities !== undefined && params.newCapabilities !== null
|
|
93
|
+
? new BN(params.newCapabilities) : null,
|
|
94
|
+
params.newName ?? null,
|
|
95
|
+
(params.newServiceCategory as any) ?? null,
|
|
96
|
+
params.newVersion ?? null,
|
|
97
|
+
params.newAgentCardUrl ?? null,
|
|
98
|
+
params.newAgentCardHash ? Array.from(params.newAgentCardHash) : null,
|
|
99
|
+
)
|
|
100
|
+
.accounts({
|
|
101
|
+
owner: params.owner,
|
|
102
|
+
config: configPda,
|
|
103
|
+
agent: params.agentPda,
|
|
104
|
+
} as any)
|
|
105
|
+
.rpc();
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
async deactivateAgent(params: {
|
|
109
|
+
owner: PublicKey;
|
|
110
|
+
agentPda: PublicKey;
|
|
111
|
+
}) {
|
|
112
|
+
const [configPda] = RegistryClient.findConfigPda(this.program.programId);
|
|
113
|
+
|
|
114
|
+
return this.program.methods
|
|
115
|
+
.deactivateAgent()
|
|
116
|
+
.accounts({
|
|
117
|
+
owner: params.owner,
|
|
118
|
+
config: configPda,
|
|
119
|
+
agent: params.agentPda,
|
|
120
|
+
deactivationRecord: PublicKey.findProgramAddressSync(
|
|
121
|
+
[SEEDS.DEACTIVATED, params.owner.toBuffer()],
|
|
122
|
+
this.program.programId,
|
|
123
|
+
)[0],
|
|
124
|
+
systemProgram: SystemProgram.programId,
|
|
125
|
+
} as any)
|
|
126
|
+
.rpc();
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
async closeAgent(params: {
|
|
130
|
+
owner: PublicKey;
|
|
131
|
+
agentPda: PublicKey;
|
|
132
|
+
}) {
|
|
133
|
+
// V6-M10: Include stake_account PDA required by on-chain CloseAgent
|
|
134
|
+
const [stakePda] = PublicKey.findProgramAddressSync(
|
|
135
|
+
[SEEDS.STAKE, params.agentPda.toBuffer()],
|
|
136
|
+
this.program.programId,
|
|
137
|
+
);
|
|
138
|
+
const [configPda] = RegistryClient.findConfigPda(this.program.programId);
|
|
139
|
+
|
|
140
|
+
return this.program.methods
|
|
141
|
+
.closeAgent()
|
|
142
|
+
.accounts({
|
|
143
|
+
owner: params.owner,
|
|
144
|
+
config: configPda,
|
|
145
|
+
agent: params.agentPda,
|
|
146
|
+
stakeAccount: stakePda,
|
|
147
|
+
} as any)
|
|
148
|
+
.rpc();
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
async suspendAgent(params: {
|
|
152
|
+
authority: PublicKey;
|
|
153
|
+
agentPda: PublicKey;
|
|
154
|
+
}) {
|
|
155
|
+
const [configPda] = RegistryClient.findConfigPda(this.program.programId);
|
|
156
|
+
|
|
157
|
+
return this.program.methods
|
|
158
|
+
.suspendAgent()
|
|
159
|
+
.accounts({
|
|
160
|
+
authority: params.authority,
|
|
161
|
+
config: configPda,
|
|
162
|
+
agent: params.agentPda,
|
|
163
|
+
} as any)
|
|
164
|
+
.rpc();
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
async reactivateAgent(params: {
|
|
168
|
+
authority: PublicKey;
|
|
169
|
+
agentPda: PublicKey;
|
|
170
|
+
}) {
|
|
171
|
+
const [configPda] = RegistryClient.findConfigPda(this.program.programId);
|
|
172
|
+
|
|
173
|
+
return this.program.methods
|
|
174
|
+
.reactivateAgent()
|
|
175
|
+
.accounts({
|
|
176
|
+
authority: params.authority,
|
|
177
|
+
config: configPda,
|
|
178
|
+
agent: params.agentPda,
|
|
179
|
+
} as any)
|
|
180
|
+
.rpc();
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
async closeDeactivationRecord(params: {
|
|
184
|
+
owner: PublicKey;
|
|
185
|
+
}) {
|
|
186
|
+
const [configPda] = RegistryClient.findConfigPda(this.program.programId);
|
|
187
|
+
const [deactivationRecordPda] = PublicKey.findProgramAddressSync(
|
|
188
|
+
[SEEDS.DEACTIVATED, params.owner.toBuffer()],
|
|
189
|
+
this.program.programId,
|
|
190
|
+
);
|
|
191
|
+
|
|
192
|
+
return this.program.methods
|
|
193
|
+
.closeDeactivationRecord()
|
|
194
|
+
.accounts({
|
|
195
|
+
owner: params.owner,
|
|
196
|
+
config: configPda,
|
|
197
|
+
deactivationRecord: deactivationRecordPda,
|
|
198
|
+
} as any)
|
|
199
|
+
.rpc();
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
async checkAgentEligibility(agentPda: PublicKey) {
|
|
203
|
+
const [configPda] = RegistryClient.findConfigPda(this.program.programId);
|
|
204
|
+
|
|
205
|
+
return this.program.methods
|
|
206
|
+
.checkAgentEligibility()
|
|
207
|
+
.accounts({
|
|
208
|
+
agent: agentPda,
|
|
209
|
+
config: configPda,
|
|
210
|
+
} as any)
|
|
211
|
+
.rpc();
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
async verifyAgent(agentPda: PublicKey) {
|
|
215
|
+
const [configPda] = RegistryClient.findConfigPda(this.program.programId);
|
|
216
|
+
|
|
217
|
+
return this.program.methods
|
|
218
|
+
.verifyAgent()
|
|
219
|
+
.accounts({
|
|
220
|
+
agent: agentPda,
|
|
221
|
+
config: configPda,
|
|
222
|
+
} as any)
|
|
223
|
+
.rpc();
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// ── Fetchers ──
|
|
227
|
+
|
|
228
|
+
async fetchConfig(): Promise<VouchConfig> {
|
|
229
|
+
const [configPda] = RegistryClient.findConfigPda(this.program.programId);
|
|
230
|
+
return this.program.account.vouchConfig.fetch(configPda) as Promise<any>;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
async fetchAgent(agentPda: PublicKey): Promise<AgentIdentity> {
|
|
234
|
+
return this.program.account.agentIdentity.fetch(agentPda) as Promise<any>;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
async fetchAgentByOwner(owner: PublicKey): Promise<AgentIdentity> {
|
|
238
|
+
const [agentPda] = RegistryClient.findAgentPda(
|
|
239
|
+
owner,
|
|
240
|
+
this.program.programId
|
|
241
|
+
);
|
|
242
|
+
return this.fetchAgent(agentPda);
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
async fetchDeactivationRecord(owner: PublicKey): Promise<any> {
|
|
246
|
+
const [pda] = RegistryClient.findDeactivationRecordPda(
|
|
247
|
+
owner,
|
|
248
|
+
this.program.programId
|
|
249
|
+
);
|
|
250
|
+
return this.program.account.deactivationRecord.fetch(pda);
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
// ── DID Resolution ──
|
|
254
|
+
|
|
255
|
+
/**
|
|
256
|
+
* Derive the W3C DID (did:sol:<base58>) for an agent owner.
|
|
257
|
+
*/
|
|
258
|
+
static deriveAgentDid(owner: PublicKey): string {
|
|
259
|
+
return deriveAgentDid(owner);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
/**
|
|
263
|
+
* Resolve a did:sol URI to the on-chain AgentIdentity.
|
|
264
|
+
* Returns null if the DID is invalid or the agent doesn't exist.
|
|
265
|
+
*/
|
|
266
|
+
async resolveAgentByDid(did: string): Promise<AgentIdentity | null> {
|
|
267
|
+
const owner = parseDid(did);
|
|
268
|
+
if (!owner) return null;
|
|
269
|
+
try {
|
|
270
|
+
return await this.fetchAgentByOwner(owner);
|
|
271
|
+
} catch {
|
|
272
|
+
return null;
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
/**
|
|
277
|
+
* Generate a W3C DID Document for a Vouch-registered agent.
|
|
278
|
+
*/
|
|
279
|
+
async generateDidDocument(owner: PublicKey): Promise<DidDocument> {
|
|
280
|
+
const [agentPda] = RegistryClient.findAgentPda(
|
|
281
|
+
owner,
|
|
282
|
+
this.program.programId
|
|
283
|
+
);
|
|
284
|
+
const agent = await this.fetchAgent(agentPda);
|
|
285
|
+
return generateDidDocument({ owner, agentPda, agent });
|
|
286
|
+
}
|
|
287
|
+
}
|
package/src/types.ts
ADDED
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import { PublicKey } from "@solana/web3.js";
|
|
2
|
+
import { BN } from "@coral-xyz/anchor";
|
|
3
|
+
|
|
4
|
+
// ── Enums ──
|
|
5
|
+
|
|
6
|
+
export enum AgentTier {
|
|
7
|
+
Observer = "observer",
|
|
8
|
+
Basic = "basic",
|
|
9
|
+
Standard = "standard",
|
|
10
|
+
Premium = "premium",
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export enum AgentStatus {
|
|
14
|
+
Active = "active",
|
|
15
|
+
Suspended = "suspended",
|
|
16
|
+
Deactivated = "deactivated",
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export enum ServiceCategory {
|
|
20
|
+
Commerce = "commerce",
|
|
21
|
+
DataAnalysis = "dataAnalysis",
|
|
22
|
+
ContentCreation = "contentCreation",
|
|
23
|
+
CustomerService = "customerService",
|
|
24
|
+
Financial = "financial",
|
|
25
|
+
Logistics = "logistics",
|
|
26
|
+
Development = "development",
|
|
27
|
+
Research = "research",
|
|
28
|
+
Other = "other",
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// ── Account types ──
|
|
32
|
+
|
|
33
|
+
export interface VouchConfig {
|
|
34
|
+
admin: PublicKey;
|
|
35
|
+
pendingAdmin: PublicKey | null;
|
|
36
|
+
paused: boolean;
|
|
37
|
+
treasury: PublicKey;
|
|
38
|
+
usdcMint: PublicKey;
|
|
39
|
+
tierThresholds: [BN, BN, BN, BN];
|
|
40
|
+
cooldownPeriod: BN;
|
|
41
|
+
stakeToTxRatio: number;
|
|
42
|
+
bump: number;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export interface AgentIdentity {
|
|
46
|
+
owner: PublicKey;
|
|
47
|
+
tier: { [key in AgentTier]?: {} };
|
|
48
|
+
capabilities: BN;
|
|
49
|
+
name: string;
|
|
50
|
+
serviceCategory: { [key in ServiceCategory]?: {} };
|
|
51
|
+
version: string;
|
|
52
|
+
agentCardUrl: string;
|
|
53
|
+
agentCardHash: number[];
|
|
54
|
+
status: { [key in AgentStatus]?: {} };
|
|
55
|
+
createdAt: BN;
|
|
56
|
+
updatedAt: BN;
|
|
57
|
+
bump: number;
|
|
58
|
+
reputationScore: number;
|
|
59
|
+
reputationUpdatedAt: BN;
|
|
60
|
+
reputationChangeToday: number;
|
|
61
|
+
reputationDayStart: BN;
|
|
62
|
+
tierEffectiveAt: BN;
|
|
63
|
+
suspendedBy: PublicKey | null;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export interface StakeAccount {
|
|
67
|
+
agent: PublicKey;
|
|
68
|
+
owner: PublicKey;
|
|
69
|
+
depositedAmount: BN;
|
|
70
|
+
lockedAmount: BN;
|
|
71
|
+
pendingWithdrawal: BN;
|
|
72
|
+
bump: number;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export interface WithdrawalRequest {
|
|
76
|
+
stakeAccount: PublicKey;
|
|
77
|
+
owner: PublicKey;
|
|
78
|
+
amount: BN;
|
|
79
|
+
unlockAt: BN;
|
|
80
|
+
createdAt: BN;
|
|
81
|
+
bump: number;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export interface PendingConfigChange {
|
|
85
|
+
proposer: PublicKey;
|
|
86
|
+
proposedAt: BN;
|
|
87
|
+
executableAt: BN;
|
|
88
|
+
newTierThresholds: [BN, BN, BN, BN] | null;
|
|
89
|
+
newCooldownPeriod: BN | null;
|
|
90
|
+
newTreasury: PublicKey | null;
|
|
91
|
+
newStakeToTxRatio: number | null;
|
|
92
|
+
bump: number;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export interface DeactivationRecord {
|
|
96
|
+
owner: PublicKey;
|
|
97
|
+
deactivatedAt: BN;
|
|
98
|
+
finalReputationScore: number;
|
|
99
|
+
bump: number;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export interface ReputationReporter {
|
|
103
|
+
authority: PublicKey;
|
|
104
|
+
registeredBy: PublicKey;
|
|
105
|
+
label: string;
|
|
106
|
+
weight: number;
|
|
107
|
+
totalReports: BN;
|
|
108
|
+
lastReportSlot: BN;
|
|
109
|
+
isActive: boolean;
|
|
110
|
+
bump: number;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// ── Helper for parsing Anchor enum variants ──
|
|
114
|
+
|
|
115
|
+
export function parseEnum<T extends string>(
|
|
116
|
+
enumObj: { [key: string]: {} | undefined } | null | undefined,
|
|
117
|
+
enumType: Record<string, T>
|
|
118
|
+
): T | null {
|
|
119
|
+
if (!enumObj) return null;
|
|
120
|
+
const objKey = Object.keys(enumObj)[0];
|
|
121
|
+
if (!objKey) return null;
|
|
122
|
+
const lowerKey = objKey.toLowerCase();
|
|
123
|
+
for (const [enumKey, enumValue] of Object.entries(enumType)) {
|
|
124
|
+
if (enumKey.toLowerCase() === lowerKey) {
|
|
125
|
+
return enumValue;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
return null;
|
|
129
|
+
}
|
package/src/vault.ts
ADDED
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
import { Program, AnchorProvider, BN } from "@coral-xyz/anchor";
|
|
2
|
+
import { PublicKey, SystemProgram } from "@solana/web3.js";
|
|
3
|
+
import { TOKEN_PROGRAM_ID, ASSOCIATED_TOKEN_PROGRAM_ID, getAssociatedTokenAddressSync } from "@solana/spl-token";
|
|
4
|
+
import { Kya } from "../../target/types/kya";
|
|
5
|
+
import { SEEDS, VOUCH_PROGRAM_ID } from "./constants";
|
|
6
|
+
import type { StakeAccount, WithdrawalRequest } from "./types";
|
|
7
|
+
|
|
8
|
+
export class VaultClient {
|
|
9
|
+
constructor(
|
|
10
|
+
public readonly program: Program<Kya>,
|
|
11
|
+
public readonly provider: AnchorProvider
|
|
12
|
+
) {}
|
|
13
|
+
|
|
14
|
+
// ── PDA derivation ──
|
|
15
|
+
|
|
16
|
+
static findConfigPda(
|
|
17
|
+
programId: PublicKey = VOUCH_PROGRAM_ID
|
|
18
|
+
): [PublicKey, number] {
|
|
19
|
+
return PublicKey.findProgramAddressSync([SEEDS.VOUCH_CONFIG], programId);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
static findStakePda(
|
|
23
|
+
agentPda: PublicKey,
|
|
24
|
+
programId: PublicKey = VOUCH_PROGRAM_ID
|
|
25
|
+
): [PublicKey, number] {
|
|
26
|
+
return PublicKey.findProgramAddressSync(
|
|
27
|
+
[SEEDS.STAKE, agentPda.toBuffer()],
|
|
28
|
+
programId
|
|
29
|
+
);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
static findWithdrawalPda(
|
|
33
|
+
stakeAccountPda: PublicKey,
|
|
34
|
+
programId: PublicKey = VOUCH_PROGRAM_ID
|
|
35
|
+
): [PublicKey, number] {
|
|
36
|
+
return PublicKey.findProgramAddressSync(
|
|
37
|
+
[SEEDS.WITHDRAWAL, stakeAccountPda.toBuffer()],
|
|
38
|
+
programId
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* V6-M04: Derive the canonical vault token account (ATA of config PDA for USDC mint).
|
|
44
|
+
* This is the only vault address accepted by the on-chain program.
|
|
45
|
+
*/
|
|
46
|
+
static findVaultTokenAccount(usdcMint: PublicKey, programId: PublicKey = VOUCH_PROGRAM_ID): PublicKey {
|
|
47
|
+
const [configPda] = VaultClient.findConfigPda(programId);
|
|
48
|
+
return getAssociatedTokenAddressSync(usdcMint, configPda, true);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// ── Instructions (agent owner / user operations) ──
|
|
52
|
+
|
|
53
|
+
async deposit(params: {
|
|
54
|
+
owner: PublicKey;
|
|
55
|
+
agentPda: PublicKey;
|
|
56
|
+
ownerTokenAccount: PublicKey;
|
|
57
|
+
vaultTokenAccount: PublicKey;
|
|
58
|
+
amount: BN | number;
|
|
59
|
+
}) {
|
|
60
|
+
const [configPda] = VaultClient.findConfigPda(this.program.programId);
|
|
61
|
+
const [stakePda] = VaultClient.findStakePda(
|
|
62
|
+
params.agentPda,
|
|
63
|
+
this.program.programId
|
|
64
|
+
);
|
|
65
|
+
|
|
66
|
+
return this.program.methods
|
|
67
|
+
.deposit(new BN(params.amount))
|
|
68
|
+
.accounts({
|
|
69
|
+
owner: params.owner,
|
|
70
|
+
config: configPda,
|
|
71
|
+
agent: params.agentPda,
|
|
72
|
+
stakeAccount: stakePda,
|
|
73
|
+
ownerTokenAccount: params.ownerTokenAccount,
|
|
74
|
+
vaultTokenAccount: params.vaultTokenAccount,
|
|
75
|
+
tokenProgram: TOKEN_PROGRAM_ID,
|
|
76
|
+
systemProgram: SystemProgram.programId,
|
|
77
|
+
} as any)
|
|
78
|
+
.rpc();
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
async requestWithdrawal(params: {
|
|
82
|
+
owner: PublicKey;
|
|
83
|
+
agentPda: PublicKey;
|
|
84
|
+
stakeAccountPda: PublicKey;
|
|
85
|
+
amount: BN | number;
|
|
86
|
+
}) {
|
|
87
|
+
const [configPda] = VaultClient.findConfigPda(this.program.programId);
|
|
88
|
+
const [withdrawalPda] = VaultClient.findWithdrawalPda(
|
|
89
|
+
params.stakeAccountPda,
|
|
90
|
+
this.program.programId
|
|
91
|
+
);
|
|
92
|
+
|
|
93
|
+
return this.program.methods
|
|
94
|
+
.requestWithdrawal(new BN(params.amount))
|
|
95
|
+
.accounts({
|
|
96
|
+
owner: params.owner,
|
|
97
|
+
config: configPda,
|
|
98
|
+
agent: params.agentPda,
|
|
99
|
+
stakeAccount: params.stakeAccountPda,
|
|
100
|
+
withdrawalRequest: withdrawalPda,
|
|
101
|
+
systemProgram: SystemProgram.programId,
|
|
102
|
+
} as any)
|
|
103
|
+
.rpc();
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
async completeWithdrawal(params: {
|
|
107
|
+
owner: PublicKey;
|
|
108
|
+
stakeAccountPda: PublicKey;
|
|
109
|
+
agentPda: PublicKey;
|
|
110
|
+
vaultTokenAccount: PublicKey;
|
|
111
|
+
ownerTokenAccount: PublicKey;
|
|
112
|
+
}) {
|
|
113
|
+
const [configPda] = VaultClient.findConfigPda(this.program.programId);
|
|
114
|
+
const [withdrawalPda] = VaultClient.findWithdrawalPda(
|
|
115
|
+
params.stakeAccountPda,
|
|
116
|
+
this.program.programId
|
|
117
|
+
);
|
|
118
|
+
|
|
119
|
+
return this.program.methods
|
|
120
|
+
.completeWithdrawal()
|
|
121
|
+
.accounts({
|
|
122
|
+
owner: params.owner,
|
|
123
|
+
config: configPda,
|
|
124
|
+
agent: params.agentPda,
|
|
125
|
+
stakeAccount: params.stakeAccountPda,
|
|
126
|
+
withdrawalRequest: withdrawalPda,
|
|
127
|
+
vaultTokenAccount: params.vaultTokenAccount,
|
|
128
|
+
ownerTokenAccount: params.ownerTokenAccount,
|
|
129
|
+
tokenProgram: TOKEN_PROGRAM_ID,
|
|
130
|
+
systemProgram: SystemProgram.programId,
|
|
131
|
+
} as any)
|
|
132
|
+
.rpc();
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
async cancelWithdrawal(params: {
|
|
136
|
+
owner: PublicKey;
|
|
137
|
+
agentPda: PublicKey;
|
|
138
|
+
stakeAccountPda: PublicKey;
|
|
139
|
+
}) {
|
|
140
|
+
const [configPda] = VaultClient.findConfigPda(this.program.programId);
|
|
141
|
+
const [withdrawalPda] = VaultClient.findWithdrawalPda(
|
|
142
|
+
params.stakeAccountPda,
|
|
143
|
+
this.program.programId
|
|
144
|
+
);
|
|
145
|
+
|
|
146
|
+
return this.program.methods
|
|
147
|
+
.cancelWithdrawal()
|
|
148
|
+
.accounts({
|
|
149
|
+
owner: params.owner,
|
|
150
|
+
config: configPda,
|
|
151
|
+
agent: params.agentPda,
|
|
152
|
+
stakeAccount: params.stakeAccountPda,
|
|
153
|
+
withdrawalRequest: withdrawalPda,
|
|
154
|
+
} as any)
|
|
155
|
+
.rpc();
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// ── Instructions (owner cleanup operations) ──
|
|
159
|
+
|
|
160
|
+
async closeStake(params: {
|
|
161
|
+
owner: PublicKey;
|
|
162
|
+
agentPda: PublicKey;
|
|
163
|
+
}) {
|
|
164
|
+
const [configPda] = VaultClient.findConfigPda(this.program.programId);
|
|
165
|
+
const [stakePda] = VaultClient.findStakePda(params.agentPda, this.program.programId);
|
|
166
|
+
|
|
167
|
+
return this.program.methods
|
|
168
|
+
.closeStake()
|
|
169
|
+
.accounts({
|
|
170
|
+
owner: params.owner,
|
|
171
|
+
config: configPda,
|
|
172
|
+
agent: params.agentPda,
|
|
173
|
+
stakeAccount: stakePda,
|
|
174
|
+
} as any)
|
|
175
|
+
.rpc();
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// ── Fetchers ──
|
|
179
|
+
|
|
180
|
+
async fetchConfig(): Promise<any> {
|
|
181
|
+
const [configPda] = VaultClient.findConfigPda(this.program.programId);
|
|
182
|
+
return this.program.account.vouchConfig.fetch(configPda) as Promise<any>;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
async fetchStakeAccount(stakePda: PublicKey): Promise<StakeAccount> {
|
|
186
|
+
return this.program.account.stakeAccount.fetch(stakePda) as Promise<any>;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
async fetchStakeByAgent(agentPda: PublicKey): Promise<StakeAccount> {
|
|
190
|
+
const [stakePda] = VaultClient.findStakePda(
|
|
191
|
+
agentPda,
|
|
192
|
+
this.program.programId
|
|
193
|
+
);
|
|
194
|
+
return this.fetchStakeAccount(stakePda);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
async fetchWithdrawalRequest(
|
|
198
|
+
stakeAccountPda: PublicKey
|
|
199
|
+
): Promise<WithdrawalRequest> {
|
|
200
|
+
const [withdrawalPda] = VaultClient.findWithdrawalPda(
|
|
201
|
+
stakeAccountPda,
|
|
202
|
+
this.program.programId
|
|
203
|
+
);
|
|
204
|
+
return this.program.account.withdrawalRequest.fetch(
|
|
205
|
+
withdrawalPda
|
|
206
|
+
) as Promise<any>;
|
|
207
|
+
}
|
|
208
|
+
}
|