veilioexchange 0.1.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +37 -0
- package/LICENSE +21 -21
- package/README.md +225 -113
- package/dist/cjs/auth.d.ts +15 -0
- package/dist/cjs/auth.d.ts.map +1 -1
- package/dist/cjs/auth.js +32 -0
- package/dist/cjs/auth.js.map +1 -1
- package/dist/cjs/deployments.js +2 -2
- package/dist/cjs/index.d.ts +260 -6
- package/dist/cjs/index.d.ts.map +1 -1
- package/dist/cjs/index.js +221 -62
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/servicesApi.d.ts +86 -0
- package/dist/cjs/servicesApi.d.ts.map +1 -0
- package/dist/cjs/servicesApi.js +177 -0
- package/dist/cjs/servicesApi.js.map +1 -0
- package/dist/cjs/solana/auction.d.ts +230 -0
- package/dist/cjs/solana/auction.d.ts.map +1 -0
- package/dist/cjs/solana/auction.js +546 -0
- package/dist/cjs/solana/auction.js.map +1 -0
- package/dist/cjs/solana/client.d.ts +100 -0
- package/dist/cjs/solana/client.d.ts.map +1 -0
- package/dist/cjs/solana/client.js +368 -0
- package/dist/cjs/solana/client.js.map +1 -0
- package/dist/cjs/solana/escrow.d.ts +193 -0
- package/dist/cjs/solana/escrow.d.ts.map +1 -0
- package/dist/cjs/solana/escrow.js +463 -0
- package/dist/cjs/solana/escrow.js.map +1 -0
- package/dist/cjs/solana/index.d.ts +9 -0
- package/dist/cjs/solana/index.d.ts.map +1 -0
- package/dist/cjs/solana/index.js +35 -0
- package/dist/cjs/solana/index.js.map +1 -0
- package/dist/cjs/solana/registry.d.ts +112 -0
- package/dist/cjs/solana/registry.d.ts.map +1 -0
- package/dist/cjs/solana/registry.js +305 -0
- package/dist/cjs/solana/registry.js.map +1 -0
- package/dist/esm/auth.d.ts +15 -0
- package/dist/esm/auth.d.ts.map +1 -1
- package/dist/esm/auth.js +28 -0
- package/dist/esm/auth.js.map +1 -1
- package/dist/esm/deployments.js +2 -2
- package/dist/esm/index.d.ts +260 -6
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +218 -61
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/servicesApi.d.ts +86 -0
- package/dist/esm/servicesApi.d.ts.map +1 -0
- package/dist/esm/servicesApi.js +174 -0
- package/dist/esm/servicesApi.js.map +1 -0
- package/dist/esm/solana/auction.d.ts +230 -0
- package/dist/esm/solana/auction.d.ts.map +1 -0
- package/dist/esm/solana/auction.js +523 -0
- package/dist/esm/solana/auction.js.map +1 -0
- package/dist/esm/solana/client.d.ts +100 -0
- package/dist/esm/solana/client.d.ts.map +1 -0
- package/dist/esm/solana/client.js +361 -0
- package/dist/esm/solana/client.js.map +1 -0
- package/dist/esm/solana/escrow.d.ts +193 -0
- package/dist/esm/solana/escrow.d.ts.map +1 -0
- package/dist/esm/solana/escrow.js +444 -0
- package/dist/esm/solana/escrow.js.map +1 -0
- package/dist/esm/solana/index.d.ts +9 -0
- package/dist/esm/solana/index.d.ts.map +1 -0
- package/dist/esm/solana/index.js +9 -0
- package/dist/esm/solana/index.js.map +1 -0
- package/dist/esm/solana/registry.d.ts +112 -0
- package/dist/esm/solana/registry.d.ts.map +1 -0
- package/dist/esm/solana/registry.js +289 -0
- package/dist/esm/solana/registry.js.map +1 -0
- package/package.json +82 -55
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* VEILIO Solana Services Escrow Client & Program Interface
|
|
3
|
+
*
|
|
4
|
+
* Implements client-side PDA derivation, Anchor instruction serialization,
|
|
5
|
+
* account deserialization, fee calculations, and transaction verification
|
|
6
|
+
* for the dedicated Solana Devnet VeilServiceEscrow program.
|
|
7
|
+
*/
|
|
8
|
+
import { type SolanaCompiledInstruction } from './registry.js';
|
|
9
|
+
export declare const ESCROW_SEED: Buffer<ArrayBuffer>;
|
|
10
|
+
export declare const VAULT_SEED: Buffer<ArrayBuffer>;
|
|
11
|
+
export declare const MAX_DELIVERABLE_REF_LEN = 200;
|
|
12
|
+
export declare const MAX_FEE_BPS = 500;
|
|
13
|
+
/** Global platform config PDA seed: [b"escrow_config"] (EscrowConfig account). */
|
|
14
|
+
export declare const ESCROW_CONFIG_SEED: Buffer<ArrayBuffer>;
|
|
15
|
+
/** 8 (discriminator) + 32 admin + 32 reviewer + 32 fee_recipient + 2 fee_basis_points + 1 bump */
|
|
16
|
+
export declare const ESCROW_CONFIG_ACCOUNT_SIZE = 107;
|
|
17
|
+
export declare const DEFAULT_SOLANA_SERVICE_ESCROW_PROGRAM_ID = "5Vj4y8BT74PDe5VwLuDp9agTR5ak4vtZdwxnBfRW3R8s";
|
|
18
|
+
export type SolanaServiceEscrowStatus = 'None' | 'Funded' | 'Delivered' | 'Released' | 'Refunded' | 'Disputed';
|
|
19
|
+
export declare const SOLANA_SERVICE_ESCROW_STATUS_MAP: Record<number, SolanaServiceEscrowStatus>;
|
|
20
|
+
export interface DecodedSolanaEscrowOrder {
|
|
21
|
+
buyer: string;
|
|
22
|
+
seller: string;
|
|
23
|
+
reviewer: string;
|
|
24
|
+
feeRecipient: string;
|
|
25
|
+
orderIdHex: string;
|
|
26
|
+
orderIdBytes: Uint8Array;
|
|
27
|
+
amountLamports: bigint;
|
|
28
|
+
amountSol: string;
|
|
29
|
+
feeBasisPoints: number;
|
|
30
|
+
deadline: number;
|
|
31
|
+
status: SolanaServiceEscrowStatus;
|
|
32
|
+
createdAt: number;
|
|
33
|
+
settledAt: number;
|
|
34
|
+
deliverableReference: string;
|
|
35
|
+
bump: number;
|
|
36
|
+
vaultBump: number;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Derives the EscrowOrder account PDA: [b"service_escrow", order_id]
|
|
40
|
+
*/
|
|
41
|
+
export declare function findEscrowOrderPda(orderId: string | Uint8Array, programId?: string): {
|
|
42
|
+
pda: string;
|
|
43
|
+
bump: number;
|
|
44
|
+
};
|
|
45
|
+
/**
|
|
46
|
+
* Derives the Vault account PDA holding SOL lamports: [b"service_vault", order_id]
|
|
47
|
+
*/
|
|
48
|
+
export declare function findVaultPda(orderId: string | Uint8Array, programId?: string): {
|
|
49
|
+
pda: string;
|
|
50
|
+
bump: number;
|
|
51
|
+
};
|
|
52
|
+
/**
|
|
53
|
+
* Derives the global EscrowConfig PDA: [b"escrow_config"]. Holds the platform reviewer, fee
|
|
54
|
+
* recipient and fee rate that the upgraded program snapshots into every new order.
|
|
55
|
+
*/
|
|
56
|
+
export declare function findEscrowConfigPda(programId?: string): {
|
|
57
|
+
pda: string;
|
|
58
|
+
bump: number;
|
|
59
|
+
};
|
|
60
|
+
export interface DecodedSolanaEscrowConfig {
|
|
61
|
+
admin: string;
|
|
62
|
+
reviewer: string;
|
|
63
|
+
feeRecipient: string;
|
|
64
|
+
feeBasisPoints: number;
|
|
65
|
+
bump: number;
|
|
66
|
+
}
|
|
67
|
+
/** Decodes the EscrowConfig account (admin, reviewer, fee_recipient, fee_basis_points u16, bump). */
|
|
68
|
+
export declare function decodeEscrowConfigAccount(buffer: Uint8Array | Buffer): DecodedSolanaEscrowConfig;
|
|
69
|
+
/**
|
|
70
|
+
* Encodes initialize_config(reviewer, fee_recipient, fee_basis_points). Only the program's
|
|
71
|
+
* upgrade authority (`admin`) can call it, once.
|
|
72
|
+
* accounts: [config (mut, pda), admin (signer, mut), program, program_data, system_program]
|
|
73
|
+
*/
|
|
74
|
+
export declare function createInitializeEscrowConfigInstruction(params: {
|
|
75
|
+
programId?: string;
|
|
76
|
+
admin: string;
|
|
77
|
+
reviewer: string;
|
|
78
|
+
feeRecipient: string;
|
|
79
|
+
feeBasisPoints: number;
|
|
80
|
+
}): SolanaCompiledInstruction;
|
|
81
|
+
/**
|
|
82
|
+
* Encodes update_config(reviewer, fee_recipient, fee_basis_points, new_admin). Signed by the
|
|
83
|
+
* current config admin; `newAdmin` defaults to `admin` (no hand-over).
|
|
84
|
+
* accounts: [config (mut, pda), admin (signer)]
|
|
85
|
+
*/
|
|
86
|
+
export declare function createUpdateEscrowConfigInstruction(params: {
|
|
87
|
+
programId?: string;
|
|
88
|
+
admin: string;
|
|
89
|
+
reviewer: string;
|
|
90
|
+
feeRecipient: string;
|
|
91
|
+
feeBasisPoints: number;
|
|
92
|
+
newAdmin?: string;
|
|
93
|
+
}): SolanaCompiledInstruction;
|
|
94
|
+
/**
|
|
95
|
+
* Encodes the deposit instruction:
|
|
96
|
+
* accounts: [escrow_order (mut, pda), vault (mut, pda), buyer (signer, mut), system_program, config]
|
|
97
|
+
*
|
|
98
|
+
* The trailing read-only `config` PDA is required by the upgraded program (which takes the
|
|
99
|
+
* reviewer / fee recipient / fee rate from it and ignores the `reviewer` / `feeRecipient`
|
|
100
|
+
* args). The pre-upgrade program ignores it as an Anchor remaining account.
|
|
101
|
+
*/
|
|
102
|
+
export declare function createDepositServiceOrderInstruction(params: {
|
|
103
|
+
programId?: string;
|
|
104
|
+
buyer: string;
|
|
105
|
+
seller: string;
|
|
106
|
+
reviewer: string;
|
|
107
|
+
feeRecipient: string;
|
|
108
|
+
orderId: string | Uint8Array;
|
|
109
|
+
amountLamports: bigint | number;
|
|
110
|
+
deadline: number;
|
|
111
|
+
}): SolanaCompiledInstruction;
|
|
112
|
+
/**
|
|
113
|
+
* Encodes the submit_delivery instruction:
|
|
114
|
+
* accounts: [escrow_order (mut), seller (signer)]
|
|
115
|
+
*/
|
|
116
|
+
export declare function createSubmitDeliveryInstruction(params: {
|
|
117
|
+
programId?: string;
|
|
118
|
+
seller: string;
|
|
119
|
+
orderId: string | Uint8Array;
|
|
120
|
+
deliverableReference: string;
|
|
121
|
+
}): SolanaCompiledInstruction;
|
|
122
|
+
/**
|
|
123
|
+
* Encodes the release_funds instruction:
|
|
124
|
+
* accounts: [escrow_order (mut), vault (mut), buyer (signer), seller (mut), fee_recipient (mut)]
|
|
125
|
+
*/
|
|
126
|
+
export declare function createReleaseFundsInstruction(params: {
|
|
127
|
+
programId?: string;
|
|
128
|
+
buyer: string;
|
|
129
|
+
seller: string;
|
|
130
|
+
feeRecipient: string;
|
|
131
|
+
orderId: string | Uint8Array;
|
|
132
|
+
}): SolanaCompiledInstruction;
|
|
133
|
+
/**
|
|
134
|
+
* Encodes the cancel_or_refund instruction:
|
|
135
|
+
* accounts: [escrow_order (mut), vault (mut), caller (signer), buyer (mut), system_program]
|
|
136
|
+
*/
|
|
137
|
+
export declare function createCancelOrRefundInstruction(params: {
|
|
138
|
+
programId?: string;
|
|
139
|
+
caller: string;
|
|
140
|
+
buyer: string;
|
|
141
|
+
orderId: string | Uint8Array;
|
|
142
|
+
reason: string;
|
|
143
|
+
}): SolanaCompiledInstruction;
|
|
144
|
+
/**
|
|
145
|
+
* Encodes the dispute instruction:
|
|
146
|
+
* accounts: [escrow_order (mut), caller (signer)]
|
|
147
|
+
*/
|
|
148
|
+
export declare function createDisputeOrderInstruction(params: {
|
|
149
|
+
programId?: string;
|
|
150
|
+
caller: string;
|
|
151
|
+
orderId: string | Uint8Array;
|
|
152
|
+
reason: string;
|
|
153
|
+
}): SolanaCompiledInstruction;
|
|
154
|
+
/**
|
|
155
|
+
* Encodes the resolve_dispute instruction:
|
|
156
|
+
* accounts: [escrow_order (mut), vault (mut), reviewer (signer), buyer (mut), seller (mut),
|
|
157
|
+
* fee_recipient (mut), system_program, config]
|
|
158
|
+
* The trailing read-only `config` PDA lets the upgraded program authorize the CURRENT platform
|
|
159
|
+
* reviewer; the pre-upgrade program ignores it as an Anchor remaining account.
|
|
160
|
+
*/
|
|
161
|
+
export declare function createResolveDisputeInstruction(params: {
|
|
162
|
+
programId?: string;
|
|
163
|
+
reviewer: string;
|
|
164
|
+
buyer: string;
|
|
165
|
+
seller: string;
|
|
166
|
+
feeRecipient: string;
|
|
167
|
+
orderId: string | Uint8Array;
|
|
168
|
+
splitToBuyerPercent: number;
|
|
169
|
+
}): SolanaCompiledInstruction;
|
|
170
|
+
/**
|
|
171
|
+
* Decodes serialized EscrowOrder account buffer.
|
|
172
|
+
*/
|
|
173
|
+
export declare function decodeEscrowOrderAccount(buffer: Uint8Array | Buffer): DecodedSolanaEscrowOrder;
|
|
174
|
+
/**
|
|
175
|
+
* Calculates exact platform fee and payouts for Solana lamports.
|
|
176
|
+
* Strict parity with EVM: 500 bps (5%) platform fee deducted from seller gross award.
|
|
177
|
+
* Buyer refunds are 100% fee-free.
|
|
178
|
+
*/
|
|
179
|
+
export declare function calculateSolanaServicePayouts(totalLamports: bigint | number, splitToBuyerPercent?: number, feeBps?: number): {
|
|
180
|
+
buyerRefundLamports: bigint;
|
|
181
|
+
sellerGrossLamports: bigint;
|
|
182
|
+
platformFeeLamports: bigint;
|
|
183
|
+
sellerNetPayoutLamports: bigint;
|
|
184
|
+
};
|
|
185
|
+
/**
|
|
186
|
+
* Lossless conversion of lamports to a high-precision SOL string without floating-point errors.
|
|
187
|
+
*/
|
|
188
|
+
export declare function formatLamportsToSol(lamports: bigint | number): string;
|
|
189
|
+
/**
|
|
190
|
+
* Lossless conversion of SOL string to lamports bigint without floating-point inaccuracies.
|
|
191
|
+
*/
|
|
192
|
+
export declare function parseSolToLamports(sol: string): bigint;
|
|
193
|
+
//# sourceMappingURL=escrow.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"escrow.d.ts","sourceRoot":"","sources":["../../../src/solana/escrow.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,EASL,KAAK,yBAAyB,EAC/B,MAAM,eAAe,CAAC;AAGvB,eAAO,MAAM,WAAW,qBAAgC,CAAC;AACzD,eAAO,MAAM,UAAU,qBAA+B,CAAC;AACvD,eAAO,MAAM,uBAAuB,MAAM,CAAC;AAC3C,eAAO,MAAM,WAAW,MAAM,CAAC;AAC/B,kFAAkF;AAClF,eAAO,MAAM,kBAAkB,qBAA+B,CAAC;AAC/D,kGAAkG;AAClG,eAAO,MAAM,0BAA0B,MAAM,CAAC;AAG9C,eAAO,MAAM,wCAAwC,iDACL,CAAC;AAEjD,MAAM,MAAM,yBAAyB,GACjC,MAAM,GACN,QAAQ,GACR,WAAW,GACX,UAAU,GACV,UAAU,GACV,UAAU,CAAC;AAEf,eAAO,MAAM,gCAAgC,EAAE,MAAM,CAAC,MAAM,EAAE,yBAAyB,CAOtF,CAAC;AAEF,MAAM,WAAW,wBAAwB;IACvC,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,UAAU,CAAC;IACzB,cAAc,EAAE,MAAM,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,MAAM,CAAC;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,yBAAyB,CAAC;IAClC,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,oBAAoB,EAAE,MAAM,CAAC;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,MAAM,GAAG,UAAU,EAC5B,SAAS,GAAE,MAAiD,GAC3D;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAG/B;AAED;;GAEG;AACH,wBAAgB,YAAY,CAC1B,OAAO,EAAE,MAAM,GAAG,UAAU,EAC5B,SAAS,GAAE,MAAiD,GAC3D;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAG/B;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CACjC,SAAS,GAAE,MAAiD,GAC3D;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAE/B;AAED,MAAM,WAAW,yBAAyB;IACxC,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,MAAM,CAAC;IACvB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,qGAAqG;AACrG,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,GAAG,yBAAyB,CAmBhG;AAmBD;;;;GAIG;AACH,wBAAgB,uCAAuC,CAAC,MAAM,EAAE;IAC9D,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,MAAM,CAAC;CACxB,GAAG,yBAAyB,CAoB5B;AAED;;;;GAIG;AACH,wBAAgB,mCAAmC,CAAC,MAAM,EAAE;IAC1D,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,GAAG,yBAAyB,CAmB5B;AAED;;;;;;;GAOG;AACH,wBAAgB,oCAAoC,CAAC,MAAM,EAAE;IAC3D,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,MAAM,GAAG,UAAU,CAAC;IAC7B,cAAc,EAAE,MAAM,GAAG,MAAM,CAAC;IAChC,QAAQ,EAAE,MAAM,CAAC;CAClB,GAAG,yBAAyB,CA8C5B;AAED;;;GAGG;AACH,wBAAgB,+BAA+B,CAAC,MAAM,EAAE;IACtD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,GAAG,UAAU,CAAC;IAC7B,oBAAoB,EAAE,MAAM,CAAC;CAC9B,GAAG,yBAAyB,CA4B5B;AAED;;;GAGG;AACH,wBAAgB,6BAA6B,CAAC,MAAM,EAAE;IACpD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,MAAM,GAAG,UAAU,CAAC;CAC9B,GAAG,yBAAyB,CAsB5B;AAED;;;GAGG;AACH,wBAAgB,+BAA+B,CAAC,MAAM,EAAE;IACtD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,GAAG,UAAU,CAAC;IAC7B,MAAM,EAAE,MAAM,CAAC;CAChB,GAAG,yBAAyB,CA0B5B;AAED;;;GAGG;AACH,wBAAgB,6BAA6B,CAAC,MAAM,EAAE;IACpD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,GAAG,UAAU,CAAC;IAC7B,MAAM,EAAE,MAAM,CAAC;CAChB,GAAG,yBAAyB,CAsB5B;AAED;;;;;;GAMG;AACH,wBAAgB,+BAA+B,CAAC,MAAM,EAAE;IACtD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,MAAM,GAAG,UAAU,CAAC;IAC7B,mBAAmB,EAAE,MAAM,CAAC;CAC7B,GAAG,yBAAyB,CA+B5B;AAED;;GAEG;AACH,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,GAAG,wBAAwB,CAiF9F;AAED;;;;GAIG;AACH,wBAAgB,6BAA6B,CAC3C,aAAa,EAAE,MAAM,GAAG,MAAM,EAC9B,mBAAmB,GAAE,MAAU,EAC/B,MAAM,GAAE,MAAY,GACnB;IACD,mBAAmB,EAAE,MAAM,CAAC;IAC5B,mBAAmB,EAAE,MAAM,CAAC;IAC5B,mBAAmB,EAAE,MAAM,CAAC;IAC5B,uBAAuB,EAAE,MAAM,CAAC;CACjC,CAiBA;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,CAWrE;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CActD"}
|
|
@@ -0,0 +1,463 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* VEILIO Solana Services Escrow Client & Program Interface
|
|
4
|
+
*
|
|
5
|
+
* Implements client-side PDA derivation, Anchor instruction serialization,
|
|
6
|
+
* account deserialization, fee calculations, and transaction verification
|
|
7
|
+
* for the dedicated Solana Devnet VeilServiceEscrow program.
|
|
8
|
+
*/
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.SOLANA_SERVICE_ESCROW_STATUS_MAP = exports.DEFAULT_SOLANA_SERVICE_ESCROW_PROGRAM_ID = exports.ESCROW_CONFIG_ACCOUNT_SIZE = exports.ESCROW_CONFIG_SEED = exports.MAX_FEE_BPS = exports.MAX_DELIVERABLE_REF_LEN = exports.VAULT_SEED = exports.ESCROW_SEED = void 0;
|
|
11
|
+
exports.findEscrowOrderPda = findEscrowOrderPda;
|
|
12
|
+
exports.findVaultPda = findVaultPda;
|
|
13
|
+
exports.findEscrowConfigPda = findEscrowConfigPda;
|
|
14
|
+
exports.decodeEscrowConfigAccount = decodeEscrowConfigAccount;
|
|
15
|
+
exports.createInitializeEscrowConfigInstruction = createInitializeEscrowConfigInstruction;
|
|
16
|
+
exports.createUpdateEscrowConfigInstruction = createUpdateEscrowConfigInstruction;
|
|
17
|
+
exports.createDepositServiceOrderInstruction = createDepositServiceOrderInstruction;
|
|
18
|
+
exports.createSubmitDeliveryInstruction = createSubmitDeliveryInstruction;
|
|
19
|
+
exports.createReleaseFundsInstruction = createReleaseFundsInstruction;
|
|
20
|
+
exports.createCancelOrRefundInstruction = createCancelOrRefundInstruction;
|
|
21
|
+
exports.createDisputeOrderInstruction = createDisputeOrderInstruction;
|
|
22
|
+
exports.createResolveDisputeInstruction = createResolveDisputeInstruction;
|
|
23
|
+
exports.decodeEscrowOrderAccount = decodeEscrowOrderAccount;
|
|
24
|
+
exports.calculateSolanaServicePayouts = calculateSolanaServicePayouts;
|
|
25
|
+
exports.formatLamportsToSol = formatLamportsToSol;
|
|
26
|
+
exports.parseSolToLamports = parseSolToLamports;
|
|
27
|
+
const registry_js_1 = require("./registry.js");
|
|
28
|
+
// Canonical Seeds & Limits
|
|
29
|
+
exports.ESCROW_SEED = Buffer.from('service_escrow');
|
|
30
|
+
exports.VAULT_SEED = Buffer.from('service_vault');
|
|
31
|
+
exports.MAX_DELIVERABLE_REF_LEN = 200;
|
|
32
|
+
exports.MAX_FEE_BPS = 500; // 5%
|
|
33
|
+
/** Global platform config PDA seed: [b"escrow_config"] (EscrowConfig account). */
|
|
34
|
+
exports.ESCROW_CONFIG_SEED = Buffer.from('escrow_config');
|
|
35
|
+
/** 8 (discriminator) + 32 admin + 32 reviewer + 32 fee_recipient + 2 fee_basis_points + 1 bump */
|
|
36
|
+
exports.ESCROW_CONFIG_ACCOUNT_SIZE = 107;
|
|
37
|
+
// Default Program ID (can be overridden via NEXT_PUBLIC_SOLANA_SERVICE_ESCROW_PROGRAM_ID)
|
|
38
|
+
exports.DEFAULT_SOLANA_SERVICE_ESCROW_PROGRAM_ID = '5Vj4y8BT74PDe5VwLuDp9agTR5ak4vtZdwxnBfRW3R8s';
|
|
39
|
+
exports.SOLANA_SERVICE_ESCROW_STATUS_MAP = {
|
|
40
|
+
0: 'None',
|
|
41
|
+
1: 'Funded',
|
|
42
|
+
2: 'Delivered',
|
|
43
|
+
3: 'Released',
|
|
44
|
+
4: 'Refunded',
|
|
45
|
+
5: 'Disputed',
|
|
46
|
+
};
|
|
47
|
+
/**
|
|
48
|
+
* Derives the EscrowOrder account PDA: [b"service_escrow", order_id]
|
|
49
|
+
*/
|
|
50
|
+
function findEscrowOrderPda(orderId, programId = exports.DEFAULT_SOLANA_SERVICE_ESCROW_PROGRAM_ID) {
|
|
51
|
+
const orderIdBytes = (0, registry_js_1.normalizeBytes32)(orderId);
|
|
52
|
+
return (0, registry_js_1.findProgramDerivedAddress)([exports.ESCROW_SEED, orderIdBytes], programId);
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Derives the Vault account PDA holding SOL lamports: [b"service_vault", order_id]
|
|
56
|
+
*/
|
|
57
|
+
function findVaultPda(orderId, programId = exports.DEFAULT_SOLANA_SERVICE_ESCROW_PROGRAM_ID) {
|
|
58
|
+
const orderIdBytes = (0, registry_js_1.normalizeBytes32)(orderId);
|
|
59
|
+
return (0, registry_js_1.findProgramDerivedAddress)([exports.VAULT_SEED, orderIdBytes], programId);
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Derives the global EscrowConfig PDA: [b"escrow_config"]. Holds the platform reviewer, fee
|
|
63
|
+
* recipient and fee rate that the upgraded program snapshots into every new order.
|
|
64
|
+
*/
|
|
65
|
+
function findEscrowConfigPda(programId = exports.DEFAULT_SOLANA_SERVICE_ESCROW_PROGRAM_ID) {
|
|
66
|
+
return (0, registry_js_1.findProgramDerivedAddress)([exports.ESCROW_CONFIG_SEED], programId);
|
|
67
|
+
}
|
|
68
|
+
/** Decodes the EscrowConfig account (admin, reviewer, fee_recipient, fee_basis_points u16, bump). */
|
|
69
|
+
function decodeEscrowConfigAccount(buffer) {
|
|
70
|
+
const buf = Buffer.from(buffer);
|
|
71
|
+
if (buf.length < exports.ESCROW_CONFIG_ACCOUNT_SIZE) {
|
|
72
|
+
throw new Error(`Truncated EscrowConfig buffer length: ${buf.length}`);
|
|
73
|
+
}
|
|
74
|
+
if (!buf.subarray(0, 8).equals((0, registry_js_1.getAnchorDiscriminator)('account', 'EscrowConfig'))) {
|
|
75
|
+
throw new Error('Invalid account discriminator for EscrowConfig');
|
|
76
|
+
}
|
|
77
|
+
let offset = 8;
|
|
78
|
+
const admin = (0, registry_js_1.encodeBase58)(buf.subarray(offset, offset + 32));
|
|
79
|
+
offset += 32;
|
|
80
|
+
const reviewer = (0, registry_js_1.encodeBase58)(buf.subarray(offset, offset + 32));
|
|
81
|
+
offset += 32;
|
|
82
|
+
const feeRecipient = (0, registry_js_1.encodeBase58)(buf.subarray(offset, offset + 32));
|
|
83
|
+
offset += 32;
|
|
84
|
+
const feeBasisPoints = buf.readUInt16LE(offset);
|
|
85
|
+
offset += 2;
|
|
86
|
+
const bump = buf.readUInt8(offset);
|
|
87
|
+
return { admin, reviewer, feeRecipient, feeBasisPoints, bump };
|
|
88
|
+
}
|
|
89
|
+
function validateEscrowConfigParams(params) {
|
|
90
|
+
const reviewerBytes = (0, registry_js_1.decodePubkey32)(params.reviewer, 'reviewer');
|
|
91
|
+
const feeRecipientBytes = (0, registry_js_1.decodePubkey32)(params.feeRecipient, 'fee recipient');
|
|
92
|
+
if (reviewerBytes.every((b) => b === 0))
|
|
93
|
+
throw new Error('Reviewer cannot be the default (all-zero) public key');
|
|
94
|
+
if (feeRecipientBytes.every((b) => b === 0))
|
|
95
|
+
throw new Error('Fee recipient cannot be the default (all-zero) public key');
|
|
96
|
+
if (!Number.isInteger(params.feeBasisPoints) || params.feeBasisPoints < 0 || params.feeBasisPoints > exports.MAX_FEE_BPS) {
|
|
97
|
+
throw new Error(`Fee basis points must be an integer between 0 and ${exports.MAX_FEE_BPS}`);
|
|
98
|
+
}
|
|
99
|
+
const feeBuf = Buffer.alloc(2);
|
|
100
|
+
feeBuf.writeUInt16LE(params.feeBasisPoints);
|
|
101
|
+
return { reviewerBytes, feeRecipientBytes, feeBuf };
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Encodes initialize_config(reviewer, fee_recipient, fee_basis_points). Only the program's
|
|
105
|
+
* upgrade authority (`admin`) can call it, once.
|
|
106
|
+
* accounts: [config (mut, pda), admin (signer, mut), program, program_data, system_program]
|
|
107
|
+
*/
|
|
108
|
+
function createInitializeEscrowConfigInstruction(params) {
|
|
109
|
+
const programId = params.programId || exports.DEFAULT_SOLANA_SERVICE_ESCROW_PROGRAM_ID;
|
|
110
|
+
const { reviewerBytes, feeRecipientBytes, feeBuf } = validateEscrowConfigParams(params);
|
|
111
|
+
const { pda: configPda } = findEscrowConfigPda(programId);
|
|
112
|
+
const { pda: programDataPda } = (0, registry_js_1.findProgramDataPda)(programId);
|
|
113
|
+
const data = Buffer.concat([
|
|
114
|
+
(0, registry_js_1.getAnchorDiscriminator)('global', 'initialize_config'),
|
|
115
|
+
reviewerBytes,
|
|
116
|
+
feeRecipientBytes,
|
|
117
|
+
feeBuf,
|
|
118
|
+
]);
|
|
119
|
+
const keys = [
|
|
120
|
+
{ pubkey: configPda, isSigner: false, isWritable: true },
|
|
121
|
+
{ pubkey: params.admin, isSigner: true, isWritable: true },
|
|
122
|
+
{ pubkey: programId, isSigner: false, isWritable: false },
|
|
123
|
+
{ pubkey: programDataPda, isSigner: false, isWritable: false },
|
|
124
|
+
{ pubkey: registry_js_1.SYSTEM_PROGRAM_ID, isSigner: false, isWritable: false },
|
|
125
|
+
];
|
|
126
|
+
return { programId, accounts: keys, keys, data };
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Encodes update_config(reviewer, fee_recipient, fee_basis_points, new_admin). Signed by the
|
|
130
|
+
* current config admin; `newAdmin` defaults to `admin` (no hand-over).
|
|
131
|
+
* accounts: [config (mut, pda), admin (signer)]
|
|
132
|
+
*/
|
|
133
|
+
function createUpdateEscrowConfigInstruction(params) {
|
|
134
|
+
const programId = params.programId || exports.DEFAULT_SOLANA_SERVICE_ESCROW_PROGRAM_ID;
|
|
135
|
+
const { reviewerBytes, feeRecipientBytes, feeBuf } = validateEscrowConfigParams(params);
|
|
136
|
+
const newAdminBytes = (0, registry_js_1.decodePubkey32)(params.newAdmin || params.admin, 'new admin');
|
|
137
|
+
if (newAdminBytes.every((b) => b === 0))
|
|
138
|
+
throw new Error('New admin cannot be the default (all-zero) public key');
|
|
139
|
+
const { pda: configPda } = findEscrowConfigPda(programId);
|
|
140
|
+
const data = Buffer.concat([
|
|
141
|
+
(0, registry_js_1.getAnchorDiscriminator)('global', 'update_config'),
|
|
142
|
+
reviewerBytes,
|
|
143
|
+
feeRecipientBytes,
|
|
144
|
+
feeBuf,
|
|
145
|
+
newAdminBytes,
|
|
146
|
+
]);
|
|
147
|
+
const keys = [
|
|
148
|
+
{ pubkey: configPda, isSigner: false, isWritable: true },
|
|
149
|
+
{ pubkey: params.admin, isSigner: true, isWritable: false },
|
|
150
|
+
];
|
|
151
|
+
return { programId, accounts: keys, keys, data };
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Encodes the deposit instruction:
|
|
155
|
+
* accounts: [escrow_order (mut, pda), vault (mut, pda), buyer (signer, mut), system_program, config]
|
|
156
|
+
*
|
|
157
|
+
* The trailing read-only `config` PDA is required by the upgraded program (which takes the
|
|
158
|
+
* reviewer / fee recipient / fee rate from it and ignores the `reviewer` / `feeRecipient`
|
|
159
|
+
* args). The pre-upgrade program ignores it as an Anchor remaining account.
|
|
160
|
+
*/
|
|
161
|
+
function createDepositServiceOrderInstruction(params) {
|
|
162
|
+
const programId = params.programId || exports.DEFAULT_SOLANA_SERVICE_ESCROW_PROGRAM_ID;
|
|
163
|
+
const orderIdBytes = (0, registry_js_1.normalizeBytes32)(params.orderId);
|
|
164
|
+
const { pda: escrowOrderPda } = findEscrowOrderPda(orderIdBytes, programId);
|
|
165
|
+
const { pda: vaultPda } = findVaultPda(orderIdBytes, programId);
|
|
166
|
+
const amount = BigInt(params.amountLamports);
|
|
167
|
+
if (amount <= 0n)
|
|
168
|
+
throw new Error('Deposit amount must be greater than zero');
|
|
169
|
+
if (params.seller === params.buyer)
|
|
170
|
+
throw new Error('Buyer cannot be seller');
|
|
171
|
+
const discriminator = (0, registry_js_1.getAnchorDiscriminator)('global', 'deposit');
|
|
172
|
+
const sellerBytes = Buffer.from((0, registry_js_1.decodeBase58)(params.seller));
|
|
173
|
+
const reviewerBytes = Buffer.from((0, registry_js_1.decodeBase58)(params.reviewer));
|
|
174
|
+
const feeRecipientBytes = Buffer.from((0, registry_js_1.decodeBase58)(params.feeRecipient));
|
|
175
|
+
const amountBuf = Buffer.alloc(8);
|
|
176
|
+
amountBuf.writeBigUInt64LE(amount);
|
|
177
|
+
const deadlineBuf = Buffer.alloc(8);
|
|
178
|
+
deadlineBuf.writeBigInt64LE(BigInt(params.deadline));
|
|
179
|
+
const data = Buffer.concat([
|
|
180
|
+
discriminator,
|
|
181
|
+
orderIdBytes,
|
|
182
|
+
sellerBytes,
|
|
183
|
+
reviewerBytes,
|
|
184
|
+
feeRecipientBytes,
|
|
185
|
+
amountBuf,
|
|
186
|
+
deadlineBuf,
|
|
187
|
+
]);
|
|
188
|
+
const keys = [
|
|
189
|
+
{ pubkey: escrowOrderPda, isSigner: false, isWritable: true },
|
|
190
|
+
{ pubkey: vaultPda, isSigner: false, isWritable: true },
|
|
191
|
+
{ pubkey: params.buyer, isSigner: true, isWritable: true },
|
|
192
|
+
{ pubkey: registry_js_1.SYSTEM_PROGRAM_ID, isSigner: false, isWritable: false },
|
|
193
|
+
{ pubkey: findEscrowConfigPda(programId).pda, isSigner: false, isWritable: false },
|
|
194
|
+
];
|
|
195
|
+
return {
|
|
196
|
+
programId,
|
|
197
|
+
accounts: keys,
|
|
198
|
+
keys,
|
|
199
|
+
data: Buffer.from(data),
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* Encodes the submit_delivery instruction:
|
|
204
|
+
* accounts: [escrow_order (mut), seller (signer)]
|
|
205
|
+
*/
|
|
206
|
+
function createSubmitDeliveryInstruction(params) {
|
|
207
|
+
const programId = params.programId || exports.DEFAULT_SOLANA_SERVICE_ESCROW_PROGRAM_ID;
|
|
208
|
+
const orderIdBytes = (0, registry_js_1.normalizeBytes32)(params.orderId);
|
|
209
|
+
const { pda: escrowOrderPda } = findEscrowOrderPda(orderIdBytes, programId);
|
|
210
|
+
const refStr = params.deliverableReference.trim();
|
|
211
|
+
if (!refStr)
|
|
212
|
+
throw new Error('Deliverable reference cannot be empty');
|
|
213
|
+
const refBuf = Buffer.from(refStr, 'utf8');
|
|
214
|
+
if (refBuf.length > exports.MAX_DELIVERABLE_REF_LEN) {
|
|
215
|
+
throw new Error(`Deliverable reference exceeds ${exports.MAX_DELIVERABLE_REF_LEN} bytes`);
|
|
216
|
+
}
|
|
217
|
+
const discriminator = (0, registry_js_1.getAnchorDiscriminator)('global', 'submit_delivery');
|
|
218
|
+
const lenBuf = Buffer.alloc(4);
|
|
219
|
+
lenBuf.writeUInt32LE(refBuf.length);
|
|
220
|
+
const data = Buffer.concat([discriminator, lenBuf, refBuf]);
|
|
221
|
+
const keys = [
|
|
222
|
+
{ pubkey: escrowOrderPda, isSigner: false, isWritable: true },
|
|
223
|
+
{ pubkey: params.seller, isSigner: true, isWritable: false },
|
|
224
|
+
];
|
|
225
|
+
return {
|
|
226
|
+
programId,
|
|
227
|
+
accounts: keys,
|
|
228
|
+
keys,
|
|
229
|
+
data: Buffer.from(data),
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
233
|
+
* Encodes the release_funds instruction:
|
|
234
|
+
* accounts: [escrow_order (mut), vault (mut), buyer (signer), seller (mut), fee_recipient (mut)]
|
|
235
|
+
*/
|
|
236
|
+
function createReleaseFundsInstruction(params) {
|
|
237
|
+
const programId = params.programId || exports.DEFAULT_SOLANA_SERVICE_ESCROW_PROGRAM_ID;
|
|
238
|
+
const orderIdBytes = (0, registry_js_1.normalizeBytes32)(params.orderId);
|
|
239
|
+
const { pda: escrowOrderPda } = findEscrowOrderPda(orderIdBytes, programId);
|
|
240
|
+
const { pda: vaultPda } = findVaultPda(orderIdBytes, programId);
|
|
241
|
+
const discriminator = (0, registry_js_1.getAnchorDiscriminator)('global', 'release_funds');
|
|
242
|
+
const keys = [
|
|
243
|
+
{ pubkey: escrowOrderPda, isSigner: false, isWritable: true },
|
|
244
|
+
{ pubkey: vaultPda, isSigner: false, isWritable: true },
|
|
245
|
+
{ pubkey: params.buyer, isSigner: true, isWritable: false },
|
|
246
|
+
{ pubkey: params.seller, isSigner: false, isWritable: true },
|
|
247
|
+
{ pubkey: params.feeRecipient, isSigner: false, isWritable: true },
|
|
248
|
+
{ pubkey: registry_js_1.SYSTEM_PROGRAM_ID, isSigner: false, isWritable: false },
|
|
249
|
+
];
|
|
250
|
+
return {
|
|
251
|
+
programId,
|
|
252
|
+
accounts: keys,
|
|
253
|
+
keys,
|
|
254
|
+
data: Buffer.from(discriminator),
|
|
255
|
+
};
|
|
256
|
+
}
|
|
257
|
+
/**
|
|
258
|
+
* Encodes the cancel_or_refund instruction:
|
|
259
|
+
* accounts: [escrow_order (mut), vault (mut), caller (signer), buyer (mut), system_program]
|
|
260
|
+
*/
|
|
261
|
+
function createCancelOrRefundInstruction(params) {
|
|
262
|
+
const programId = params.programId || exports.DEFAULT_SOLANA_SERVICE_ESCROW_PROGRAM_ID;
|
|
263
|
+
const orderIdBytes = (0, registry_js_1.normalizeBytes32)(params.orderId);
|
|
264
|
+
const { pda: escrowOrderPda } = findEscrowOrderPda(orderIdBytes, programId);
|
|
265
|
+
const { pda: vaultPda } = findVaultPda(orderIdBytes, programId);
|
|
266
|
+
const discriminator = (0, registry_js_1.getAnchorDiscriminator)('global', 'cancel_or_refund');
|
|
267
|
+
const reasonBuf = Buffer.from(params.reason.trim() || 'Order cancelled', 'utf8');
|
|
268
|
+
const lenBuf = Buffer.alloc(4);
|
|
269
|
+
lenBuf.writeUInt32LE(reasonBuf.length);
|
|
270
|
+
const data = Buffer.concat([discriminator, lenBuf, reasonBuf]);
|
|
271
|
+
const keys = [
|
|
272
|
+
{ pubkey: escrowOrderPda, isSigner: false, isWritable: true },
|
|
273
|
+
{ pubkey: vaultPda, isSigner: false, isWritable: true },
|
|
274
|
+
{ pubkey: params.caller, isSigner: true, isWritable: false },
|
|
275
|
+
{ pubkey: params.buyer, isSigner: false, isWritable: true },
|
|
276
|
+
{ pubkey: registry_js_1.SYSTEM_PROGRAM_ID, isSigner: false, isWritable: false },
|
|
277
|
+
];
|
|
278
|
+
return {
|
|
279
|
+
programId,
|
|
280
|
+
accounts: keys,
|
|
281
|
+
keys,
|
|
282
|
+
data: Buffer.from(data),
|
|
283
|
+
};
|
|
284
|
+
}
|
|
285
|
+
/**
|
|
286
|
+
* Encodes the dispute instruction:
|
|
287
|
+
* accounts: [escrow_order (mut), caller (signer)]
|
|
288
|
+
*/
|
|
289
|
+
function createDisputeOrderInstruction(params) {
|
|
290
|
+
const programId = params.programId || exports.DEFAULT_SOLANA_SERVICE_ESCROW_PROGRAM_ID;
|
|
291
|
+
const orderIdBytes = (0, registry_js_1.normalizeBytes32)(params.orderId);
|
|
292
|
+
const { pda: escrowOrderPda } = findEscrowOrderPda(orderIdBytes, programId);
|
|
293
|
+
const discriminator = (0, registry_js_1.getAnchorDiscriminator)('global', 'dispute');
|
|
294
|
+
const reasonBuf = Buffer.from(params.reason.trim() || 'Dispute opened', 'utf8');
|
|
295
|
+
const lenBuf = Buffer.alloc(4);
|
|
296
|
+
lenBuf.writeUInt32LE(reasonBuf.length);
|
|
297
|
+
const data = Buffer.concat([discriminator, lenBuf, reasonBuf]);
|
|
298
|
+
const keys = [
|
|
299
|
+
{ pubkey: escrowOrderPda, isSigner: false, isWritable: true },
|
|
300
|
+
{ pubkey: params.caller, isSigner: true, isWritable: false },
|
|
301
|
+
];
|
|
302
|
+
return {
|
|
303
|
+
programId,
|
|
304
|
+
accounts: keys,
|
|
305
|
+
keys,
|
|
306
|
+
data: Buffer.from(data),
|
|
307
|
+
};
|
|
308
|
+
}
|
|
309
|
+
/**
|
|
310
|
+
* Encodes the resolve_dispute instruction:
|
|
311
|
+
* accounts: [escrow_order (mut), vault (mut), reviewer (signer), buyer (mut), seller (mut),
|
|
312
|
+
* fee_recipient (mut), system_program, config]
|
|
313
|
+
* The trailing read-only `config` PDA lets the upgraded program authorize the CURRENT platform
|
|
314
|
+
* reviewer; the pre-upgrade program ignores it as an Anchor remaining account.
|
|
315
|
+
*/
|
|
316
|
+
function createResolveDisputeInstruction(params) {
|
|
317
|
+
const programId = params.programId || exports.DEFAULT_SOLANA_SERVICE_ESCROW_PROGRAM_ID;
|
|
318
|
+
const orderIdBytes = (0, registry_js_1.normalizeBytes32)(params.orderId);
|
|
319
|
+
const { pda: escrowOrderPda } = findEscrowOrderPda(orderIdBytes, programId);
|
|
320
|
+
const { pda: vaultPda } = findVaultPda(orderIdBytes, programId);
|
|
321
|
+
if (params.splitToBuyerPercent < 0 || params.splitToBuyerPercent > 100) {
|
|
322
|
+
throw new Error('Split percentage must be between 0 and 100');
|
|
323
|
+
}
|
|
324
|
+
const discriminator = (0, registry_js_1.getAnchorDiscriminator)('global', 'resolve_dispute');
|
|
325
|
+
const splitBuf = Buffer.from([params.splitToBuyerPercent]);
|
|
326
|
+
const data = Buffer.concat([discriminator, splitBuf]);
|
|
327
|
+
const keys = [
|
|
328
|
+
{ pubkey: escrowOrderPda, isSigner: false, isWritable: true },
|
|
329
|
+
{ pubkey: vaultPda, isSigner: false, isWritable: true },
|
|
330
|
+
{ pubkey: params.reviewer, isSigner: true, isWritable: false },
|
|
331
|
+
{ pubkey: params.buyer, isSigner: false, isWritable: true },
|
|
332
|
+
{ pubkey: params.seller, isSigner: false, isWritable: true },
|
|
333
|
+
{ pubkey: params.feeRecipient, isSigner: false, isWritable: true },
|
|
334
|
+
{ pubkey: registry_js_1.SYSTEM_PROGRAM_ID, isSigner: false, isWritable: false },
|
|
335
|
+
{ pubkey: findEscrowConfigPda(programId).pda, isSigner: false, isWritable: false },
|
|
336
|
+
];
|
|
337
|
+
return {
|
|
338
|
+
programId,
|
|
339
|
+
accounts: keys,
|
|
340
|
+
keys,
|
|
341
|
+
data: Buffer.from(data),
|
|
342
|
+
};
|
|
343
|
+
}
|
|
344
|
+
/**
|
|
345
|
+
* Decodes serialized EscrowOrder account buffer.
|
|
346
|
+
*/
|
|
347
|
+
function decodeEscrowOrderAccount(buffer) {
|
|
348
|
+
const buf = Buffer.from(buffer);
|
|
349
|
+
const expectedDiscriminator = (0, registry_js_1.getAnchorDiscriminator)('account', 'EscrowOrder');
|
|
350
|
+
if (buf.length < 8 + 32 * 4 + 32 + 8 + 2 + 8 + 1 + 8 + 8 + 4 + 1 + 1) {
|
|
351
|
+
throw new Error(`Truncated account buffer length: ${buf.length}`);
|
|
352
|
+
}
|
|
353
|
+
const accountDiscriminator = buf.subarray(0, 8);
|
|
354
|
+
if (!accountDiscriminator.equals(expectedDiscriminator)) {
|
|
355
|
+
throw new Error('Invalid account discriminator for EscrowOrder');
|
|
356
|
+
}
|
|
357
|
+
let offset = 8;
|
|
358
|
+
const buyer = (0, registry_js_1.encodeBase58)(buf.subarray(offset, offset + 32));
|
|
359
|
+
offset += 32;
|
|
360
|
+
const seller = (0, registry_js_1.encodeBase58)(buf.subarray(offset, offset + 32));
|
|
361
|
+
offset += 32;
|
|
362
|
+
const reviewer = (0, registry_js_1.encodeBase58)(buf.subarray(offset, offset + 32));
|
|
363
|
+
offset += 32;
|
|
364
|
+
const feeRecipient = (0, registry_js_1.encodeBase58)(buf.subarray(offset, offset + 32));
|
|
365
|
+
offset += 32;
|
|
366
|
+
const orderIdBytes = new Uint8Array(buf.subarray(offset, offset + 32));
|
|
367
|
+
const orderIdHex = '0x' + Buffer.from(orderIdBytes).toString('hex');
|
|
368
|
+
offset += 32;
|
|
369
|
+
const amountLamports = buf.readBigUInt64LE(offset);
|
|
370
|
+
offset += 8;
|
|
371
|
+
const feeBasisPoints = buf.readUInt16LE(offset);
|
|
372
|
+
offset += 2;
|
|
373
|
+
const deadline = Number(buf.readBigInt64LE(offset));
|
|
374
|
+
offset += 8;
|
|
375
|
+
const statusNum = buf.readUInt8(offset);
|
|
376
|
+
const status = exports.SOLANA_SERVICE_ESCROW_STATUS_MAP[statusNum] || 'None';
|
|
377
|
+
offset += 1;
|
|
378
|
+
const createdAt = Number(buf.readBigInt64LE(offset));
|
|
379
|
+
offset += 8;
|
|
380
|
+
const settledAt = Number(buf.readBigInt64LE(offset));
|
|
381
|
+
offset += 8;
|
|
382
|
+
const strLen = buf.readUInt32LE(offset);
|
|
383
|
+
offset += 4;
|
|
384
|
+
const deliverableReference = buf.subarray(offset, offset + strLen).toString('utf8');
|
|
385
|
+
offset += strLen;
|
|
386
|
+
const bump = buf.readUInt8(offset);
|
|
387
|
+
offset += 1;
|
|
388
|
+
const vaultBump = buf.readUInt8(offset);
|
|
389
|
+
const solDecimals = 9;
|
|
390
|
+
const amountSol = (Number(amountLamports) / 10 ** solDecimals).toFixed(4);
|
|
391
|
+
return {
|
|
392
|
+
buyer,
|
|
393
|
+
seller,
|
|
394
|
+
reviewer,
|
|
395
|
+
feeRecipient,
|
|
396
|
+
orderIdHex,
|
|
397
|
+
orderIdBytes,
|
|
398
|
+
amountLamports,
|
|
399
|
+
amountSol,
|
|
400
|
+
feeBasisPoints,
|
|
401
|
+
deadline,
|
|
402
|
+
status,
|
|
403
|
+
createdAt,
|
|
404
|
+
settledAt,
|
|
405
|
+
deliverableReference,
|
|
406
|
+
bump,
|
|
407
|
+
vaultBump,
|
|
408
|
+
};
|
|
409
|
+
}
|
|
410
|
+
/**
|
|
411
|
+
* Calculates exact platform fee and payouts for Solana lamports.
|
|
412
|
+
* Strict parity with EVM: 500 bps (5%) platform fee deducted from seller gross award.
|
|
413
|
+
* Buyer refunds are 100% fee-free.
|
|
414
|
+
*/
|
|
415
|
+
function calculateSolanaServicePayouts(totalLamports, splitToBuyerPercent = 0, feeBps = 500) {
|
|
416
|
+
const total = BigInt(totalLamports);
|
|
417
|
+
const buyerPercent = BigInt(Math.min(Math.max(splitToBuyerPercent, 0), 100));
|
|
418
|
+
const buyerRefundLamports = (total * buyerPercent) / 100n;
|
|
419
|
+
const sellerGrossLamports = total - buyerRefundLamports;
|
|
420
|
+
// Platform fee applies only to seller gross
|
|
421
|
+
const platformFeeLamports = (sellerGrossLamports * BigInt(feeBps)) / 10000n;
|
|
422
|
+
const sellerNetPayoutLamports = sellerGrossLamports - platformFeeLamports;
|
|
423
|
+
return {
|
|
424
|
+
buyerRefundLamports,
|
|
425
|
+
sellerGrossLamports,
|
|
426
|
+
platformFeeLamports,
|
|
427
|
+
sellerNetPayoutLamports,
|
|
428
|
+
};
|
|
429
|
+
}
|
|
430
|
+
/**
|
|
431
|
+
* Lossless conversion of lamports to a high-precision SOL string without floating-point errors.
|
|
432
|
+
*/
|
|
433
|
+
function formatLamportsToSol(lamports) {
|
|
434
|
+
const value = BigInt(lamports);
|
|
435
|
+
const negative = value < 0n;
|
|
436
|
+
const absVal = negative ? -value : value;
|
|
437
|
+
const intPart = absVal / 1000000000n;
|
|
438
|
+
const rem = absVal % 1000000000n;
|
|
439
|
+
if (rem === 0n) {
|
|
440
|
+
return (negative ? '-' : '') + intPart.toString();
|
|
441
|
+
}
|
|
442
|
+
const frac = rem.toString().padStart(9, '0').replace(/0+$/, '');
|
|
443
|
+
return (negative ? '-' : '') + `${intPart}.${frac}`;
|
|
444
|
+
}
|
|
445
|
+
/**
|
|
446
|
+
* Lossless conversion of SOL string to lamports bigint without floating-point inaccuracies.
|
|
447
|
+
*/
|
|
448
|
+
function parseSolToLamports(sol) {
|
|
449
|
+
const trimmed = sol.trim();
|
|
450
|
+
if (!trimmed || !/^-?\d+(\.\d+)?$/.test(trimmed)) {
|
|
451
|
+
throw new Error(`Invalid SOL amount string: "${sol}"`);
|
|
452
|
+
}
|
|
453
|
+
const negative = trimmed.startsWith('-');
|
|
454
|
+
const unsigned = negative ? trimmed.slice(1) : trimmed;
|
|
455
|
+
const [intStr, fracStr = ''] = unsigned.split('.');
|
|
456
|
+
if (fracStr.length > 9) {
|
|
457
|
+
throw new Error(`SOL amount has more than 9 decimal places: "${sol}"`);
|
|
458
|
+
}
|
|
459
|
+
const paddedFrac = fracStr.padEnd(9, '0');
|
|
460
|
+
const lamports = BigInt(intStr) * 1000000000n + BigInt(paddedFrac);
|
|
461
|
+
return negative ? -lamports : lamports;
|
|
462
|
+
}
|
|
463
|
+
//# sourceMappingURL=escrow.js.map
|