@ercworldio/blockchain-shared 1.0.5-dev.7-PROJ-1469.8 → 1.0.5-dev.7-PROJ-1469.10
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/build/services/ClaimJobService.d.ts.map +1 -1
- package/build/services/ClaimJobService.js +8 -3
- package/build/services/solana/escrow/SolanaEscrowAdmin.d.ts +18 -0
- package/build/services/solana/escrow/SolanaEscrowAdmin.d.ts.map +1 -1
- package/build/services/solana/escrow/SolanaEscrowAdmin.js +18 -1
- package/build/services/solana/escrow/services/EscrowAdminUtility.d.ts +40 -2
- package/build/services/solana/escrow/services/EscrowAdminUtility.d.ts.map +1 -1
- package/build/services/solana/escrow/services/EscrowAdminUtility.js +228 -19
- package/build/services/solana/escrow/services/TreasuryWithdrawalSignature.d.ts +5 -0
- package/build/services/solana/escrow/services/TreasuryWithdrawalSignature.d.ts.map +1 -1
- package/build/services/solana/escrow/services/TreasuryWithdrawalSignature.js +29 -9
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ClaimJobService.d.ts","sourceRoot":"","sources":["../../src/services/ClaimJobService.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAGjD,OAAO,EAAE,SAAS,EAA0B,MAAM,eAAe,CAAC;AAElE,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAExC,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACvD,OAAO,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,sBAAsB,EAAE,mBAAmB,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AAKlK,cAAM,gBAAgB;IAClB,OAAO,CAAC,MAAM,CAAgB;IAC9B,OAAO,CAAC,MAAM,CAA4B;IAC1C,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,KAAK,CAAS;gBAGV,MAAM,EAAE,aAAa;IAMjC,OAAO,CAAC,QAAQ,CAIf;IAED,OAAO,CAAC,gBAAgB,CAIvB;IAED,OAAO,CAAC,QAAQ,CAsBf;IAEM,yCAAyC,GAAU,QAAO,MAAW,EAAE,YAAW,MAAY,EAAE,kBAAiB,MAAU,EAAE,gBAAe,oBAAoF,KAAG,OAAO,CAAC,mBAAmB,EAAE,CAAC,CAOvQ;IAEM,8BAA8B,GAAU,QAAO,MAAW,EAAE,YAAW,MAAY,EAAE,kBAAiB,MAAU,EAAE,gBAAe,oBAAoF,KAAG,OAAO,CAAC,mBAAmB,EAAE,CAAC,
|
|
1
|
+
{"version":3,"file":"ClaimJobService.d.ts","sourceRoot":"","sources":["../../src/services/ClaimJobService.ts"],"names":[],"mappings":"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"}
|
|
@@ -119,9 +119,10 @@ class ClaimJobsService {
|
|
|
119
119
|
AND LOWER(cer.contract_address) = LOWER(cs.contract_address)
|
|
120
120
|
LEFT JOIN multisig.crypto_role cr ON cr.id = cer.role_id
|
|
121
121
|
WHERE cs.reference_id = u.request_id
|
|
122
|
-
AND
|
|
123
|
-
|
|
124
|
-
|
|
122
|
+
AND (
|
|
123
|
+
(cs.v IS NOT NULL AND cs.r IS NOT NULL AND cs.s IS NOT NULL)
|
|
124
|
+
OR cs.signature IS NOT NULL
|
|
125
|
+
)
|
|
125
126
|
) AS multisig_signatures
|
|
126
127
|
FROM updated u;
|
|
127
128
|
`, [limit, job_ttl_s, (0, uuid_1.v4)(), lock_metadata.lock_owner, lock_metadata.lock_reason, max_retry_count]);
|
|
@@ -197,6 +198,10 @@ class ClaimJobsService {
|
|
|
197
198
|
AND LOWER(cer.contract_address) = LOWER(cs.contract_address)
|
|
198
199
|
LEFT JOIN multisig.crypto_role cr ON cr.id = cer.role_id
|
|
199
200
|
WHERE cs.reference_id = u.request_id
|
|
201
|
+
AND (
|
|
202
|
+
(cs.v IS NOT NULL AND cs.r IS NOT NULL AND cs.s IS NOT NULL)
|
|
203
|
+
OR cs.signature IS NOT NULL
|
|
204
|
+
)
|
|
200
205
|
) AS multisig_signatures
|
|
201
206
|
FROM updated u
|
|
202
207
|
LEFT JOIN multisig.crypto_withdrawal_commitment cwc ON cwc.request_id = u.request_id;
|
|
@@ -6,6 +6,12 @@ import { ChainId } from "../../../interfaces";
|
|
|
6
6
|
interface AdditionalConstructorParams {
|
|
7
7
|
signer_keypair?: Keypair;
|
|
8
8
|
localnet: boolean;
|
|
9
|
+
/**
|
|
10
|
+
* Address Lookup Table holding the batch path's static accounts. Supply it to send v0
|
|
11
|
+
* transactions, which is required for batches carrying more than two treasury signatures.
|
|
12
|
+
* Create it once with `create_lookup_table` and persist the returned address.
|
|
13
|
+
*/
|
|
14
|
+
lookup_table_address?: string;
|
|
9
15
|
}
|
|
10
16
|
declare class SolanaEscrowAdmin {
|
|
11
17
|
provider: anchor.AnchorProvider;
|
|
@@ -83,6 +89,18 @@ declare class SolanaEscrowAdmin {
|
|
|
83
89
|
*/
|
|
84
90
|
set_pause_state: (target_state: boolean) => Promise<string>;
|
|
85
91
|
withdraw_batch: (chain_id: ChainId, token_address: string, receivers: BatchReceiver[]) => Promise<string>;
|
|
92
|
+
/**
|
|
93
|
+
* Idempotently ensures the batch path's Address Lookup Table exists and covers `mints`.
|
|
94
|
+
* Safe to call on every startup: it discovers an existing table on-chain, extends it when
|
|
95
|
+
* addresses are missing, and only creates one when none exists. Returns the address, or null
|
|
96
|
+
* when provisioning failed (callers then run on legacy transactions).
|
|
97
|
+
*
|
|
98
|
+
* `withdraw_batch` calls this automatically for signature-carrying batches, so wiring it into
|
|
99
|
+
* startup is about observability and warming, not correctness.
|
|
100
|
+
*/
|
|
101
|
+
ensure_lookup_table: (mints: string[]) => Promise<string | null>;
|
|
102
|
+
/** @deprecated prefer `ensure_lookup_table` — this throws instead of degrading gracefully. */
|
|
103
|
+
create_lookup_table: (mints: string[]) => Promise<string>;
|
|
86
104
|
/**
|
|
87
105
|
*
|
|
88
106
|
* @param token_address Address of the token to withdraw
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SolanaEscrowAdmin.d.ts","sourceRoot":"","sources":["../../../../src/services/solana/escrow/SolanaEscrowAdmin.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,SAAS,EAAqC,MAAM,iBAAiB,CAAC;AAEpG,OAAO,KAAK,MAAM,MAAM,mBAAmB,CAAC;AAE5C,OAAO,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AAExC,OAAO,EAAE,aAAa,EAAE,4BAA4B,EAAE,wBAAwB,EAAE,MAAM,eAAe,CAAC;AACtG,OAAO,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AAkB9C,UAAU,2BAA2B;IACjC,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,QAAQ,EAAE,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"SolanaEscrowAdmin.d.ts","sourceRoot":"","sources":["../../../../src/services/solana/escrow/SolanaEscrowAdmin.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,SAAS,EAAqC,MAAM,iBAAiB,CAAC;AAEpG,OAAO,KAAK,MAAM,MAAM,mBAAmB,CAAC;AAE5C,OAAO,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AAExC,OAAO,EAAE,aAAa,EAAE,4BAA4B,EAAE,wBAAwB,EAAE,MAAM,eAAe,CAAC;AACtG,OAAO,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AAkB9C,UAAU,2BAA2B;IACjC,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,QAAQ,EAAE,OAAO,CAAC;IAClB;;;;OAIG;IACH,oBAAoB,CAAC,EAAE,MAAM,CAAC;CACjC;AAED,cAAM,iBAAiB;IACZ,QAAQ,EAAE,MAAM,CAAC,cAAc,CAAC;IAChC,OAAO,EAAE,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IACvC,OAAO,CAAC,YAAY,CAAqB;IACzC,OAAO,CAAC,MAAM,CAAC,CAAU;IAClB,UAAU,EAAE,UAAU,CAAC;gBAG1B,aAAa,EAAE,MAAM,EACrB,eAAe,EAAE,SAAS,EAC1B,eAAe,EAAE,wBAAwB,EACzC,mBAAmB,EAAE,4BAA4B,EACjD,OAAO,EAAE,MAAM,EACf,gBAAgB,CAAC,EAAE,2BAA2B,EAC9C,UAAU,CAAC,EAAE,MAAM,CAAC,IAAI,CAAC,UAAU;IAkCvC;;;OAGG;IACH,OAAO,CAAC,OAAO,CAGb;IAEF;;;OAGG;IACI,kBAAkB,wBAGvB;IAKF;;;OAGG;IACI,SAAS,yBAEf;IAED;;;;OAIG;IACI,QAAQ,GAAU,gBAAgB,MAAM,sBAE9C;IAED;;;;OAIG;IACI,gBAAgB,GAAU,eAAe,MAAM,sBAErD;IAEM,YAAY,oCAElB;IAGD;;;OAGG;IACI,kBAAkB,0BAExB;IAED;;;OAGG;IACI,UAAU,0BAEhB;IAED;;;;OAIG;IACI,iBAAiB,GAAU,eAAe,MAAM,qBAEtD;IAED;;;;OAIG;IACI,oBAAoB,GAAU,eAAe,MAAM,qBAEzD;IAED;;;;OAIG;IACI,SAAS,GAAU,gBAAgB,MAAM,qBAE/C;IAGD;;;;OAIG;IACI,YAAY,GAAU,gBAAgB,MAAM,qBAElD;IAED;;;;OAIG;IACI,eAAe,GAAU,cAAc,OAAO,qBAEpD;IAIM,cAAc,GAAU,UAAU,OAAO,EAAE,eAAe,MAAM,EAAE,WAAW,aAAa,EAAE,qBAElG;IAED;;;;;;;;OAQG;IACI,mBAAmB,GAAU,OAAO,MAAM,EAAE,4BAGlD;IAED,8FAA8F;IACvF,mBAAmB,GAAU,OAAO,MAAM,EAAE,qBAElD;IAGD;;;;;;OAMG;IACI,QAAQ,GAAU,eAAe,MAAM,EAAE,oBAAoB,MAAM,EAAE,kBAAkB,MAAM,iCAEnG;IAED;;;;;OAKG;IACI,OAAO,GAAU,eAAe,MAAM,EAAE,oBAAoB,MAAM,qBAExE;CAKJ;AAED,eAAe,iBAAiB,CAAC"}
|
|
@@ -165,6 +165,23 @@ class SolanaEscrowAdmin {
|
|
|
165
165
|
this.withdraw_batch = (chain_id, token_address, receivers) => __awaiter(this, void 0, void 0, function* () {
|
|
166
166
|
return this.adminUtility.withdraw_batch(chain_id, token_address, receivers, this.signer);
|
|
167
167
|
});
|
|
168
|
+
/**
|
|
169
|
+
* Idempotently ensures the batch path's Address Lookup Table exists and covers `mints`.
|
|
170
|
+
* Safe to call on every startup: it discovers an existing table on-chain, extends it when
|
|
171
|
+
* addresses are missing, and only creates one when none exists. Returns the address, or null
|
|
172
|
+
* when provisioning failed (callers then run on legacy transactions).
|
|
173
|
+
*
|
|
174
|
+
* `withdraw_batch` calls this automatically for signature-carrying batches, so wiring it into
|
|
175
|
+
* startup is about observability and warming, not correctness.
|
|
176
|
+
*/
|
|
177
|
+
this.ensure_lookup_table = (mints) => __awaiter(this, void 0, void 0, function* () {
|
|
178
|
+
const table = yield this.adminUtility.ensure_lookup_table(mints, this.signer);
|
|
179
|
+
return table ? table.toBase58() : null;
|
|
180
|
+
});
|
|
181
|
+
/** @deprecated prefer `ensure_lookup_table` — this throws instead of degrading gracefully. */
|
|
182
|
+
this.create_lookup_table = (mints) => __awaiter(this, void 0, void 0, function* () {
|
|
183
|
+
return this.adminUtility.create_lookup_table(mints, this.signer);
|
|
184
|
+
});
|
|
168
185
|
/**
|
|
169
186
|
*
|
|
170
187
|
* @param token_address Address of the token to withdraw
|
|
@@ -205,7 +222,7 @@ class SolanaEscrowAdmin {
|
|
|
205
222
|
const program = new anchor.Program(target_idl, provider);
|
|
206
223
|
this.program = program;
|
|
207
224
|
this.provider = provider;
|
|
208
|
-
this.adminUtility = EscrowAdminUtility_1.default.createWithCustomProgramId(provider, new web3_js_1.PublicKey(escrowAddress), this.get_idl());
|
|
225
|
+
this.adminUtility = EscrowAdminUtility_1.default.createWithCustomProgramId(provider, new web3_js_1.PublicKey(escrowAddress), this.get_idl(), additionalParams === null || additionalParams === void 0 ? void 0 : additionalParams.lookup_table_address);
|
|
209
226
|
if (additionalParams === null || additionalParams === void 0 ? void 0 : additionalParams.signer_keypair)
|
|
210
227
|
this.signer = additionalParams.signer_keypair;
|
|
211
228
|
}
|
|
@@ -7,7 +7,43 @@ import { ChainId } from "../../../../interfaces";
|
|
|
7
7
|
export declare class EscrowAdminUtility {
|
|
8
8
|
program: Program<Escrow>;
|
|
9
9
|
provider: anchor.AnchorProvider;
|
|
10
|
-
|
|
10
|
+
/**
|
|
11
|
+
* Optional Address Lookup Table. When set, transactions are sent as v0 and the batch path's
|
|
12
|
+
* ~11 static accounts collapse from 32 bytes each to a 1-byte index — roughly 300 bytes back,
|
|
13
|
+
* which is what makes >2 treasury signatures fit under the 1232-byte limit.
|
|
14
|
+
*/
|
|
15
|
+
private lookupTableAddress?;
|
|
16
|
+
private lookupTableCache?;
|
|
17
|
+
constructor(program: Program<Escrow>, provider: anchor.AnchorProvider, lookupTableAddress?: string);
|
|
18
|
+
/** Accounts that are identical on every batch withdrawal — the ALT payload. */
|
|
19
|
+
lookup_table_addresses(mints: string[]): PublicKey[];
|
|
20
|
+
/**
|
|
21
|
+
* Idempotently guarantees a lookup table covering `mints` exists and is usable.
|
|
22
|
+
*
|
|
23
|
+
* Deliberately keeps no external state: tables are discovered on-chain by their authority
|
|
24
|
+
* (the funding wallet), so there is nothing to persist, migrate, or keep in sync across
|
|
25
|
+
* environments and worker instances. Extends a table that is missing addresses, creates one
|
|
26
|
+
* when none exists, and returns the usable address.
|
|
27
|
+
*
|
|
28
|
+
* Returns null if provisioning fails — the lookup table is an optimisation, so callers fall
|
|
29
|
+
* back to legacy transactions rather than failing a withdrawal that would otherwise succeed.
|
|
30
|
+
*/
|
|
31
|
+
ensure_lookup_table(mints: string[], signer?: Keypair): Promise<PublicKey | null>;
|
|
32
|
+
/** Back-compat wrapper for explicit one-time provisioning; prefer `ensure_lookup_table`. */
|
|
33
|
+
create_lookup_table(mints: string[], signer?: Keypair): Promise<string>;
|
|
34
|
+
private fetchLookupTable;
|
|
35
|
+
/**
|
|
36
|
+
* Finds a live table already owned by this authority. `getProgramAccounts` is filtered
|
|
37
|
+
* server-side on the authority pubkey, which sits at a fixed offset in the table header:
|
|
38
|
+
* u32 typeIndex + u64 deactivationSlot + u64 lastExtendedSlot + u8 startIndex + u8 option tag.
|
|
39
|
+
*/
|
|
40
|
+
private discoverLookupTable;
|
|
41
|
+
private missingAddresses;
|
|
42
|
+
private createLookupTable;
|
|
43
|
+
private extendLookupTable;
|
|
44
|
+
private waitForLookupTableActivation;
|
|
45
|
+
/** Resolves (and caches) the configured lookup table; [] when none is set or it's missing. */
|
|
46
|
+
private resolveLookupTables;
|
|
11
47
|
/**
|
|
12
48
|
* Check if the escrow program is paused or running
|
|
13
49
|
* @returns true/false. True: program is paused. False: Program is running
|
|
@@ -111,6 +147,8 @@ export declare class EscrowAdminUtility {
|
|
|
111
147
|
getVaultBalance(): Promise<number>;
|
|
112
148
|
getVaultTokenBalance(mint: PublicKey): Promise<number>;
|
|
113
149
|
private sendTransaction;
|
|
150
|
+
private sendVersionedTransaction;
|
|
151
|
+
private sendLegacyTransaction;
|
|
114
152
|
confirmTransaction(signature: string, commitment?: Commitment): Promise<void>;
|
|
115
153
|
waitForConfirmation(signature: TransactionSignature, commitment?: 'confirmed' | 'finalized', timeoutMs?: number): Promise<void>;
|
|
116
154
|
/**
|
|
@@ -127,7 +165,7 @@ export declare class EscrowAdminUtility {
|
|
|
127
165
|
* @param idl IDL file - Escrow program idl
|
|
128
166
|
* @returns
|
|
129
167
|
*/
|
|
130
|
-
static createWithCustomProgramId(provider: anchor.AnchorProvider, programId: PublicKey, idl: anchor.Idl): EscrowAdminUtility;
|
|
168
|
+
static createWithCustomProgramId(provider: anchor.AnchorProvider, programId: PublicKey, idl: anchor.Idl, lookupTableAddress?: string): EscrowAdminUtility;
|
|
131
169
|
}
|
|
132
170
|
export default EscrowAdminUtility;
|
|
133
171
|
//# sourceMappingURL=EscrowAdminUtility.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"EscrowAdminUtility.d.ts","sourceRoot":"","sources":["../../../../../src/services/solana/escrow/services/EscrowAdminUtility.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,MAAM,mBAAmB,CAAC;AAC5C,OAAO,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAC5C,OAAO,
|
|
1
|
+
{"version":3,"file":"EscrowAdminUtility.d.ts","sourceRoot":"","sources":["../../../../../src/services/solana/escrow/services/EscrowAdminUtility.ts"],"names":[],"mappings":"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"}
|
|
@@ -58,9 +58,181 @@ const TokenAccountService_1 = require("./TokenAccountService");
|
|
|
58
58
|
const SolanaTokenProgramCache_1 = require("./SolanaTokenProgramCache");
|
|
59
59
|
const TreasuryWithdrawalSignature_1 = require("./TreasuryWithdrawalSignature");
|
|
60
60
|
class EscrowAdminUtility {
|
|
61
|
-
constructor(program, provider) {
|
|
61
|
+
constructor(program, provider, lookupTableAddress) {
|
|
62
62
|
this.program = program;
|
|
63
63
|
this.provider = provider;
|
|
64
|
+
if (lookupTableAddress)
|
|
65
|
+
this.lookupTableAddress = new web3_js_1.PublicKey(lookupTableAddress);
|
|
66
|
+
}
|
|
67
|
+
/** Accounts that are identical on every batch withdrawal — the ALT payload. */
|
|
68
|
+
lookup_table_addresses(mints) {
|
|
69
|
+
const programId = this.program.programId;
|
|
70
|
+
const global = [
|
|
71
|
+
EscrowService.findEscrowConfigPda(programId),
|
|
72
|
+
EscrowService.findVaultAuthorityPda(programId),
|
|
73
|
+
web3_js_1.PublicKey.findProgramAddressSync([Buffer.from("treasury-config")], programId)[0],
|
|
74
|
+
web3_js_1.PublicKey.findProgramAddressSync([Buffer.from("timelock-config")], programId)[0],
|
|
75
|
+
spl_token_1.TOKEN_PROGRAM_ID,
|
|
76
|
+
web3_js_1.SystemProgram.programId,
|
|
77
|
+
web3_js_1.SYSVAR_INSTRUCTIONS_PUBKEY,
|
|
78
|
+
];
|
|
79
|
+
const perMint = mints.flatMap(m => {
|
|
80
|
+
const mint = new web3_js_1.PublicKey(m);
|
|
81
|
+
return [
|
|
82
|
+
mint,
|
|
83
|
+
EscrowService.findVaultAta(mint, programId),
|
|
84
|
+
web3_js_1.PublicKey.findProgramAddressSync([Buffer.from("token-threshold"), mint.toBytes()], programId)[0],
|
|
85
|
+
web3_js_1.PublicKey.findProgramAddressSync([Buffer.from("token-timelock"), mint.toBytes()], programId)[0],
|
|
86
|
+
];
|
|
87
|
+
});
|
|
88
|
+
return [...global, ...perMint];
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Idempotently guarantees a lookup table covering `mints` exists and is usable.
|
|
92
|
+
*
|
|
93
|
+
* Deliberately keeps no external state: tables are discovered on-chain by their authority
|
|
94
|
+
* (the funding wallet), so there is nothing to persist, migrate, or keep in sync across
|
|
95
|
+
* environments and worker instances. Extends a table that is missing addresses, creates one
|
|
96
|
+
* when none exists, and returns the usable address.
|
|
97
|
+
*
|
|
98
|
+
* Returns null if provisioning fails — the lookup table is an optimisation, so callers fall
|
|
99
|
+
* back to legacy transactions rather than failing a withdrawal that would otherwise succeed.
|
|
100
|
+
*/
|
|
101
|
+
ensure_lookup_table(mints, signer) {
|
|
102
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
103
|
+
try {
|
|
104
|
+
const required = this.lookup_table_addresses(mints);
|
|
105
|
+
const existing = this.lookupTableAddress
|
|
106
|
+
? yield this.fetchLookupTable(this.lookupTableAddress)
|
|
107
|
+
: yield this.discoverLookupTable();
|
|
108
|
+
if (existing) {
|
|
109
|
+
const missing = this.missingAddresses(existing.state.addresses, required);
|
|
110
|
+
if (missing.length)
|
|
111
|
+
yield this.extendLookupTable(existing.key, missing, signer);
|
|
112
|
+
this.lookupTableAddress = existing.key;
|
|
113
|
+
this.lookupTableCache = undefined;
|
|
114
|
+
return existing.key;
|
|
115
|
+
}
|
|
116
|
+
const table = yield this.createLookupTable(required, signer);
|
|
117
|
+
this.lookupTableAddress = table;
|
|
118
|
+
this.lookupTableCache = undefined;
|
|
119
|
+
return table;
|
|
120
|
+
}
|
|
121
|
+
catch (error) {
|
|
122
|
+
return null;
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
/** Back-compat wrapper for explicit one-time provisioning; prefer `ensure_lookup_table`. */
|
|
127
|
+
create_lookup_table(mints, signer) {
|
|
128
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
129
|
+
const table = yield this.ensure_lookup_table(mints, signer);
|
|
130
|
+
if (!table)
|
|
131
|
+
throw new Error("Failed to provision the escrow lookup table");
|
|
132
|
+
return table.toBase58();
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
fetchLookupTable(key) {
|
|
136
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
137
|
+
const { value } = yield this.provider.connection.getAddressLookupTable(key);
|
|
138
|
+
return value ? { key, state: value.state } : null;
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Finds a live table already owned by this authority. `getProgramAccounts` is filtered
|
|
143
|
+
* server-side on the authority pubkey, which sits at a fixed offset in the table header:
|
|
144
|
+
* u32 typeIndex + u64 deactivationSlot + u64 lastExtendedSlot + u8 startIndex + u8 option tag.
|
|
145
|
+
*/
|
|
146
|
+
discoverLookupTable() {
|
|
147
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
148
|
+
const AUTHORITY_OFFSET = 22;
|
|
149
|
+
const authority = this.provider.wallet.publicKey;
|
|
150
|
+
const accounts = yield this.provider.connection.getProgramAccounts(web3_js_1.AddressLookupTableProgram.programId, { filters: [{ memcmp: { offset: AUTHORITY_OFFSET, bytes: authority.toBase58() } }] });
|
|
151
|
+
const live = accounts
|
|
152
|
+
.map(a => {
|
|
153
|
+
try {
|
|
154
|
+
return { key: a.pubkey, state: web3_js_1.AddressLookupTableAccount.deserialize(a.account.data) };
|
|
155
|
+
}
|
|
156
|
+
catch (_a) {
|
|
157
|
+
return null;
|
|
158
|
+
}
|
|
159
|
+
})
|
|
160
|
+
.filter((t) => t !== null)
|
|
161
|
+
// A deactivated table cannot be used; MAX u64 means "never deactivated".
|
|
162
|
+
.filter(t => t.state.deactivationSlot === BigInt("18446744073709551615"));
|
|
163
|
+
if (!live.length)
|
|
164
|
+
return null;
|
|
165
|
+
// Prefer the most complete table so repeated runs converge on one.
|
|
166
|
+
return live.sort((a, b) => b.state.addresses.length - a.state.addresses.length)[0];
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
missingAddresses(present, required) {
|
|
170
|
+
const have = new Set(present.map(a => a.toBase58()));
|
|
171
|
+
const seen = new Set();
|
|
172
|
+
return required.filter(a => {
|
|
173
|
+
const k = a.toBase58();
|
|
174
|
+
if (have.has(k) || seen.has(k))
|
|
175
|
+
return false;
|
|
176
|
+
seen.add(k);
|
|
177
|
+
return true;
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
createLookupTable(addresses, signer) {
|
|
181
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
182
|
+
const authority = this.provider.wallet.publicKey;
|
|
183
|
+
const slot = yield this.provider.connection.getSlot("finalized");
|
|
184
|
+
const [createIx, table] = web3_js_1.AddressLookupTableProgram.createLookupTable({
|
|
185
|
+
authority, payer: authority, recentSlot: slot,
|
|
186
|
+
});
|
|
187
|
+
yield this.sendLegacyTransaction([createIx], signer);
|
|
188
|
+
yield this.extendLookupTable(table, addresses, signer);
|
|
189
|
+
return table;
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
extendLookupTable(table, addresses, signer) {
|
|
193
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
194
|
+
const authority = this.provider.wallet.publicKey;
|
|
195
|
+
// Chunked so the extend instruction itself stays under the transaction size limit.
|
|
196
|
+
for (let i = 0; i < addresses.length; i += 20) {
|
|
197
|
+
yield this.sendLegacyTransaction([
|
|
198
|
+
web3_js_1.AddressLookupTableProgram.extendLookupTable({
|
|
199
|
+
payer: authority, authority, lookupTable: table, addresses: addresses.slice(i, i + 20),
|
|
200
|
+
}),
|
|
201
|
+
], signer);
|
|
202
|
+
}
|
|
203
|
+
// A table is only usable from the slot after it was written; wait so the first v0
|
|
204
|
+
// transaction referencing it can actually resolve the accounts.
|
|
205
|
+
yield this.waitForLookupTableActivation(table);
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
waitForLookupTableActivation(table_1) {
|
|
209
|
+
return __awaiter(this, arguments, void 0, function* (table, timeoutMs = 30000) {
|
|
210
|
+
const startSlot = yield this.provider.connection.getSlot("confirmed");
|
|
211
|
+
const deadline = Date.now() + timeoutMs;
|
|
212
|
+
while (Date.now() < deadline) {
|
|
213
|
+
const [{ value }, slot] = yield Promise.all([
|
|
214
|
+
this.provider.connection.getAddressLookupTable(table),
|
|
215
|
+
this.provider.connection.getSlot("confirmed"),
|
|
216
|
+
]);
|
|
217
|
+
if (value && slot > startSlot)
|
|
218
|
+
return;
|
|
219
|
+
yield new Promise(r => setTimeout(r, 1000));
|
|
220
|
+
}
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
/** Resolves (and caches) the configured lookup table; [] when none is set or it's missing. */
|
|
224
|
+
resolveLookupTables() {
|
|
225
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
226
|
+
if (!this.lookupTableAddress)
|
|
227
|
+
return [];
|
|
228
|
+
if (this.lookupTableCache)
|
|
229
|
+
return [this.lookupTableCache];
|
|
230
|
+
const { value } = yield this.provider.connection.getAddressLookupTable(this.lookupTableAddress);
|
|
231
|
+
if (!value)
|
|
232
|
+
return [];
|
|
233
|
+
this.lookupTableCache = value;
|
|
234
|
+
return [value];
|
|
235
|
+
});
|
|
64
236
|
}
|
|
65
237
|
// ==========================
|
|
66
238
|
// Admin View Methods
|
|
@@ -368,6 +540,13 @@ class EscrowAdminUtility {
|
|
|
368
540
|
withdraw_batch(chain_id, token_address, recipients, signer) {
|
|
369
541
|
return __awaiter(this, void 0, void 0, function* () {
|
|
370
542
|
const token_pubkey = new web3_js_1.PublicKey(token_address);
|
|
543
|
+
// A batch carrying treasury signatures only fits in 1232 bytes as a v0 transaction, so make
|
|
544
|
+
// sure the lookup table exists before building it. This is idempotent and self-healing: the
|
|
545
|
+
// first signature-gated withdrawal provisions the table, every later one reuses it, and a
|
|
546
|
+
// failure here simply leaves us on legacy transactions rather than blocking the withdrawal.
|
|
547
|
+
if (recipients.some(r => { var _a; return (_a = r.signatures) === null || _a === void 0 ? void 0 : _a.length; })) {
|
|
548
|
+
yield this.ensure_lookup_table([token_address], signer);
|
|
549
|
+
}
|
|
371
550
|
switch (token_pubkey.toBase58()) {
|
|
372
551
|
case (web3_js_1.SystemProgram.programId.toBase58()):
|
|
373
552
|
return this.batch_withdraw_sol(chain_id, recipients, signer);
|
|
@@ -623,29 +802,59 @@ class EscrowAdminUtility {
|
|
|
623
802
|
sendTransaction(ixs, signer) {
|
|
624
803
|
return __awaiter(this, void 0, void 0, function* () {
|
|
625
804
|
try {
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
tx.recentBlockhash = (yield this.provider.connection.getLatestBlockhash()).blockhash;
|
|
632
|
-
let signature = "";
|
|
633
|
-
if (signer) {
|
|
634
|
-
tx.sign(signer);
|
|
635
|
-
signature = yield this.provider.connection.sendRawTransaction(tx.serialize());
|
|
636
|
-
yield (0, TransactionsService_1.waitForTransactionConfirmation)(this.provider, signature, "confirmed");
|
|
805
|
+
// Prefer a v0 transaction when a lookup table is configured — it is the only way a
|
|
806
|
+
// batch carrying more than two treasury signatures fits in 1232 bytes.
|
|
807
|
+
const lookupTables = yield this.resolveLookupTables();
|
|
808
|
+
if (lookupTables.length) {
|
|
809
|
+
return yield this.sendVersionedTransaction(ixs, lookupTables, signer);
|
|
637
810
|
}
|
|
638
|
-
|
|
639
|
-
signature = yield this.provider.sendAndConfirm(tx);
|
|
640
|
-
yield (0, TransactionsService_1.waitForTransactionConfirmation)(this.provider, signature, "confirmed");
|
|
641
|
-
}
|
|
642
|
-
return signature;
|
|
811
|
+
return yield this.sendLegacyTransaction(ixs, signer);
|
|
643
812
|
}
|
|
644
813
|
catch (error) {
|
|
645
814
|
throw Errors_1.default.decode(error);
|
|
646
815
|
}
|
|
647
816
|
});
|
|
648
817
|
}
|
|
818
|
+
sendVersionedTransaction(ixs, lookupTables, signer) {
|
|
819
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
820
|
+
const message = new web3_js_1.TransactionMessage({
|
|
821
|
+
payerKey: this.provider.wallet.publicKey,
|
|
822
|
+
recentBlockhash: (yield this.provider.connection.getLatestBlockhash()).blockhash,
|
|
823
|
+
instructions: ixs,
|
|
824
|
+
}).compileToV0Message(lookupTables);
|
|
825
|
+
const tx = new web3_js_1.VersionedTransaction(message);
|
|
826
|
+
if (signer) {
|
|
827
|
+
tx.sign([signer]);
|
|
828
|
+
}
|
|
829
|
+
else {
|
|
830
|
+
yield this.provider.wallet.signTransaction(tx);
|
|
831
|
+
}
|
|
832
|
+
const signature = yield this.provider.connection.sendRawTransaction(tx.serialize());
|
|
833
|
+
yield (0, TransactionsService_1.waitForTransactionConfirmation)(this.provider, signature, "confirmed");
|
|
834
|
+
return signature;
|
|
835
|
+
});
|
|
836
|
+
}
|
|
837
|
+
sendLegacyTransaction(ixs, signer) {
|
|
838
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
839
|
+
const tx = new web3_js_1.Transaction();
|
|
840
|
+
for (let ix of ixs) {
|
|
841
|
+
tx.add(ix);
|
|
842
|
+
}
|
|
843
|
+
tx.feePayer = this.provider.wallet.publicKey;
|
|
844
|
+
tx.recentBlockhash = (yield this.provider.connection.getLatestBlockhash()).blockhash;
|
|
845
|
+
let signature = "";
|
|
846
|
+
if (signer) {
|
|
847
|
+
tx.sign(signer);
|
|
848
|
+
signature = yield this.provider.connection.sendRawTransaction(tx.serialize());
|
|
849
|
+
yield (0, TransactionsService_1.waitForTransactionConfirmation)(this.provider, signature, "confirmed");
|
|
850
|
+
}
|
|
851
|
+
else {
|
|
852
|
+
signature = yield this.provider.sendAndConfirm(tx);
|
|
853
|
+
yield (0, TransactionsService_1.waitForTransactionConfirmation)(this.provider, signature, "confirmed");
|
|
854
|
+
}
|
|
855
|
+
return signature;
|
|
856
|
+
});
|
|
857
|
+
}
|
|
649
858
|
confirmTransaction(signature_1) {
|
|
650
859
|
return __awaiter(this, arguments, void 0, function* (signature, commitment = "finalized") {
|
|
651
860
|
yield this.provider.connection.confirmTransaction(signature, commitment);
|
|
@@ -698,11 +907,11 @@ class EscrowAdminUtility {
|
|
|
698
907
|
* @param idl IDL file - Escrow program idl
|
|
699
908
|
* @returns
|
|
700
909
|
*/
|
|
701
|
-
static createWithCustomProgramId(provider, programId, idl) {
|
|
910
|
+
static createWithCustomProgramId(provider, programId, idl, lookupTableAddress) {
|
|
702
911
|
// Override the program ID in the IDL
|
|
703
912
|
const modifiedIdl = Object.assign(Object.assign({}, idl), { address: programId.toBase58() });
|
|
704
913
|
const program = new anchor_1.Program(modifiedIdl, provider);
|
|
705
|
-
return new EscrowAdminUtility(program, provider);
|
|
914
|
+
return new EscrowAdminUtility(program, provider, lookupTableAddress);
|
|
706
915
|
}
|
|
707
916
|
}
|
|
708
917
|
exports.EscrowAdminUtility = EscrowAdminUtility;
|
|
@@ -48,6 +48,11 @@ export interface Ed25519Entry {
|
|
|
48
48
|
* (each entry's pubkey, signature and message live in this instruction's own data). This is the
|
|
49
49
|
* compact layout the program scans in `verify_treasury_threshold`; one instruction for the whole
|
|
50
50
|
* batch keeps the transaction far smaller than one instruction per signature.
|
|
51
|
+
*
|
|
52
|
+
* Identical messages are stored ONCE and shared by every signature over them, since the offsets
|
|
53
|
+
* table lets multiple entries point at the same message region. This matters: the N signers who
|
|
54
|
+
* approve one withdrawal all sign the same ~194-byte payload, so without sharing, a 2-of-N
|
|
55
|
+
* approval would spend an extra ~194 bytes and overflow Solana's 1232-byte transaction limit.
|
|
51
56
|
*/
|
|
52
57
|
export declare function buildTreasuryEd25519Instruction(entries: Ed25519Entry[]): TransactionInstruction;
|
|
53
58
|
//# sourceMappingURL=TreasuryWithdrawalSignature.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TreasuryWithdrawalSignature.d.ts","sourceRoot":"","sources":["../../../../../src/services/solana/escrow/services/TreasuryWithdrawalSignature.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkB,SAAS,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAC;AAGpF;;;;;GAKG;AAEH,wEAAwE;AACxE,MAAM,WAAW,sBAAsB;IACnC,4EAA4E;IAC5E,MAAM,EAAE,MAAM,CAAC;IACf,qDAAqD;IACrD,SAAS,EAAE,MAAM,CAAC;CACrB;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,8BAA8B,CAAC,MAAM,EAAE;IACnD,SAAS,EAAE,SAAS,CAAC;IACrB,SAAS,EAAE,SAAS,CAAC;IACrB,eAAe,EAAE,MAAM,CAAC;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;CACrB,GAAG,MAAM,CAUT;AAED,oFAAoF;AACpF,wBAAgB,sBAAsB,CAAC,CAAC,EAAE,MAAM,GAAG,UAAU,CAU5D;AAED,4EAA4E;AAC5E,MAAM,WAAW,YAAY;IACzB,SAAS,EAAE,UAAU,CAAC;IACtB,SAAS,EAAE,UAAU,CAAC;IACtB,OAAO,EAAE,UAAU,CAAC;CACvB;AAED
|
|
1
|
+
{"version":3,"file":"TreasuryWithdrawalSignature.d.ts","sourceRoot":"","sources":["../../../../../src/services/solana/escrow/services/TreasuryWithdrawalSignature.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkB,SAAS,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAC;AAGpF;;;;;GAKG;AAEH,wEAAwE;AACxE,MAAM,WAAW,sBAAsB;IACnC,4EAA4E;IAC5E,MAAM,EAAE,MAAM,CAAC;IACf,qDAAqD;IACrD,SAAS,EAAE,MAAM,CAAC;CACrB;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,8BAA8B,CAAC,MAAM,EAAE;IACnD,SAAS,EAAE,SAAS,CAAC;IACrB,SAAS,EAAE,SAAS,CAAC;IACrB,eAAe,EAAE,MAAM,CAAC;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;CACrB,GAAG,MAAM,CAUT;AAED,oFAAoF;AACpF,wBAAgB,sBAAsB,CAAC,CAAC,EAAE,MAAM,GAAG,UAAU,CAU5D;AAED,4EAA4E;AAC5E,MAAM,WAAW,YAAY;IACzB,SAAS,EAAE,UAAU,CAAC;IACtB,SAAS,EAAE,UAAU,CAAC;IACtB,OAAO,EAAE,UAAU,CAAC;CACvB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,+BAA+B,CAAC,OAAO,EAAE,YAAY,EAAE,GAAG,sBAAsB,CAoD/F"}
|
|
@@ -55,6 +55,11 @@ function decodeEd25519Signature(s) {
|
|
|
55
55
|
* (each entry's pubkey, signature and message live in this instruction's own data). This is the
|
|
56
56
|
* compact layout the program scans in `verify_treasury_threshold`; one instruction for the whole
|
|
57
57
|
* batch keeps the transaction far smaller than one instruction per signature.
|
|
58
|
+
*
|
|
59
|
+
* Identical messages are stored ONCE and shared by every signature over them, since the offsets
|
|
60
|
+
* table lets multiple entries point at the same message region. This matters: the N signers who
|
|
61
|
+
* approve one withdrawal all sign the same ~194-byte payload, so without sharing, a 2-of-N
|
|
62
|
+
* approval would spend an extra ~194 bytes and overflow Solana's 1232-byte transaction limit.
|
|
58
63
|
*/
|
|
59
64
|
function buildTreasuryEd25519Instruction(entries) {
|
|
60
65
|
const N = entries.length;
|
|
@@ -62,28 +67,43 @@ function buildTreasuryEd25519Instruction(entries) {
|
|
|
62
67
|
const ENTRY_SIZE = 32 + 64; // pubkey + signature
|
|
63
68
|
const header = 2 + N * OFFSETS_SIZE;
|
|
64
69
|
const msgStart = header + N * ENTRY_SIZE;
|
|
65
|
-
|
|
66
|
-
const
|
|
70
|
+
// Deduplicate message blobs by content; remember where each unique one lands.
|
|
71
|
+
const uniqueMessages = [];
|
|
72
|
+
const messageOffsets = [];
|
|
73
|
+
const seen = new Map();
|
|
74
|
+
let cursor = msgStart;
|
|
75
|
+
for (const entry of entries) {
|
|
76
|
+
const key = Buffer.from(entry.message).toString("base64");
|
|
77
|
+
let offset = seen.get(key);
|
|
78
|
+
if (offset === undefined) {
|
|
79
|
+
offset = cursor;
|
|
80
|
+
seen.set(key, offset);
|
|
81
|
+
uniqueMessages.push(entry.message);
|
|
82
|
+
cursor += entry.message.length;
|
|
83
|
+
}
|
|
84
|
+
messageOffsets.push(offset);
|
|
85
|
+
}
|
|
86
|
+
const data = Buffer.alloc(cursor);
|
|
67
87
|
data[0] = N; // number of signatures
|
|
68
88
|
data[1] = 0; // padding
|
|
69
|
-
let msgCursor = msgStart;
|
|
70
89
|
for (let i = 0; i < N; i++) {
|
|
71
90
|
const base = 2 + i * OFFSETS_SIZE;
|
|
72
91
|
const pkOffset = header + i * ENTRY_SIZE;
|
|
73
92
|
const sigOffset = pkOffset + 32;
|
|
74
|
-
const msgOffset = msgCursor;
|
|
75
|
-
const msgLen = entries[i].message.length;
|
|
76
93
|
data.writeUInt16LE(sigOffset, base + 0); // signature_offset
|
|
77
94
|
data.writeUInt16LE(0xffff, base + 2); // signature_instruction_index (self)
|
|
78
95
|
data.writeUInt16LE(pkOffset, base + 4); // public_key_offset
|
|
79
96
|
data.writeUInt16LE(0xffff, base + 6); // public_key_instruction_index (self)
|
|
80
|
-
data.writeUInt16LE(
|
|
81
|
-
data.writeUInt16LE(
|
|
97
|
+
data.writeUInt16LE(messageOffsets[i], base + 8); // message_data_offset (may be shared)
|
|
98
|
+
data.writeUInt16LE(entries[i].message.length, base + 10); // message_data_size
|
|
82
99
|
data.writeUInt16LE(0xffff, base + 12); // message_instruction_index (self)
|
|
83
100
|
data.set(entries[i].publicKey, pkOffset);
|
|
84
101
|
data.set(entries[i].signature, sigOffset);
|
|
85
|
-
|
|
86
|
-
|
|
102
|
+
}
|
|
103
|
+
// Write each unique message once, at the offset its first referrer recorded.
|
|
104
|
+
for (let i = 0, offset = msgStart; i < uniqueMessages.length; i++) {
|
|
105
|
+
data.set(uniqueMessages[i], offset);
|
|
106
|
+
offset += uniqueMessages[i].length;
|
|
87
107
|
}
|
|
88
108
|
return new web3_js_1.TransactionInstruction({ keys: [], programId: web3_js_1.Ed25519Program.programId, data });
|
|
89
109
|
}
|
package/package.json
CHANGED