@altiuslabs/tx-sdk 0.1.12 → 0.1.14
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/package.json +3 -3
- package/src/rpc.js +2 -2
- package/src/transaction.js +38 -33
- package/src/utils.js +4 -45
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@altiuslabs/tx-sdk",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.14",
|
|
4
4
|
"description": "SDK for signing and sending Altius USD multi-token transactions",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/index.js",
|
|
@@ -19,9 +19,9 @@
|
|
|
19
19
|
"signer"
|
|
20
20
|
],
|
|
21
21
|
"dependencies": {
|
|
22
|
+
"ethereumjs-util": "^7.1.5",
|
|
22
23
|
"js-sha3": "^0.9.3",
|
|
23
|
-
"noble-secp256k1": "^1.2.14"
|
|
24
|
-
"rlp": "^3.0.0"
|
|
24
|
+
"noble-secp256k1": "^1.2.14"
|
|
25
25
|
},
|
|
26
26
|
"author": "",
|
|
27
27
|
"license": "MIT"
|
package/src/rpc.js
CHANGED
|
@@ -71,7 +71,7 @@ export class RpcClient {
|
|
|
71
71
|
*/
|
|
72
72
|
async get_balance(address) {
|
|
73
73
|
const hex = await this.request('eth_getBalance', [address, 'latest']);
|
|
74
|
-
return BigInt(hex);
|
|
74
|
+
return hex && hex !== '0x' ? BigInt(hex) : 0n;
|
|
75
75
|
}
|
|
76
76
|
|
|
77
77
|
/**
|
|
@@ -141,7 +141,7 @@ export class RpcClient {
|
|
|
141
141
|
// ERC20 balanceOf selector: 0x70a08231
|
|
142
142
|
const data = '0x70a08231' + pad_hex(owner_address, 32).slice(2);
|
|
143
143
|
const result = await this.call({ to: token_address, data });
|
|
144
|
-
return BigInt(result);
|
|
144
|
+
return result && result !== '0x' ? BigInt(result) : 0n;
|
|
145
145
|
}
|
|
146
146
|
}
|
|
147
147
|
|
package/src/transaction.js
CHANGED
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
|
|
5
5
|
import { keccak256, pad_hex, num_to_hex, rlp_encode } from './utils.js';
|
|
6
6
|
|
|
7
|
+
const RLP = require('ethereumjs-util').rlp;
|
|
8
|
+
|
|
7
9
|
/**
|
|
8
10
|
* Magic byte for fee payer signature (0x7B)
|
|
9
11
|
*/
|
|
@@ -182,26 +184,25 @@ export class TxBuilder {
|
|
|
182
184
|
|
|
183
185
|
// For 0x7a transaction, encode fields WITHOUT fee_payer_signature (matches node's encode_for_signing)
|
|
184
186
|
// Format: [chainId, nonce, maxPriorityFeePerGas, maxFeePerGas, gasLimit, to, value, input, accessList, feeToken, feePayer, maxFeePerGasUsdAttodollars]
|
|
187
|
+
// IMPORTANT: Use Buffer for addresses and data to match Rust alloy-rlp encoding
|
|
185
188
|
const list = [
|
|
186
|
-
tx.chain_id,
|
|
187
|
-
tx.nonce,
|
|
188
|
-
tx.max_priority_fee_per_gas,
|
|
189
|
-
tx.max_fee_per_gas,
|
|
190
|
-
tx.gas_limit,
|
|
191
|
-
tx.to,
|
|
192
|
-
tx.value,
|
|
193
|
-
tx.data,
|
|
194
|
-
// Empty access list
|
|
195
|
-
|
|
196
|
-
tx.
|
|
197
|
-
tx.
|
|
198
|
-
tx.max_fee_per_gas_usd_attodollars,
|
|
189
|
+
BigInt(tx.chain_id),
|
|
190
|
+
BigInt(tx.nonce),
|
|
191
|
+
BigInt(tx.max_priority_fee_per_gas),
|
|
192
|
+
BigInt(tx.max_fee_per_gas),
|
|
193
|
+
BigInt(tx.gas_limit),
|
|
194
|
+
Buffer.from(tx.to.slice(2), 'hex'), // address as 20-byte buffer
|
|
195
|
+
BigInt(tx.value),
|
|
196
|
+
Buffer.from(tx.data.slice(2), 'hex') || Buffer.alloc(0), // data as buffer
|
|
197
|
+
[], // Empty access list
|
|
198
|
+
Buffer.from(tx.fee_token.slice(2), 'hex'), // fee_token as buffer
|
|
199
|
+
Buffer.from(tx.fee_payer.slice(2), 'hex'), // fee_payer as buffer
|
|
200
|
+
BigInt(tx.max_fee_per_gas_usd_attodollars),
|
|
199
201
|
];
|
|
200
202
|
|
|
201
203
|
// Encode with type byte 0x7a prefix (matches node's encode_for_signing)
|
|
202
|
-
const
|
|
203
|
-
const
|
|
204
|
-
const with_type = type_byte + encoded.slice(2);
|
|
204
|
+
const rlp_buf = RLP.encode(list);
|
|
205
|
+
const with_type = '0x7a' + rlp_buf.toString('hex');
|
|
205
206
|
|
|
206
207
|
return keccak256(with_type);
|
|
207
208
|
}
|
|
@@ -220,32 +221,36 @@ export class TxBuilder {
|
|
|
220
221
|
|
|
221
222
|
const tx = this.build();
|
|
222
223
|
|
|
224
|
+
// Convert r, s to 32-byte buffers
|
|
225
|
+
const rBuffer = Buffer.from(sig.r.slice(2), 'hex');
|
|
226
|
+
const sBuffer = Buffer.from(sig.s.slice(2), 'hex');
|
|
227
|
+
|
|
223
228
|
// Build signed transaction list (for EIP-2718 encoding)
|
|
224
229
|
// Format matches node's rlp_encode_fields: [chainId, nonce, ..., feePayerSignature, signature]
|
|
230
|
+
// IMPORTANT: Use Buffer for addresses and data to match Rust alloy-rlp encoding
|
|
225
231
|
const signed_fields = [
|
|
226
|
-
tx.chain_id,
|
|
227
|
-
tx.nonce,
|
|
228
|
-
tx.max_priority_fee_per_gas,
|
|
229
|
-
tx.max_fee_per_gas,
|
|
230
|
-
tx.gas_limit,
|
|
231
|
-
tx.to,
|
|
232
|
-
tx.value,
|
|
233
|
-
tx.data,
|
|
232
|
+
BigInt(tx.chain_id),
|
|
233
|
+
BigInt(tx.nonce),
|
|
234
|
+
BigInt(tx.max_priority_fee_per_gas),
|
|
235
|
+
BigInt(tx.max_fee_per_gas),
|
|
236
|
+
BigInt(tx.gas_limit),
|
|
237
|
+
Buffer.from(tx.to.slice(2), 'hex'), // address as 20-byte buffer
|
|
238
|
+
BigInt(tx.value),
|
|
239
|
+
Buffer.from(tx.data.slice(2), 'hex') || Buffer.alloc(0), // data as buffer
|
|
234
240
|
[], // empty access list
|
|
235
|
-
tx.fee_token,
|
|
236
|
-
tx.fee_payer,
|
|
237
|
-
tx.max_fee_per_gas_usd_attodollars,
|
|
238
|
-
tx.fee_payer_signature,
|
|
241
|
+
Buffer.from(tx.fee_token.slice(2), 'hex'), // fee_token as buffer
|
|
242
|
+
Buffer.from(tx.fee_payer.slice(2), 'hex'), // fee_payer as buffer
|
|
243
|
+
BigInt(tx.max_fee_per_gas_usd_attodollars),
|
|
244
|
+
Buffer.from(tx.fee_payer_signature?.slice(2) || '', 'hex') || Buffer.alloc(0),
|
|
239
245
|
// Signature: y_parity (1 byte), r (32 bytes), s (32 bytes)
|
|
240
246
|
y_parity,
|
|
241
|
-
|
|
242
|
-
|
|
247
|
+
rBuffer,
|
|
248
|
+
sBuffer,
|
|
243
249
|
];
|
|
244
250
|
|
|
245
251
|
// EIP-2718: first byte is type (0x7a), then RLP encoded fields
|
|
246
|
-
const
|
|
247
|
-
const
|
|
248
|
-
const raw_transaction = type_byte + rlp_fields.slice(2); // Remove 0x prefix from RLP output
|
|
252
|
+
const rlp_fields_buf = RLP.encode(signed_fields);
|
|
253
|
+
const raw_transaction = '0x7a' + rlp_fields_buf.toString('hex');
|
|
249
254
|
|
|
250
255
|
const transaction_hash = keccak256(raw_transaction);
|
|
251
256
|
|
package/src/utils.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
import sha3 from 'js-sha3';
|
|
6
|
-
import RLP from '
|
|
6
|
+
import { rlp as RLP } from 'ethereumjs-util';
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* Compute keccak256 hash
|
|
@@ -38,55 +38,14 @@ export function num_to_hex(num, bytes = 32) {
|
|
|
38
38
|
return pad_hex('0x' + hex, bytes);
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
-
/**
|
|
42
|
-
* Convert a value to RLP-compatible Buffer
|
|
43
|
-
* @param {any} value - Value to convert
|
|
44
|
-
* @returns {Buffer} RLP-compatible buffer
|
|
45
|
-
*/
|
|
46
|
-
function toRlpBytes(value) {
|
|
47
|
-
if (Buffer.isBuffer(value)) {
|
|
48
|
-
return value;
|
|
49
|
-
}
|
|
50
|
-
if (typeof value === 'string') {
|
|
51
|
-
// Hex string
|
|
52
|
-
if (value.startsWith('0x')) {
|
|
53
|
-
return Buffer.from(value.slice(2), 'hex');
|
|
54
|
-
}
|
|
55
|
-
return Buffer.from(value);
|
|
56
|
-
}
|
|
57
|
-
if (typeof value === 'number' || typeof value === 'bigint') {
|
|
58
|
-
// Convert number/bigint to big-endian bytes
|
|
59
|
-
const bigIntValue = BigInt(value);
|
|
60
|
-
if (bigIntValue === 0n) {
|
|
61
|
-
return Buffer.from([]);
|
|
62
|
-
}
|
|
63
|
-
const hex = bigIntValue.toString(16);
|
|
64
|
-
// RLP encodes integers as big-endian without leading zeros (except for zero itself)
|
|
65
|
-
return Buffer.from(hex, 'hex');
|
|
66
|
-
}
|
|
67
|
-
if (Array.isArray(value)) {
|
|
68
|
-
// For empty arrays, return empty buffer
|
|
69
|
-
if (value.length === 0) {
|
|
70
|
-
return Buffer.from([]);
|
|
71
|
-
}
|
|
72
|
-
// Recursively encode array items
|
|
73
|
-
const encodedItems = value.map(item => toRlpBytes(item));
|
|
74
|
-
return Buffer.concat(encodedItems);
|
|
75
|
-
}
|
|
76
|
-
// Default: stringify
|
|
77
|
-
return Buffer.from(String(value));
|
|
78
|
-
}
|
|
79
|
-
|
|
80
41
|
/**
|
|
81
42
|
* RLP encoding (for 0x7a transactions)
|
|
82
|
-
* @param {Array} items - Array of items to encode
|
|
43
|
+
* @param {Array} items - Array of items to encode (numbers, bigints, strings, Buffers, arrays)
|
|
83
44
|
* @returns {string} RLP encoded data as 0x-prefixed hex
|
|
84
45
|
*/
|
|
85
46
|
export function rlp_encode(items) {
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
const encoded = RLP.encode(buffers);
|
|
89
|
-
return '0x' + Buffer.from(encoded).toString('hex');
|
|
47
|
+
const encoded = RLP.encode(items);
|
|
48
|
+
return '0x' + encoded.toString('hex');
|
|
90
49
|
}
|
|
91
50
|
|
|
92
51
|
/**
|