@pushchain/core 6.0.20 → 6.0.21
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 +48 -0
- package/package.json +1 -1
- package/src/lib/cache/cache.js +2 -0
- package/src/lib/constants/abi/index.d.ts +1 -0
- package/src/lib/constants/abi/index.js +8 -1
- package/src/lib/constants/abi/pc20.evm.d.ts +217 -0
- package/src/lib/constants/abi/pc20.evm.js +150 -0
- package/src/lib/constants/abi/prc20.evm.d.ts +172 -0
- package/src/lib/constants/abi/prc20.evm.js +97 -0
- package/src/lib/constants/abi/universalGatewayV0.json +1 -1
- package/src/lib/constants/chain.js +38 -8
- package/src/lib/constants/selectors.js +2 -2
- package/src/lib/constants/tokens.js +4 -3
- package/src/lib/formatters.js +16 -6
- package/src/lib/generated/uexecutor/v1/query.js +2 -4
- package/src/lib/generated/uexecutor/v1/types.d.ts +14 -0
- package/src/lib/generated/uexecutor/v1/types.js +90 -47
- package/src/lib/generated/uexecutor/v2/query.js +2 -4
- package/src/lib/generated/uexecutor/v2/types.d.ts +20 -0
- package/src/lib/generated/uexecutor/v2/types.js +49 -33
- package/src/lib/generated/v1/tx.js +30 -37
- package/src/lib/index.d.ts +3 -0
- package/src/lib/index.js +21 -3
- package/src/lib/internal/buffer.js +1 -2
- package/src/lib/orchestrator/cea-utils.js +73 -83
- package/src/lib/orchestrator/internals/account-manager.js +130 -139
- package/src/lib/orchestrator/internals/cascade.d.ts +0 -6
- package/src/lib/orchestrator/internals/cascade.js +1184 -1059
- package/src/lib/orchestrator/internals/confirmation.js +138 -148
- package/src/lib/orchestrator/internals/error-decoder.js +1 -1
- package/src/lib/orchestrator/internals/errors.js +12 -3
- package/src/lib/orchestrator/internals/execute-funds-only.d.ts +2 -2
- package/src/lib/orchestrator/internals/execute-funds-only.js +297 -259
- package/src/lib/orchestrator/internals/execute-funds-payload.d.ts +2 -2
- package/src/lib/orchestrator/internals/execute-funds-payload.js +220 -220
- package/src/lib/orchestrator/internals/execute-standard.d.ts +0 -8
- package/src/lib/orchestrator/internals/execute-standard.js +339 -342
- package/src/lib/orchestrator/internals/gas-calculator.js +497 -520
- package/src/lib/orchestrator/internals/gas-usd-sizer.js +101 -110
- package/src/lib/orchestrator/internals/gateway-client.js +102 -103
- package/src/lib/orchestrator/internals/helpers.js +30 -27
- package/src/lib/orchestrator/internals/inbound-tracker.js +234 -238
- package/src/lib/orchestrator/internals/outbound-sync.js +463 -452
- package/src/lib/orchestrator/internals/outbound-tracker.js +27 -34
- package/src/lib/orchestrator/internals/payload-builder.d.ts +2 -2
- package/src/lib/orchestrator/internals/payload-builder.js +119 -100
- package/src/lib/orchestrator/internals/pc-usd-oracle.js +121 -129
- package/src/lib/orchestrator/internals/pc20/address-codec.d.ts +31 -0
- package/src/lib/orchestrator/internals/pc20/address-codec.js +124 -0
- package/src/lib/orchestrator/internals/pc20/chain-namespace.d.ts +68 -0
- package/src/lib/orchestrator/internals/pc20/chain-namespace.js +136 -0
- package/src/lib/orchestrator/internals/pc20/errors.d.ts +160 -0
- package/src/lib/orchestrator/internals/pc20/errors.js +236 -0
- package/src/lib/orchestrator/internals/pc20/export.d.ts +172 -0
- package/src/lib/orchestrator/internals/pc20/export.js +412 -0
- package/src/lib/orchestrator/internals/pc20/gate.d.ts +67 -0
- package/src/lib/orchestrator/internals/pc20/gate.js +184 -0
- package/src/lib/orchestrator/internals/pc20/resolver.d.ts +187 -0
- package/src/lib/orchestrator/internals/pc20/resolver.js +658 -0
- package/src/lib/orchestrator/internals/pc20/svm.d.ts +189 -0
- package/src/lib/orchestrator/internals/pc20/svm.js +286 -0
- package/src/lib/orchestrator/internals/pc20/tracking.d.ts +46 -0
- package/src/lib/orchestrator/internals/pc20/tracking.js +109 -0
- package/src/lib/orchestrator/internals/preflight.js +1 -1
- package/src/lib/orchestrator/internals/progress-route-hooks.js +2 -2
- package/src/lib/orchestrator/internals/push-chain-tx.js +319 -329
- package/src/lib/orchestrator/internals/quote.js +90 -94
- package/src/lib/orchestrator/internals/rescue.js +76 -79
- package/src/lib/orchestrator/internals/response-builder.d.ts +28 -1
- package/src/lib/orchestrator/internals/response-builder.js +817 -701
- package/src/lib/orchestrator/internals/route-handlers.d.ts +7 -15
- package/src/lib/orchestrator/internals/route-handlers.js +1512 -1178
- package/src/lib/orchestrator/internals/signing.js +78 -83
- package/src/lib/orchestrator/internals/svm-bridge.d.ts +2 -2
- package/src/lib/orchestrator/internals/svm-bridge.js +161 -93
- package/src/lib/orchestrator/internals/svm-helpers.d.ts +15 -1
- package/src/lib/orchestrator/internals/svm-helpers.js +68 -24
- package/src/lib/orchestrator/internals/svm-rent.d.ts +19 -1
- package/src/lib/orchestrator/internals/svm-rent.js +163 -141
- package/src/lib/orchestrator/internals/tx-transformer.js +26 -23
- package/src/lib/orchestrator/internals/uea-manager.js +89 -86
- package/src/lib/orchestrator/max-pc-for-gas.js +5 -6
- package/src/lib/orchestrator/orchestrator.js +217 -200
- package/src/lib/orchestrator/orchestrator.types.d.ts +121 -1
- package/src/lib/orchestrator/orchestrator.types.js +19 -0
- package/src/lib/orchestrator/payload-builders.d.ts +2 -2
- package/src/lib/orchestrator/payload-builders.js +26 -24
- package/src/lib/orchestrator/route-detector.js +26 -9
- package/src/lib/orchestrator/svm-idl/ix-encoder.js +1 -2
- package/src/lib/orchestrator/svm-idl/normalize-address.js +2 -2
- package/src/lib/orchestrator/svm-idl/resolve.js +1 -2
- package/src/lib/price-fetch/price-fetch.js +67 -68
- package/src/lib/progress-hook/progress-hook.js +124 -72
- package/src/lib/push-chain/push-chain.js +171 -153
- package/src/lib/push-client/push-client.js +223 -237
- package/src/lib/universal/account/account.js +349 -365
- package/src/lib/universal/signer/signer.js +306 -294
- package/src/lib/universal-tx-detector/auto-detect.js +55 -60
- package/src/lib/universal-tx-detector/cascade.js +160 -172
- package/src/lib/universal-tx-detector/child-inbounds.js +67 -75
- package/src/lib/universal-tx-detector/classify.js +2 -3
- package/src/lib/universal-tx-detector/detector-svm.js +139 -147
- package/src/lib/universal-tx-detector/detector.js +145 -157
- package/src/lib/universal-tx-detector/normalize.js +7 -7
- package/src/lib/utils/external-tx-hash.js +1 -2
- package/src/lib/utils.d.ts +44 -0
- package/src/lib/utils.js +762 -683
- package/src/lib/vm-client/evm-client.js +186 -202
- package/src/lib/vm-client/svm-client.d.ts +1 -1
- package/src/lib/vm-client/svm-client.js +220 -224
- package/src/lib/vm-client/vm-client.types.d.ts +14 -2
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.SvmClient = void 0;
|
|
4
|
-
const tslib_1 = require("tslib");
|
|
5
4
|
const web3_js_1 = require("@solana/web3.js");
|
|
6
5
|
const anchor_1 = require("@coral-xyz/anchor");
|
|
7
6
|
const bs58_1 = require("../internal/bs58");
|
|
@@ -11,8 +10,9 @@ const ALT_ADDRESS = new web3_js_1.PublicKey('EWXJ1ERkMwizmSovjtQ2qBTDpm1vxrZZ4Y2
|
|
|
11
10
|
* Solana-compatible VM client for reading and writing SVM-based chains.
|
|
12
11
|
*/
|
|
13
12
|
class SvmClient {
|
|
13
|
+
connections;
|
|
14
|
+
currentConnectionIndex = 0;
|
|
14
15
|
constructor({ rpcUrls }) {
|
|
15
|
-
this.currentConnectionIndex = 0;
|
|
16
16
|
if (!rpcUrls || rpcUrls.length === 0) {
|
|
17
17
|
throw new Error('At least one RPC URL must be provided');
|
|
18
18
|
}
|
|
@@ -21,35 +21,33 @@ class SvmClient {
|
|
|
21
21
|
/**
|
|
22
22
|
* Executes a function with automatic fallback to next RPC endpoint on failure
|
|
23
23
|
*/
|
|
24
|
-
executeWithFallback(
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
this.currentConnectionIndex = connectionIndex;
|
|
37
|
-
}
|
|
38
|
-
return result;
|
|
24
|
+
async executeWithFallback(operation, operationName = 'operation') {
|
|
25
|
+
let lastError = null;
|
|
26
|
+
// Try each connection starting from current index
|
|
27
|
+
for (let attempt = 0; attempt < this.connections.length; attempt++) {
|
|
28
|
+
const connectionIndex = (this.currentConnectionIndex + attempt) % this.connections.length;
|
|
29
|
+
const connection = this.connections[connectionIndex];
|
|
30
|
+
try {
|
|
31
|
+
const result = await operation(connection);
|
|
32
|
+
// Success - update current connection index if we switched
|
|
33
|
+
if (connectionIndex !== this.currentConnectionIndex) {
|
|
34
|
+
//console.log(`Switched to RPC endpoint ${connectionIndex + 1}: ${this.rpcUrls[connectionIndex]}`);
|
|
35
|
+
this.currentConnectionIndex = connectionIndex;
|
|
39
36
|
}
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
yield new Promise((resolve) => setTimeout(resolve, 100));
|
|
37
|
+
return result;
|
|
38
|
+
}
|
|
39
|
+
catch (error) {
|
|
40
|
+
lastError = error;
|
|
41
|
+
//console.warn(`RPC endpoint ${connectionIndex + 1} failed for ${operationName}:`, error);
|
|
42
|
+
// If this was our last attempt, throw the error
|
|
43
|
+
if (attempt === this.connections.length - 1) {
|
|
44
|
+
break;
|
|
49
45
|
}
|
|
46
|
+
// Wait a bit before trying next endpoint
|
|
47
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
50
48
|
}
|
|
51
|
-
|
|
52
|
-
});
|
|
49
|
+
}
|
|
50
|
+
throw new Error(`All RPC endpoints failed for ${operationName}. Last error: ${lastError?.message}`);
|
|
53
51
|
}
|
|
54
52
|
/** Build an AnchorProvider; if a signer is passed we wrap it, otherwise we give a no-op wallet. */
|
|
55
53
|
createProvider(connection, signer) {
|
|
@@ -59,8 +57,8 @@ class SvmClient {
|
|
|
59
57
|
wallet = {
|
|
60
58
|
publicKey: feePayerPk,
|
|
61
59
|
payer: signer.account,
|
|
62
|
-
signTransaction: (tx) =>
|
|
63
|
-
signAllTransactions: (txs) =>
|
|
60
|
+
signTransaction: async (tx) => tx,
|
|
61
|
+
signAllTransactions: async (txs) => txs,
|
|
64
62
|
};
|
|
65
63
|
}
|
|
66
64
|
else {
|
|
@@ -69,8 +67,8 @@ class SvmClient {
|
|
|
69
67
|
wallet = {
|
|
70
68
|
publicKey: kp.publicKey,
|
|
71
69
|
payer: kp,
|
|
72
|
-
signTransaction: (tx) =>
|
|
73
|
-
signAllTransactions: (txs) =>
|
|
70
|
+
signTransaction: async (tx) => tx,
|
|
71
|
+
signAllTransactions: async (txs) => txs,
|
|
74
72
|
};
|
|
75
73
|
}
|
|
76
74
|
return new anchor_1.AnchorProvider(connection, wallet, {
|
|
@@ -80,227 +78,225 @@ class SvmClient {
|
|
|
80
78
|
/**
|
|
81
79
|
* Returns the balance (in lamports) of a Solana address.
|
|
82
80
|
*/
|
|
83
|
-
getBalance(address) {
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
return BigInt(lamports);
|
|
88
|
-
});
|
|
81
|
+
async getBalance(address) {
|
|
82
|
+
const pubkey = new web3_js_1.PublicKey(address);
|
|
83
|
+
const lamports = await this.executeWithFallback((connection) => connection.getBalance(pubkey), 'getBalance');
|
|
84
|
+
return BigInt(lamports);
|
|
89
85
|
}
|
|
90
86
|
/**
|
|
91
87
|
* Reads a full program account using Anchor IDL.
|
|
92
88
|
* `functionName` must match the account layout name in the IDL.
|
|
93
89
|
*/
|
|
94
|
-
readContract(
|
|
95
|
-
return
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
}), 'readContract');
|
|
107
|
-
});
|
|
90
|
+
async readContract({ abi, functionName, args = [], }) {
|
|
91
|
+
return this.executeWithFallback(async (connection) => {
|
|
92
|
+
const provider = this.createProvider(connection);
|
|
93
|
+
// Anchor v0.31 constructor no longer takes programId
|
|
94
|
+
// Use the IDL's embedded metadata.address instead
|
|
95
|
+
const program = new anchor_1.Program(abi, provider);
|
|
96
|
+
const pubkey = new web3_js_1.PublicKey(args[0]);
|
|
97
|
+
// Cast account namespace to any to allow dynamic string
|
|
98
|
+
const accountNamespace = program.account;
|
|
99
|
+
const account = await accountNamespace[functionName].fetch(pubkey);
|
|
100
|
+
return account;
|
|
101
|
+
}, 'readContract');
|
|
108
102
|
}
|
|
109
103
|
/**
|
|
110
104
|
* Sends a Solana transaction using a smart contract instruction.
|
|
111
105
|
*/
|
|
112
|
-
writeContract(
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
106
|
+
async writeContract({ abi, signer, functionName, args = [], accounts = {}, extraSigners = [], remainingAccounts = [], }) {
|
|
107
|
+
// 1. Grab or build your RPC connection however your class manages it
|
|
108
|
+
const connection = this.connections[this.currentConnectionIndex];
|
|
109
|
+
// 2. Create an AnchorProvider
|
|
110
|
+
const provider = this.createProvider(connection);
|
|
111
|
+
// 3. Instantiate the program (Anchor v0.31 will infer programId from IDL.metadata.address)
|
|
112
|
+
const program = new anchor_1.Program(abi, provider);
|
|
113
|
+
// 4. Deep-convert arguments into Anchor-friendly types
|
|
114
|
+
// - BigInt -> BN
|
|
115
|
+
// - hex strings (0x...) -> Buffer
|
|
116
|
+
// - Uint8Array -> Buffer
|
|
117
|
+
// - UniversalPayload object normalization (to/data/vType)
|
|
118
|
+
const anchorify = (value) => {
|
|
119
|
+
// Preserve BN, Buffer, PublicKey, null/undefined
|
|
120
|
+
if (value === null ||
|
|
121
|
+
value === undefined ||
|
|
122
|
+
value instanceof anchor_1.BN ||
|
|
123
|
+
Buffer.isBuffer(value) ||
|
|
124
|
+
value instanceof web3_js_1.PublicKey)
|
|
125
|
+
return value;
|
|
126
|
+
// BigInt -> BN
|
|
127
|
+
if (typeof value === 'bigint')
|
|
128
|
+
return new anchor_1.BN(value.toString());
|
|
129
|
+
// Hex string -> Buffer
|
|
130
|
+
if (typeof value === 'string' && value.startsWith('0x')) {
|
|
131
|
+
const hex = value.slice(2);
|
|
132
|
+
if (hex.length === 0)
|
|
133
|
+
return Buffer.alloc(0);
|
|
134
|
+
// If odd length, left-pad a 0
|
|
135
|
+
const normalized = hex.length % 2 === 1 ? `0${hex}` : hex;
|
|
136
|
+
return Buffer.from(normalized, 'hex');
|
|
137
|
+
}
|
|
138
|
+
// Uint8Array -> Buffer
|
|
139
|
+
if (value instanceof Uint8Array)
|
|
140
|
+
return Buffer.from(value);
|
|
141
|
+
// Array -> map recursively
|
|
142
|
+
if (Array.isArray(value))
|
|
143
|
+
return value.map((v) => anchorify(v));
|
|
144
|
+
// Plain object -> recurse and normalize UniversalPayload shape
|
|
145
|
+
if (typeof value === 'object') {
|
|
146
|
+
const obj = value;
|
|
147
|
+
const out = {};
|
|
148
|
+
for (const [k, v] of Object.entries(obj)) {
|
|
149
|
+
out[k] = anchorify(v);
|
|
144
150
|
}
|
|
145
|
-
//
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
151
|
+
// Heuristic: normalize UniversalPayload fields expected by Anchor IDL
|
|
152
|
+
const hasUniversalPayloadKeys = 'to' in out &&
|
|
153
|
+
'value' in out &&
|
|
154
|
+
'data' in out &&
|
|
155
|
+
'gasLimit' in out &&
|
|
156
|
+
'maxFeePerGas' in out &&
|
|
157
|
+
'maxPriorityFeePerGas' in out &&
|
|
158
|
+
'nonce' in out &&
|
|
159
|
+
'deadline' in out &&
|
|
160
|
+
'vType' in out;
|
|
161
|
+
if (hasUniversalPayloadKeys) {
|
|
162
|
+
// to: address(20 bytes) -> Buffer(20)
|
|
163
|
+
if (typeof obj['to'] === 'string' && obj['to'].startsWith('0x')) {
|
|
164
|
+
const hex = obj['to'].slice(2).padStart(40, '0');
|
|
165
|
+
out['to'] = Buffer.from(hex, 'hex');
|
|
166
|
+
}
|
|
167
|
+
// data: bytes -> Buffer
|
|
168
|
+
if (typeof obj['data'] === 'string' && obj['data'].startsWith('0x')) {
|
|
169
|
+
const hex = obj['data'].slice(2);
|
|
170
|
+
out['data'] = hex.length
|
|
171
|
+
? Buffer.from(hex, 'hex')
|
|
172
|
+
: Buffer.alloc(0);
|
|
157
173
|
}
|
|
158
|
-
//
|
|
159
|
-
const
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
'
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
if (typeof val === 'string' && /^[0-9]+$/.test(val))
|
|
186
|
-
return new anchor_1.BN(val);
|
|
187
|
-
return val;
|
|
188
|
-
};
|
|
189
|
-
out['value'] = numericStringToBn(out['value']);
|
|
190
|
-
out['gasLimit'] = numericStringToBn(out['gasLimit']);
|
|
191
|
-
out['maxFeePerGas'] = numericStringToBn(out['maxFeePerGas']);
|
|
192
|
-
out['maxPriorityFeePerGas'] = numericStringToBn(out['maxPriorityFeePerGas']);
|
|
193
|
-
out['nonce'] = numericStringToBn(out['nonce']);
|
|
194
|
-
out['deadline'] = numericStringToBn(out['deadline']);
|
|
195
|
-
// vType: enum -> Anchor enum object
|
|
196
|
-
if (typeof obj['vType'] === 'number') {
|
|
197
|
-
out['vType'] =
|
|
198
|
-
obj['vType'] === 0
|
|
199
|
-
? { signedVerification: {} }
|
|
200
|
-
: { universalTxVerification: {} };
|
|
201
|
-
}
|
|
202
|
-
else if (typeof obj['vType'] === 'string') {
|
|
203
|
-
const vt = obj['vType'].toLowerCase();
|
|
204
|
-
if (vt.includes('signed'))
|
|
205
|
-
out['vType'] = { signedVerification: {} };
|
|
206
|
-
else
|
|
207
|
-
out['vType'] = { universalTxVerification: {} };
|
|
208
|
-
}
|
|
174
|
+
// numeric fields (often provided as decimal strings from protobuf/JSON) -> BN
|
|
175
|
+
const numericStringToBn = (val) => {
|
|
176
|
+
if (typeof val === 'bigint')
|
|
177
|
+
return new anchor_1.BN(val.toString());
|
|
178
|
+
if (typeof val === 'string' && /^[0-9]+$/.test(val))
|
|
179
|
+
return new anchor_1.BN(val);
|
|
180
|
+
return val;
|
|
181
|
+
};
|
|
182
|
+
out['value'] = numericStringToBn(out['value']);
|
|
183
|
+
out['gasLimit'] = numericStringToBn(out['gasLimit']);
|
|
184
|
+
out['maxFeePerGas'] = numericStringToBn(out['maxFeePerGas']);
|
|
185
|
+
out['maxPriorityFeePerGas'] = numericStringToBn(out['maxPriorityFeePerGas']);
|
|
186
|
+
out['nonce'] = numericStringToBn(out['nonce']);
|
|
187
|
+
out['deadline'] = numericStringToBn(out['deadline']);
|
|
188
|
+
// vType: enum -> Anchor enum object
|
|
189
|
+
if (typeof obj['vType'] === 'number') {
|
|
190
|
+
out['vType'] =
|
|
191
|
+
obj['vType'] === 0
|
|
192
|
+
? { signedVerification: {} }
|
|
193
|
+
: { universalTxVerification: {} };
|
|
194
|
+
}
|
|
195
|
+
else if (typeof obj['vType'] === 'string') {
|
|
196
|
+
const vt = obj['vType'].toLowerCase();
|
|
197
|
+
if (vt.includes('signed'))
|
|
198
|
+
out['vType'] = { signedVerification: {} };
|
|
199
|
+
else
|
|
200
|
+
out['vType'] = { universalTxVerification: {} };
|
|
209
201
|
}
|
|
210
|
-
return out;
|
|
211
202
|
}
|
|
212
|
-
return
|
|
213
|
-
};
|
|
214
|
-
const convertedArgs = anchorify(args);
|
|
215
|
-
// 5. Build the method call
|
|
216
|
-
let builder = Array.isArray(convertedArgs) && convertedArgs.length > 0
|
|
217
|
-
? program.methods[functionName](...convertedArgs)
|
|
218
|
-
: program.methods[functionName]();
|
|
219
|
-
if (Object.keys(accounts).length > 0) {
|
|
220
|
-
builder = builder.accounts(accounts);
|
|
203
|
+
return out;
|
|
221
204
|
}
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
205
|
+
return value;
|
|
206
|
+
};
|
|
207
|
+
const convertedArgs = anchorify(args);
|
|
208
|
+
// 5. Build the method call
|
|
209
|
+
let builder = Array.isArray(convertedArgs) && convertedArgs.length > 0
|
|
210
|
+
? program.methods[functionName](...convertedArgs)
|
|
211
|
+
: program.methods[functionName]();
|
|
212
|
+
if (Object.keys(accounts).length > 0) {
|
|
213
|
+
builder = builder.accounts(accounts);
|
|
214
|
+
}
|
|
215
|
+
// Positional accounts appended after the instruction's named accounts.
|
|
216
|
+
// Order and flags are program-defined (e.g. the PC20 burn requires
|
|
217
|
+
// [pc20_state readonly, pc20_mint writable]) and must be passed exactly.
|
|
218
|
+
if (remainingAccounts.length > 0) {
|
|
219
|
+
builder = builder.remainingAccounts(remainingAccounts.map((a) => ({
|
|
220
|
+
pubkey: a.pubkey,
|
|
221
|
+
isSigner: a.isSigner,
|
|
222
|
+
isWritable: a.isWritable,
|
|
223
|
+
})));
|
|
224
|
+
}
|
|
225
|
+
// 6. Get the actual instruction
|
|
226
|
+
const instruction = await builder.instruction();
|
|
227
|
+
// 7. Send it and return the tx signature
|
|
228
|
+
return this.sendTransaction({
|
|
229
|
+
instruction,
|
|
230
|
+
signer,
|
|
231
|
+
extraSigners,
|
|
230
232
|
});
|
|
231
233
|
}
|
|
232
234
|
/**
|
|
233
235
|
* Sends a set of instructions as a manually-signed Solana transaction.
|
|
234
236
|
*/
|
|
235
|
-
sendTransaction(
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
return bs58_1.bs58.encode(Buffer.from(txHashBytes)); // Clean, readable tx hash
|
|
260
|
-
});
|
|
237
|
+
async sendTransaction({ instruction, signer, extraSigners = [], }) {
|
|
238
|
+
const connection = this.connections[this.currentConnectionIndex];
|
|
239
|
+
const feePayer = new web3_js_1.PublicKey(signer.account.address);
|
|
240
|
+
// Prefer an ALT-backed v0 transaction to avoid Solana's 1232-byte legacy limit
|
|
241
|
+
const { value: alt } = await connection.getAddressLookupTable(ALT_ADDRESS);
|
|
242
|
+
if (!alt) {
|
|
243
|
+
throw new Error(`Lookup table ${ALT_ADDRESS.toBase58()} not found on chain`);
|
|
244
|
+
}
|
|
245
|
+
const { blockhash } = await connection.getLatestBlockhash('finalized');
|
|
246
|
+
const messageV0 = new web3_js_1.TransactionMessage({
|
|
247
|
+
payerKey: feePayer,
|
|
248
|
+
recentBlockhash: blockhash,
|
|
249
|
+
instructions: [instruction],
|
|
250
|
+
}).compileToV0Message([alt]);
|
|
251
|
+
const vtx = new web3_js_1.VersionedTransaction(messageV0);
|
|
252
|
+
if (extraSigners.length > 0) {
|
|
253
|
+
vtx.sign(extraSigners);
|
|
254
|
+
}
|
|
255
|
+
const txBytes = vtx.serialize();
|
|
256
|
+
if (!signer.signAndSendTransaction) {
|
|
257
|
+
throw new Error('signer.signTransaction is undefined');
|
|
258
|
+
}
|
|
259
|
+
const txHashBytes = await signer.signAndSendTransaction(new Uint8Array(txBytes));
|
|
260
|
+
return bs58_1.bs58.encode(Buffer.from(txHashBytes)); // Clean, readable tx hash
|
|
261
261
|
}
|
|
262
262
|
/**
|
|
263
263
|
* Waits for a transaction to be confirmed on the blockchain.
|
|
264
264
|
*/
|
|
265
|
-
confirmTransaction(
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
if (status
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
return;
|
|
278
|
-
}
|
|
265
|
+
async confirmTransaction(signature, timeout = 30000) {
|
|
266
|
+
const startTime = Date.now();
|
|
267
|
+
return this.executeWithFallback(async (connection) => {
|
|
268
|
+
while (Date.now() - startTime < timeout) {
|
|
269
|
+
const status = await connection.getSignatureStatus(signature);
|
|
270
|
+
if (status?.value) {
|
|
271
|
+
if (status.value.err) {
|
|
272
|
+
throw new Error(`Transaction failed: ${JSON.stringify(status.value.err)}`);
|
|
273
|
+
}
|
|
274
|
+
if (status.value.confirmationStatus === 'confirmed' ||
|
|
275
|
+
status.value.confirmationStatus === 'finalized') {
|
|
276
|
+
return;
|
|
279
277
|
}
|
|
280
|
-
yield new Promise((r) => setTimeout(r, 500));
|
|
281
278
|
}
|
|
282
|
-
|
|
283
|
-
}
|
|
284
|
-
|
|
279
|
+
await new Promise((r) => setTimeout(r, 500));
|
|
280
|
+
}
|
|
281
|
+
throw new Error(`Transaction confirmation timeout after ${timeout}ms`);
|
|
282
|
+
}, 'confirmTransaction');
|
|
285
283
|
}
|
|
286
284
|
/**
|
|
287
285
|
* Estimates the fee (in lamports) to send a transaction with the given instructions.
|
|
288
286
|
*/
|
|
289
|
-
estimateGas(
|
|
290
|
-
return
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
}), 'estimateGas');
|
|
303
|
-
});
|
|
287
|
+
async estimateGas({ instructions, signer, }) {
|
|
288
|
+
return this.executeWithFallback(async (connection) => {
|
|
289
|
+
const feePayer = new web3_js_1.PublicKey(signer.account.address);
|
|
290
|
+
const { blockhash, lastValidBlockHeight } = await connection.getLatestBlockhash();
|
|
291
|
+
const tx = new web3_js_1.Transaction({ blockhash, lastValidBlockHeight, feePayer });
|
|
292
|
+
if (instructions.length)
|
|
293
|
+
tx.add(...instructions);
|
|
294
|
+
const message = tx.compileMessage();
|
|
295
|
+
const feeResp = await connection.getFeeForMessage(message);
|
|
296
|
+
if (!feeResp?.value)
|
|
297
|
+
throw new Error('Failed to estimate fee');
|
|
298
|
+
return BigInt(feeResp.value);
|
|
299
|
+
}, 'estimateGas');
|
|
304
300
|
}
|
|
305
301
|
}
|
|
306
302
|
exports.SvmClient = SvmClient;
|
|
@@ -40,13 +40,25 @@ export interface WriteContractParams extends ReadContractParams {
|
|
|
40
40
|
value?: bigint;
|
|
41
41
|
signer: UniversalSigner;
|
|
42
42
|
/**
|
|
43
|
-
* **For Solana only** Dynamic accounts to pass to the solana program
|
|
43
|
+
* **For Solana only** Dynamic accounts to pass to the solana program
|
|
44
|
+
* instruction. `null` is valid for accounts the IDL marks `optional` —
|
|
45
|
+
* Anchor substitutes the program id as the on-wire "none" placeholder.
|
|
44
46
|
*/
|
|
45
|
-
accounts?: Record<string, PublicKey>;
|
|
47
|
+
accounts?: Record<string, PublicKey | null>;
|
|
46
48
|
/**
|
|
47
49
|
* **For Solana only** Keypairs that should sign the transaction
|
|
48
50
|
*/
|
|
49
51
|
extraSigners?: Keypair[];
|
|
52
|
+
/**
|
|
53
|
+
* **For Solana only** Positional accounts appended after the instruction's
|
|
54
|
+
* named accounts. Order and flags are program-defined — e.g. the PC20 burn
|
|
55
|
+
* requires exactly `[pc20_state readonly, pc20_mint writable]`.
|
|
56
|
+
*/
|
|
57
|
+
remainingAccounts?: Array<{
|
|
58
|
+
pubkey: PublicKey;
|
|
59
|
+
isSigner: boolean;
|
|
60
|
+
isWritable: boolean;
|
|
61
|
+
}>;
|
|
50
62
|
}
|
|
51
63
|
export type TxResponse = Transaction & {
|
|
52
64
|
wait: (confirmations?: number) => Promise<TransactionReceipt>;
|