gethstorage-sdk 0.0.0-stage → 5.0.2

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.
@@ -0,0 +1,1023 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __export = (target, all) => {
3
+ for (var name in all)
4
+ __defProp(target, name, { get: all[name], enumerable: true });
5
+ };
6
+
7
+ // src/utils/index.ts
8
+ var utils_exports = {};
9
+ __export(utils_exports, {
10
+ TxSender: () => TxSender,
11
+ calcTxCost: () => calcTxCost,
12
+ getChainId: () => getChainId,
13
+ getChunkCounts: () => getChunkCounts,
14
+ getChunkHashes: () => getChunkHashes,
15
+ getContentChunk: () => getContentChunk,
16
+ getUploadInfo: () => getUploadInfo,
17
+ isBuffer: () => isBuffer,
18
+ isFile: () => isFile,
19
+ isNodejs: () => isNodejs,
20
+ stableRetry: () => stableRetry,
21
+ stringToHex: () => stringToHex
22
+ });
23
+
24
+ // src/utils/util.ts
25
+ import { ethers } from "ethers";
26
+ var stringToHex = (s) => ethers.hexlify(ethers.toUtf8Bytes(s));
27
+ async function getChainId(rpc) {
28
+ const provider = new ethers.JsonRpcProvider(rpc);
29
+ const network = await provider.getNetwork();
30
+ return Number(network.chainId);
31
+ }
32
+ async function getContentChunk(content, start, end) {
33
+ if (isBuffer(content)) {
34
+ return content.slice(start, Math.min(end, content.length));
35
+ } else {
36
+ const slice = content.slice(start, Math.min(end, content.size));
37
+ const data = await slice.arrayBuffer();
38
+ return new Uint8Array(data);
39
+ }
40
+ }
41
+ function isBuffer(content) {
42
+ return content instanceof Uint8Array;
43
+ }
44
+ function isFile(content) {
45
+ if (isNodejs()) {
46
+ return content && typeof content === "object" && typeof content.isNodeJs === "boolean" && content.isNodeJs;
47
+ } else {
48
+ return content instanceof File;
49
+ }
50
+ }
51
+ function isNodejs() {
52
+ return typeof process !== "undefined" && !!process.versions && !!process.versions.node;
53
+ }
54
+ function calcTxCost(receipt) {
55
+ if (!receipt) {
56
+ return { normalGasCost: 0n };
57
+ }
58
+ const normalGasCost = receipt.gasUsed * receipt.gasPrice;
59
+ return {
60
+ normalGasCost
61
+ };
62
+ }
63
+
64
+ // src/utils/uploader.ts
65
+ import { ethers as ethers2 } from "ethers";
66
+
67
+ // src/utils/retry.ts
68
+ var FIXED_TOTAL_RETRIES = 5;
69
+ var FIXED_BASE_DELAY = 100;
70
+ var FIXED_MAX_DELAY = 5e3;
71
+ var INTERNAL_FIXED_RETRIES = {
72
+ SOCKET: 5,
73
+ // Connection/Socket errors (high retry chance)
74
+ NETWORK: 3,
75
+ // DNS/Reachability errors
76
+ TIMEOUT: 3,
77
+ // Request timeouts
78
+ RATE_LIMIT: 5,
79
+ // 429 errors (high retry chance after delay)
80
+ SERVER: 2,
81
+ // HTTP 5xx errors
82
+ RPC_SERVER: 2,
83
+ // JSON-RPC internal errors (-32xxx)
84
+ CLIENT: 0,
85
+ // Client errors (4xx) are never retried
86
+ UNKNOWN: 1
87
+ // Unclassified errors (minimal safeguard retry)
88
+ };
89
+ function classifyError(error) {
90
+ const code = error.code || error.cause?.code || "";
91
+ const message = (error.message || error.cause?.message || "").toLowerCase();
92
+ const statusCode = error.statusCode || error.response?.statusCode;
93
+ if (["ECONNRESET", "ECONNREFUSED", "EPIPE", "ECONNABORTED"].includes(String(code))) return "SOCKET";
94
+ if (["ETIMEDOUT", "ENOTFOUND", "EHOSTUNREACH", "ENETUNREACH"].includes(String(code))) return "NETWORK";
95
+ if (message.includes("timeout") || message.includes("timed out")) return "TIMEOUT";
96
+ if (statusCode === 429 || code === 429 || message.includes("rate limit")) return "RATE_LIMIT";
97
+ if ([-32e3, -32603, -32601, -32600].includes(Number(code))) return "RPC_SERVER";
98
+ if (typeof statusCode === "number") {
99
+ if (statusCode >= 500) return "SERVER";
100
+ if (statusCode >= 400) return "CLIENT";
101
+ }
102
+ return "UNKNOWN";
103
+ }
104
+ function isRetryable(error) {
105
+ const type = classifyError(error);
106
+ if (type === "CLIENT") return false;
107
+ const retryableTypes = ["SOCKET", "NETWORK", "TIMEOUT", "RATE_LIMIT", "SERVER", "RPC_SERVER", "UNKNOWN"];
108
+ return retryableTypes.includes(type);
109
+ }
110
+ function computeDelay(attempt) {
111
+ const base = FIXED_BASE_DELAY;
112
+ const max = FIXED_MAX_DELAY;
113
+ if (attempt < 0) return base;
114
+ let delay = base * Math.pow(2, attempt);
115
+ delay = Math.min(delay, max);
116
+ const jitter = delay * 0.2 * (Math.random() * 2 - 1);
117
+ return Math.floor(Math.max(delay + jitter, 0));
118
+ }
119
+ async function stableRetry(fn, ...args) {
120
+ const totalRetries = FIXED_TOTAL_RETRIES;
121
+ const errorTypeRetries = INTERNAL_FIXED_RETRIES;
122
+ const errorTypeCount = {
123
+ SOCKET: 0,
124
+ NETWORK: 0,
125
+ TIMEOUT: 0,
126
+ RATE_LIMIT: 0,
127
+ SERVER: 0,
128
+ RPC_SERVER: 0,
129
+ CLIENT: 0,
130
+ UNKNOWN: 0
131
+ };
132
+ let lastError = {};
133
+ let totalAttempts = 0;
134
+ while (true) {
135
+ try {
136
+ return await fn(...args);
137
+ } catch (err) {
138
+ lastError = err;
139
+ totalAttempts++;
140
+ const type = classifyError(err);
141
+ if (!isRetryable(err)) {
142
+ const wrapErr = new Error(`Non-retryable error: ${err.message} (type: ${type})`);
143
+ wrapErr.cause = err;
144
+ throw wrapErr;
145
+ }
146
+ errorTypeCount[type] += 1;
147
+ const typeMax = errorTypeRetries[type] || 0;
148
+ if (errorTypeCount[type] > typeMax) {
149
+ break;
150
+ }
151
+ if (totalAttempts > totalRetries) {
152
+ break;
153
+ }
154
+ const delay = computeDelay(errorTypeCount[type] - 1);
155
+ await new Promise((r) => setTimeout(r, delay));
156
+ }
157
+ }
158
+ const lastErrorType = classifyError(lastError);
159
+ const finalError = new Error(`Retry failed after ${totalAttempts} attempts (last error type: ${lastErrorType}): ${lastError?.message || "Unknown error"}`);
160
+ finalError.cause = lastError;
161
+ throw finalError;
162
+ }
163
+
164
+ // src/param/abi.ts
165
+ var FlatDirectoryAbi = [
166
+ "constructor(uint8 slotLimit, uint32 maxChunkSize, address storageAddress) public",
167
+ "function setDefault(bytes memory _defaultFile) external",
168
+ "function writeChunkByCalldata(bytes memory name, uint256 chunkId, bytes calldata data) external payable",
169
+ "function remove(bytes memory name) external returns (uint256)",
170
+ "function truncate(bytes memory name, uint256 chunkId) external returns (uint256)",
171
+ "function readChunk(bytes memory name, uint256 chunkId) external view returns (bytes memory, bool)",
172
+ "function getUploadInfo(bytes memory name) external view returns (uint8 mode, uint256 chunkCount, uint256 storageCost)",
173
+ "function getChunkHashesBatch((bytes,uint256[])[] memory fileChunks) external view returns (bytes32[] memory)",
174
+ "function getChunkCountsBatch(bytes[] memory names) external view returns (uint256[] memory)"
175
+ ];
176
+
177
+ // src/param/constant.ts
178
+ var MAINNET_CHAIN_ID = 1;
179
+ var SEPOLIA_CHAIN_ID = 11155111;
180
+ var QUARKCHAIN_L2_TESTNET_CHAIN_ID = 3335;
181
+ var ETHSTORAGE_MAPPING = {
182
+ [MAINNET_CHAIN_ID]: "0xf0193d6E8fc186e77b6E63af4151db07524f6a7A",
183
+ [SEPOLIA_CHAIN_ID]: "0xAb3d380A268d088BA21Eb313c1C23F3BEC5cfe93",
184
+ [QUARKCHAIN_L2_TESTNET_CHAIN_ID]: "0x64003adbdf3014f7E38FC6BE752EB047b95da89A"
185
+ };
186
+ var CONTRACT_MAX_CHUNK_SIZE = (4 * 31 + 3) * 1024 - 4;
187
+ var MAX_CHUNKS = 100;
188
+ var CALLDATA_CHUNK_OVERHEAD = 326;
189
+ var DEFAULT_MAX_CHUNK_SIZE_KB = 64;
190
+ var DEFAULT_PRIORITY_FEE_PER_GAS = 100n;
191
+ var BASE_FEE_MULTIPLIER_NUMERATOR = 11n;
192
+ var BASE_FEE_MULTIPLIER_DENOMINATOR = 10n;
193
+ var LEGACY_GAS_CHAIN_IDS = /* @__PURE__ */ new Set([56, 97]);
194
+ var AVALANCHE_GAS_CHAIN_IDS = /* @__PURE__ */ new Set([43114, 43113]);
195
+ var AVALANCHE_MIN_BASE_FEE_PER_GAS = 25000000000n;
196
+ function toChunkSizeBytes(maxChunkSizeKB) {
197
+ const kb = maxChunkSizeKB && maxChunkSizeKB > 0 ? maxChunkSizeKB : DEFAULT_MAX_CHUNK_SIZE_KB;
198
+ return kb * 1024 - CALLDATA_CHUNK_OVERHEAD;
199
+ }
200
+
201
+ // src/param/bytecode.ts
202
+ var FlatDirectoryBytecode = "0x60c06040525f60a0908152600a90620000199082620001cb565b5034801562000026575f80fd5b5060405162003bb238038062003bb2833981016040819052620000499162000293565b60ff8316608052828282818133806200007b57604051631e4fbdf760e01b81525f600482015260240160405180910390fd5b6200008681620000da565b506004805463ffffffff909316600160a01b0263ffffffff60a01b1990931692909217909155600580546001600160a01b039092166001600160a01b031990921691909117905550620002f9945050505050565b600480546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a35050565b634e487b7160e01b5f52604160045260245ffd5b600181811c908216806200015457607f821691505b6020821081036200017357634e487b7160e01b5f52602260045260245ffd5b50919050565b601f821115620001c6575f81815260208120601f850160051c81016020861015620001a15750805b601f850160051c820191505b81811015620001c257828155600101620001ad565b5050505b505050565b81516001600160401b03811115620001e757620001e76200012b565b620001ff81620001f884546200013f565b8462000179565b602080601f83116001811462000235575f84156200021d5750858301515b5f19600386901b1c1916600185901b178555620001c2565b5f85815260208120601f198616915b82811015620002655788860151825594840194600190910190840162000244565b50858210156200028357878501515f19600388901b60f8161c191681555b5050505050600190811b01905550565b5f805f60608486031215620002a6575f80fd5b835160ff81168114620002b7575f80fd5b602085015190935063ffffffff81168114620002d1575f80fd5b60408501519092506001600160a01b0381168114620002ee575f80fd5b809150509250925092565b608051613899620003195f395f818161057801526124ae01526138995ff3fe60806040526004361062000211575f3560e01c8063761ab10e116200011a578063cf86bf9311620000a2578063f14c7ad7116200006c578063f14c7ad71462000850578063f2fde38b1462000867578063f53264ea146200088b578063f916c5b014620008af5762000211565b8063cf86bf9314620007b0578063d84eb56c14620007eb578063dc38b0a2146200080f578063dd473fae14620008335762000211565b8063956a343311620000e4578063956a343314620006fb578063a741f1cb146200071f578063c708dd141462000752578063caf1283614620007765762000211565b8063761ab10e146200063c5780638bf4515c146200066f5780638da5cb5b146200069357806393b7628f14620006b25762000211565b80631ccbc6da116200019e57806354fd4d50116200016857806354fd4d5014620005ae57806358edef4c14620005dd5780635ba1d9e51462000601578063715018a614620006255762000211565b80631ccbc6da146200050857806342216bed146200052e5780634db654f914620005525780634eed7cf114620005695762000211565b8063152a4bb311620001e0578063152a4bb314620004415780631a7237e014620004765780631c5ee10c14620004aa5780631c993ad514620004e45762000211565b8063038cd79f146200038e5780630936286114620003b45780631089f40f14620003e357806311ce02671462000407575b3480156200021d575f80fd5b505f366060808284036200024157505060408051602081019091525f815262000383565b83835f81811062000256576200025662002bca565b9050013560f81c60f81b6001600160f81b031916602f60f81b14620002a257505060408051808201909152600e81526d0d2dcc6dee4e4cac6e840e0c2e8d60931b602082015262000383565b8383620002b160018262002bf2565b818110620002c357620002c362002bca565b909101356001600160f81b031916602f60f81b03905062000325576200031c620002f1846001818862002c08565b600a604051602001620003079392919062002c65565b604051602081830303815290604052620008d3565b50905062000376565b6200037262000338846001818862002c08565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250620008d392505050565b5090505b620003818162000997565b505b915050805190602001f35b3480156200039a575f80fd5b50620003b2620003ac36600462002e1f565b620009ca565b005b348015620003c0575f80fd5b50620003cb620009e7565b604051620003da919062002eda565b60405180910390f35b348015620003ef575f80fd5b50620003b26200040136600462002ef5565b62000a7b565b34801562000413575f80fd5b5060055462000428906001600160a01b031681565b6040516001600160a01b039091168152602001620003da565b3480156200044d575f80fd5b50620004656200045f36600462002f1a565b62000aab565b604051620003da9392919062002f80565b34801562000482575f80fd5b506200049a6200049436600462002fa3565b62000b5e565b604051620003da92919062002fe8565b348015620004b6575f80fd5b50620004ce620004c836600462002f1a565b62000c09565b60408051928352602083019190915201620003da565b348015620004f0575f80fd5b50620003b26200050236600462002f1a565b62000cad565b34801562000514575f80fd5b506200051f62000cc9565b604051908152602001620003da565b3480156200053a575f80fd5b506200051f6200054c36600462002fa3565b62000d3c565b620003b2620005633660046200309c565b62000dd5565b34801562000575575f80fd5b507f000000000000000000000000000000000000000000000000000000000000000060ff1615155b6040519015158152602001620003da565b348015620005ba575f80fd5b506040805180820190915260058152640312e312e360dc1b6020820152620003cb565b348015620005e9575f80fd5b506200051f620005fb36600462002f1a565b62000f39565b3480156200060d575f80fd5b506200059d6200061f36600462002fa3565b62000fcc565b34801562000631575f80fd5b50620003b26200104f565b34801562000648575f80fd5b50620006606200065a36600462003127565b62001066565b604051620003da919062003174565b3480156200067b575f80fd5b506200049a6200068d36600462002f1a565b620008d3565b3480156200069f575f80fd5b506004546001600160a01b031662000428565b348015620006be575f80fd5b50620006ec620006d036600462002f1a565b80516020918201205f9081526009909152604090205460ff1690565b604051620003da9190620031d8565b34801562000707575f80fd5b506200051f62000719366004620031ed565b62001215565b3480156200072b575f80fd5b50620007436200073d3660046200320e565b620012b5565b604051620003da9190620032c4565b3480156200075e575f80fd5b50620007436200077036600462003309565b62001370565b34801562000782575f80fd5b506200079a6200079436600462002fa3565b62001514565b60408051928352901515602083015201620003da565b348015620007bc575f80fd5b50600454620007d590600160a01b900463ffffffff1681565b60405163ffffffff9091168152602001620003da565b348015620007f7575f80fd5b506200051f6200080936600462002fa3565b62001591565b3480156200081b575f80fd5b50620003b26200082d36600462003411565b6200160a565b3480156200083f575f80fd5b50651b585b9d585b60d21b6200051f565b3480156200085c575f80fd5b506200059d62001636565b34801562000873575f80fd5b50620003b26200088536600462003411565b62001660565b34801562000897575f80fd5b50620003b2620008a936600462003439565b620016a3565b348015620008bb575f80fd5b506200051f620008cd36600462002f1a565b62001794565b60605f805f620008fe8580516020918201205f8181526009909252604090912054909160ff90911690565b909250905060028160028111156200091a576200091a62002f4f565b0362000936576200092b8262001812565b935093505050915091565b60018160028111156200094d576200094d62002f4f565b036200095e576200092b82620019e9565b5f5b6040519080825280601f01601f1916602001820160405280156200098b576020820181803683370190505b50955f95509350505050565b5f81516040620009a89190620034aa565b9050601f19620009ba82601f620034aa565b1690506020808303528060208303f35b620009d462001b26565b620009e2835f8484620016a3565b505050565b600a8054620009f69062002c31565b80601f016020809104026020016040519081016040528092919081815260200182805462000a249062002c31565b801562000a735780601f1062000a495761010080835404028352916020019162000a73565b820191905f5260205f20905b81548152906001019060200180831162000a5557829003601f168201915b505050505081565b62000a8562001b26565b6004805463ffffffff909216600160a01b0263ffffffff60a01b19909216919091179055565b80516020808301919091205f8181526009909252604082205460ff16919081906002848181111562000ae15762000ae162002f4f565b0362000afe575f818152600760205260409020545b925062000b33565b600184600281111562000b155762000b1562002f4f565b0362000b2f575f8181526002602052604090205462000af6565b5f92505b6005546001600160a01b031662000b4b575f62000b55565b62000b5562000cc9565b93959294505050565b60605f805f62000b898680516020918201205f8181526009909252604090912054909160ff90911690565b9092509050600281600281111562000ba55762000ba562002f4f565b0362000bc35762000bb7828662001b55565b93509350505062000c02565b600181600281111562000bda5762000bda62002f4f565b0362000bec5762000bb7828662001c2c565b5050604080515f80825260208201909252925090505b9250929050565b80516020808301919091205f8181526009909252604082205482919060ff166002818181111562000c3e5762000c3e62002f4f565b0362000c64575f828152600860209081526040808320546007909252909120546200092b565b600181600281111562000c7b5762000c7b62002f4f565b0362000ca1575f828152600360209081526040808320546002909252909120546200092b565b505f9485945092505050565b62000cb762001b26565b600a62000cc5828262003509565b5050565b60055460408051630e65e36d60e11b815290515f926001600160a01b031691631ccbc6da9160048083019260209291908290030181865afa15801562000d11573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019062000d379190620035d1565b905090565b81516020808401919091205f8181526009909252604082205460ff166002818181111562000d6e5762000d6e62002f4f565b0362000d8a5762000d80828562001215565b9250505062000dcf565b600181600281111562000da15762000da162002f4f565b0362000dc9575f62000db4838662001c2c565b508051602090910120935062000dcf92505050565b505f9150505b92915050565b62000ddf62001b26565b62000de962001636565b62000e545760405162461bcd60e51b815260206004820152603060248201527f5468652063757272656e74206e6574776f726b20646f6573206e6f742073757060448201526f1c1bdc9d08189b1bd8881d5c1b1bd85960821b60648201526084015b60405180910390fd5b82516020808501919091205f81815260099092526040822054909160ff9091169081600281111562000e8a5762000e8a62002f4f565b148062000eab5750600281600281111562000ea95762000ea962002f4f565b145b62000ef05760405162461bcd60e51b8152602060048201526014602482015273496e76616c69642073746f72616765206d6f646560601b604482015260640162000e4b565b5f81600281111562000f065762000f0662002f4f565b0362000f25575f828152600960205260409020805460ff191660021790555b62000f3282858562001c9f565b5050505050565b5f62000f4462001b26565b81516020808401919091205f81815260099092526040909120805460ff19811690915560ff166002818181111562000f805762000f8062002f4f565b0362000f9a5762000f92825f62001fbc565b949350505050565b600181600281111562000fb15762000fb162002f4f565b0362000fc35762000f92825f620020e9565b505f9392505050565b5f62000fd762001b26565b82516020808501919091205f818152600990925260409091205460ff16600281818111156200100a576200100a62002f4f565b036200101c5762000d8082856200218a565b600181600281111562001033576200103362002f4f565b03620010455762000d808285620022ac565b505f949350505050565b6200105962001b26565b620010645f6200233d565b565b60605f620010748562001794565b90505f620010838486620034aa565b905081811115620010915750805b5f858211620010a1575f620010ad565b620010ad868362002bf2565b90505f80620010d78980516020918201205f8181526009909252604090912054909160ff90911690565b91509150826001600160401b03811115620010f657620010f662002cec565b6040519080825280602002602001820160405280156200112b57816020015b6060815260200190600190039081620011155790505b5095505f5b8381101562001208575f62001146828b620034aa565b905060028360028111156200115f576200115f62002f4f565b03620011985762001171848262001b55565b5088838151811062001187576200118762002bca565b6020026020010181905250620011f2565b6001836002811115620011af57620011af62002f4f565b03620011c15762001171848262001c2c565b604080515f8152602081019091528851899084908110620011e657620011e662002bca565b60200260200101819052505b5080620011ff81620035e9565b91505062001130565b5050505050509392505050565b6005545f83815260066020908152604080832085845290915280822054905163d8389dc560e01b815291926001600160a01b03169163d8389dc591620012619160040190815260200190565b602060405180830381865afa1580156200127d573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190620012a3919062003604565b67ffffffffffffffff19169392505050565b60605f82516001600160401b03811115620012d457620012d462002cec565b604051908082528060200260200182016040528015620012fe578160200160208202803683370190505b5090505f5b835181101562001369576200133484828151811062001326576200132662002bca565b602002602001015162001794565b82828151811062001349576200134962002bca565b6020908102919091010152806200136081620035e9565b91505062001303565b5092915050565b60605f805b8351811015620013c55783818151811062001394576200139462002bca565b6020026020010151602001515182620013ae9190620034aa565b915080620013bc81620035e9565b91505062001375565b505f816001600160401b03811115620013e257620013e262002cec565b6040519080825280602002602001820160405280156200140c578160200160208202803683370190505b5090505f805b85518110156200150a575f5b86828151811062001433576200143362002bca565b60200260200101516020015151811015620014f457620014af87838151811062001461576200146162002bca565b60200260200101515f015188848151811062001481576200148162002bca565b6020026020010151602001518381518110620014a157620014a162002bca565b602002602001015162000d3c565b848481518110620014c457620014c462002bca565b602090810291909101015282620014db81620035e9565b9350508080620014eb90620035e9565b9150506200141e565b50806200150181620035e9565b91505062001412565b5090949350505050565b81516020808401919091205f8181526009909252604082205482919060ff166002818181111562001549576200154962002f4f565b036200155b5762000bb782866200238e565b600181600281111562001572576200157262002f4f565b03620015845762000bb782866200244a565b505f958695509350505050565b5f6200159c62001b26565b82516020808501919091205f818152600990925260409091205460ff1660028181811115620015cf57620015cf62002f4f565b03620015e15762000d80828562001fbc565b6001816002811115620015f857620015f862002f4f565b03620010455762000d808285620020e9565b6200161462001b26565b600580546001600160a01b0319166001600160a01b0392909216919091179055565b6005545f906001600160a01b03161580159062000d3757505f6200165962000cc9565b1015905090565b6200166a62001b26565b6001600160a01b0381166200169557604051631e4fbdf760e01b81525f600482015260240162000e4b565b620016a0816200233d565b50565b620016ad62001b26565b83516020808601919091205f81815260099092526040822054909160ff90911690816002811115620016e357620016e362002f4f565b1480620017045750600181600281111562001702576200170262002f4f565b145b620017495760405162461bcd60e51b8152602060048201526014602482015273496e76616c69642073746f72616765206d6f646560601b604482015260640162000e4b565b5f8160028111156200175f576200175f62002f4f565b036200177e575f828152600960205260409020805460ff191660011790555b6200178c828686866200249d565b505050505050565b80516020808301919091205f8181526009909252604082205460ff1660028181811115620017c657620017c662002f4f565b03620017e157505f9081526007602052604090205492915050565b6001816002811115620017f857620017f862002f4f565b0362000fc3575f8281526002602052604090205462000f92565b60605f805f6200183a855f908152600860209081526040808320546007909252909120549091565b91509150805f036200184d575f62000960565b5f826001600160401b0381111562001869576200186962002cec565b6040519080825280601f01601f19166020018201604052801562001894576020820181803683370190505b5090505f805b83811015620019da575f88815260066020908152604080832084845290915280822054600554915163afd5644d60e01b8152600481018290529092916001600160a01b03169063afd5644d90602401602060405180830381865afa15801562001905573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906200192b9190620035d1565b60055460405163bea94b8b60e01b81529192506001600160a01b03169063bea94b8b90620019659085906002905f9087906004016200362e565b5f60405180830381865afa15801562001980573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052620019a991908101906200365b565b508060406020868801013e620019c08185620034aa565b935050508080620019d190620035e9565b9150506200189a565b50909660019650945050505050565b60605f805f62001a11855f908152600360209081526040808320546002909252909120549091565b91509150805f0362001a24575f62000960565b5f826001600160401b0381111562001a405762001a4062002cec565b6040519080825280601f01601f19166020018201604052801562001a6b576020820181803683370190505b509050602081015f5b83811015620019da575f888152602081815260408083208484529091528120549062001aa08262002582565b1562001ae15762001ab18260e01c90565b5f8b8152600160209081526040808320878452909152902090915062001ad990838662002596565b505062001b00565b8162001aed8162002646565b50915062001afc81866200266b565b5050505b62001b0c8185620034aa565b93505050808062001b1d90620035e9565b91505062001a74565b6004546001600160a01b03163314620010645760405163118cdaa760e01b815233600482015260240162000e4b565b60605f8062001b6585856200238e565b509050600181101562001b8b575050604080515f80825260208201909252915062000c02565b6005545f86815260066020908152604080832088845290915280822054905163bea94b8b60e01b815291926001600160a01b03169163bea94b8b9162001bdb91600290869088906004016200362e565b5f60405180830381865afa15801562001bf6573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f1916820160405262001c1f91908101906200365b565b9660019650945050505050565b5f828152602081815260408083208484529091528120546060919062001c528162002582565b1562001c89575f858152600160209081526040808320878452909152902062001c7c9082620026a3565b6001925092505062000c02565b62001c948162002746565b925092505062000c02565b815160055460408051630e65e36d60e11b815290515f926001600160a01b031691631ccbc6da9160048083019260209291908290030181865afa15801562001ce9573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019062001d0f9190620035d1565b905062001d1d8282620036d5565b34101562001d655760405162461bcd60e51b8152602060048201526014602482015273496e73756666696369656e742062616c616e636560601b604482015260640162000e4b565b5f5b828110156200178c5783818151811062001d855762001d8562002bca565b60200260200101515f10801562001dd05750600460149054906101000a900463ffffffff1663ffffffff1684828151811062001dc55762001dc562002bca565b602002602001015111155b62001e155760405162461bcd60e51b8152602060048201526014602482015273092dcecc2d8d2c840c6d0eadcd640d8cadccee8d60631b604482015260640162000e4b565b62001e5a8686838151811062001e2f5762001e2f62002bca565b602002602001015186848151811062001e4c5762001e4c62002bca565b6020026020010151620027c5565b5f338787848151811062001e725762001e7262002bca565b602002602001015160405160200162001ea9939291906001600160a01b039390931683526020830191909152604082015260600190565b60405160208183030381529060405280519060200120905060055f9054906101000a90046001600160a01b03166001600160a01b0316634581a92084838589878151811062001efc5762001efc62002bca565b60200260200101516040518563ffffffff1660e01b815260040162001f34939291909283526020830191909152604082015260600190565b5f604051808303818588803b15801562001f4c575f80fd5b505af115801562001f5f573d5f803e3d5ffd5b50505050508060065f8981526020019081526020015f205f88858151811062001f8c5762001f8c62002bca565b602002602001015181526020019081526020015f208190555050808062001fb390620035e9565b91505062001d67565b5f5b5f83815260066020908152604080832085845290915290205415620020e3576005545f84815260066020908152604080832086845290915280822054905163afd5644d60e01b815291926001600160a01b03169163afd5644d91620020299160040190815260200190565b602060405180830381865afa15801562002045573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906200206b9190620035d1565b90508060085f8681526020019081526020015f205f8282546200208f919062002bf2565b90915550505f848152600660209081526040808320868452825280832083905586835260079091528120805491620020c783620036ef565b91905055508280620020d990620035e9565b9350505062001fbe565b50919050565b5f5b5f8381526020818152604080832085845290915290205415620020e3575f6200211584846200244a565b505f858152602081815260408083208784528252808320839055878352600290915281208054929350906200214a83620036ef565b90915550505f84815260036020526040812080548392906200216e90849062002bf2565b909155508390506200218081620035e9565b93505050620020eb565b5f82815260076020526040812054620021a69060019062002bf2565b8214620021b557505f62000dcf565b6005545f84815260066020908152604080832086845290915280822054905163afd5644d60e01b815291926001600160a01b03169163afd5644d91620022019160040190815260200190565b602060405180830381865afa1580156200221d573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190620022439190620035d1565b5f8581526006602090815260408083208784528252808320839055878352600790915281208054929350906200227983620036ef565b90915550505f84815260086020526040812080548392906200229d90849062002bf2565b90915550600195945050505050565b5f82815260026020526040812054620022c89060019062002bf2565b8214620022d757505f62000dcf565b5f620022e484846200244a565b505f858152602081815260408083208784528252808320839055878352600290915281208054929350906200231983620036ef565b90915550505f84815260036020526040812080548392906200229d90849062002bf2565b600480546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a35050565b5f8281526007602052604081205481908310620023b057505f90508062000c02565b6005545f85815260066020908152604080832087845290915280822054905163afd5644d60e01b815291926001600160a01b03169163afd5644d91620023fc9160040190815260200190565b602060405180830381865afa15801562002418573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906200243e9190620035d1565b95600195509350505050565b5f8281526020818152604080832084845290915281205481908062002476575f80925092505062000c02565b620024818162002582565b15620024925762001c7c8160e01c90565b62001c948162002646565b620024aa8484836200293c565b60ff7f0000000000000000000000000000000000000000000000000000000000000000168111156200250f57620024f2620024e6838362002a5e565b6001600160a01b031690565b5f858152602081815260408083208784529091529020556200257c565b5f8481526001602090815260408083208684528252918290208251601f85018390048302810183019093528383526200256492909185908590819084018382808284375f9201919091525062002aa092505050565b5f858152602081815260408083208784529091529020555b50505050565b5f806200258f8360e01c90565b1192915050565b5f805f620025a48562002b38565b808652909350905083601c8411156200263857601c81015f805b60206001620025cf601c8a62002bf2565b620025dc906020620034aa565b620025e8919062002bf2565b620025f4919062003707565b81101562002634575f81815260208b815260409091205480855292506200261d908490620034aa565b9250806200262b81620035e9565b915050620025be565b5050505b600192505050935093915050565b5f806001600160a01b0383166200266157505f928392509050565b50503b9081151590565b5f805f806200267a8662002646565b915091508062002692575f8093509350505062000c02565b815f86883c50946001945092505050565b60605f620026b18362002b52565b92509050601c8111156200136957603c82015f805b60206001620026d7601c8762002bf2565b620026e4906020620034aa565b620026f0919062002bf2565b620026fc919062003707565b8110156200273c575f8181526020888152604090912054808552925062002725908490620034aa565b9250806200273381620035e9565b915050620026c6565b5050505092915050565b60605f805f620027568562002646565b915091508062002767575f62000960565b5f826001600160401b0381111562002783576200278362002cec565b6040519080825280601f01601f191660200182016040528015620027ae576020820181803683370190505b509050825f60208301883c95600195509350505050565b5f838152600760205260409020548211156200281d5760405162461bcd60e51b8152602060048201526016602482015275135d5cdd081c995c1b1858d9481bdc88185c1c195b9960521b604482015260640162000e4b565b5f83815260076020526040902054821015620028f2576005545f84815260066020908152604080832086845290915280822054905163afd5644d60e01b815291926001600160a01b03169163afd5644d916200287f9160040190815260200190565b602060405180830381865afa1580156200289b573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190620028c19190620035d1565b90508060085f8681526020019081526020015f205f828254620028e5919062002bf2565b9091555062002913915050565b5f8381526007602052604081208054916200290d83620035e9565b91905055505b5f838152600860205260408120805483929062002932908490620034aa565b9091555050505050565b5f8381526020818152604080832085845290915290205480620029fb578215806200298e57505f848152602081905260408120816200297d60018762002bf2565b81526020019081526020015f205414155b620029d55760405162461bcd60e51b81526020600482015260166024820152751b5d5cdd081c995c1b1858d9481bdc88185c1c195b9960521b604482015260640162000e4b565b5f848152600260205260408120805491620029f083620035e9565b919050555062002a34565b5f62002a0885856200244a565b5090508060035f8781526020019081526020015f205f82825462002a2d919062002bf2565b9091555050505b5f848152600360205260408120805484929062002a53908490620034aa565b909155505050505050565b5f80838360405162002a709062002bbc565b62002a7d92919062003727565b604051809103905ff08015801562002a97573d5f803e3d5ffd5b50949350505050565b805160208083015160e083901b911c1790601c81111562001369575f603c8401815b6020600162002ad3601c8762002bf2565b62002ae0906020620034aa565b62002aec919062002bf2565b62002af8919062003707565b8110156200273c578151925062002b11826020620034aa565b5f82815260208990526040902084905591508062002b2f81620035e9565b91505062002ac2565b5f8062002b458360e01c90565b9360209390931b92915050565b5f606062002b608360e01c90565b9150602083901b9250816001600160401b0381111562002b845762002b8462002cec565b6040519080825280601f01601f19166020018201604052801562002baf576020820181803683370190505b5060208101939093525091565b61010e806200375683390190565b634e487b7160e01b5f52603260045260245ffd5b634e487b7160e01b5f52601160045260245ffd5b8181038181111562000dcf5762000dcf62002bde565b5f808585111562002c17575f80fd5b8386111562002c24575f80fd5b5050820193919092039150565b600181811c9082168062002c4657607f821691505b602082108103620020e357634e487b7160e01b5f52602260045260245ffd5b828482375f8382015f81525f845462002c7e8162002c31565b6001828116801562002c99576001811462002caf5762002cdd565b60ff198416865282151583028601945062002cdd565b885f526020805f205f5b8581101562002cd45781548982015290840190820162002cb9565b50505082860194505b50929998505050505050505050565b634e487b7160e01b5f52604160045260245ffd5b604080519081016001600160401b038111828210171562002d255762002d2562002cec565b60405290565b604051601f8201601f191681016001600160401b038111828210171562002d565762002d5662002cec565b604052919050565b5f6001600160401b0382111562002d795762002d7962002cec565b50601f01601f191660200190565b5f82601f83011262002d97575f80fd5b813562002dae62002da88262002d5e565b62002d2b565b81815284602083860101111562002dc3575f80fd5b816020850160208301375f918101602001919091529392505050565b5f8083601f84011262002df0575f80fd5b5081356001600160401b0381111562002e07575f80fd5b60208301915083602082850101111562000c02575f80fd5b5f805f6040848603121562002e32575f80fd5b83356001600160401b038082111562002e49575f80fd5b62002e578783880162002d87565b9450602086013591508082111562002e6d575f80fd5b5062002e7c8682870162002ddf565b9497909650939450505050565b5f5b8381101562002ea557818101518382015260200162002e8b565b50505f910152565b5f815180845262002ec681602086016020860162002e89565b601f01601f19169290920160200192915050565b602081525f62002eee602083018462002ead565b9392505050565b5f6020828403121562002f06575f80fd5b813563ffffffff8116811462002eee575f80fd5b5f6020828403121562002f2b575f80fd5b81356001600160401b0381111562002f41575f80fd5b62000f928482850162002d87565b634e487b7160e01b5f52602160045260245ffd5b60038110620016a057634e487b7160e01b5f52602160045260245ffd5b6060810162002f8f8562002f63565b938152602081019290925260409091015290565b5f806040838503121562002fb5575f80fd5b82356001600160401b0381111562002fcb575f80fd5b62002fd98582860162002d87565b95602094909401359450505050565b604081525f62002ffc604083018562002ead565b905082151560208301529392505050565b5f6001600160401b0382111562003028576200302862002cec565b5060051b60200190565b5f82601f83011262003042575f80fd5b813560206200305562002da8836200300d565b82815260059290921b8401810191818101908684111562003074575f80fd5b8286015b8481101562003091578035835291830191830162003078565b509695505050505050565b5f805f60608486031215620030af575f80fd5b83356001600160401b0380821115620030c6575f80fd5b620030d48783880162002d87565b94506020860135915080821115620030ea575f80fd5b620030f88783880162003032565b935060408601359150808211156200310e575f80fd5b506200311d8682870162003032565b9150509250925092565b5f805f606084860312156200313a575f80fd5b83356001600160401b0381111562003150575f80fd5b6200315e8682870162002d87565b9660208601359650604090950135949350505050565b5f602080830181845280855180835260408601915060408160051b87010192508387015f5b82811015620031cb57603f19888603018452620031b885835162002ead565b9450928501929085019060010162003199565b5092979650505050505050565b60208101620031e78362002f63565b91905290565b5f8060408385031215620031ff575f80fd5b50508035926020909101359150565b5f602080838503121562003220575f80fd5b82356001600160401b038082111562003237575f80fd5b818501915085601f8301126200324b575f80fd5b81356200325c62002da8826200300d565b81815260059190911b830184019084810190888311156200327b575f80fd5b8585015b83811015620032b75780358581111562003298575f8081fd5b620032a88b89838a010162002d87565b8452509186019186016200327f565b5098975050505050505050565b602080825282518282018190525f9190848201906040850190845b81811015620032fd57835183529284019291840191600101620032df565b50909695505050505050565b5f60208083850312156200331b575f80fd5b82356001600160401b038082111562003332575f80fd5b818501915085601f83011262003346575f80fd5b81356200335762002da8826200300d565b81815260059190911b8301840190848101908883111562003376575f80fd5b8585015b83811015620032b75780358581111562003393575f8081fd5b86016040818c03601f1901811315620033ab575f8081fd5b620033b562002d00565b8983013588811115620033c7575f8081fd5b620033d78e8c8387010162002d87565b825250908201359087821115620033ed575f8081fd5b620033fd8d8b8486010162003032565b818b0152855250509186019186016200337a565b5f6020828403121562003422575f80fd5b81356001600160a01b038116811462002eee575f80fd5b5f805f80606085870312156200344d575f80fd5b84356001600160401b038082111562003464575f80fd5b620034728883890162002d87565b95506020870135945060408701359150808211156200348f575f80fd5b506200349e8782880162002ddf565b95989497509550505050565b8082018082111562000dcf5762000dcf62002bde565b601f821115620009e2575f81815260208120601f850160051c81016020861015620034e85750805b601f850160051c820191505b818110156200178c57828155600101620034f4565b81516001600160401b0381111562003525576200352562002cec565b6200353d8162003536845462002c31565b84620034c0565b602080601f83116001811462003573575f84156200355b5750858301515b5f19600386901b1c1916600185901b1785556200178c565b5f85815260208120601f198616915b82811015620035a35788860151825594840194600190910190840162003582565b5085821015620035c157878501515f19600388901b60f8161c191681555b5050505050600190811b01905550565b5f60208284031215620035e2575f80fd5b5051919050565b5f60018201620035fd57620035fd62002bde565b5060010190565b5f6020828403121562003615575f80fd5b815167ffffffffffffffff198116811462002eee575f80fd5b84815260808101620036408562002f63565b84602083015283604083015282606083015295945050505050565b5f602082840312156200366c575f80fd5b81516001600160401b0381111562003682575f80fd5b8201601f8101841362003693575f80fd5b8051620036a462002da88262002d5e565b818152856020838501011115620036b9575f80fd5b620036cc82602083016020860162002e89565b95945050505050565b808202811582820484141762000dcf5762000dcf62002bde565b5f8162003700576200370062002bde565b505f190190565b5f826200372257634e487b7160e01b5f52601260045260245ffd5b500490565b60208152816020820152818360408301375f818301604090810191909152601f909201601f1916010191905056fe608060405234801561000f575f80fd5b5060405161010e38038061010e83398101604081905261002e9161004b565b80518060208301f35b634e487b7160e01b5f52604160045260245ffd5b5f602080838503121561005c575f80fd5b82516001600160401b0380821115610072575f80fd5b818501915085601f830112610085575f80fd5b81518181111561009757610097610037565b604051601f8201601f19908116603f011681019083821181831017156100bf576100bf610037565b8160405282815288868487010111156100d6575f80fd5b5f93505b828410156100f757848401860151818501870152928501926100da565b5f8684830101528096505050505050509291505056fea2646970667358221220ebcd139e7374a9f1c5b5d7c1230cab1e82cbda5396f436b329517280494c00bb64736f6c63430008140033";
203
+
204
+ // src/utils/uploader.ts
205
+ var TxSender = class {
206
+ #provider;
207
+ #wallet;
208
+ #chainId;
209
+ constructor(rpc, privateKey) {
210
+ this.#provider = new ethers2.JsonRpcProvider(rpc);
211
+ this.#wallet = new ethers2.Wallet(privateKey, this.#provider);
212
+ }
213
+ async getChainId() {
214
+ if (this.#chainId === void 0) {
215
+ const network = await stableRetry(() => this.#provider.getNetwork());
216
+ this.#chainId = Number(network.chainId);
217
+ }
218
+ return this.#chainId;
219
+ }
220
+ // ====================== Gas API ======================
221
+ async getFeeData() {
222
+ return await stableRetry(() => this.#provider.getFeeData());
223
+ }
224
+ /**
225
+ * Base fee of the latest block (EIP-1559), or null on legacy chains.
226
+ */
227
+ async getBaseFee() {
228
+ const block = await stableRetry(() => this.#provider.getBlock("latest"));
229
+ return block?.baseFeePerGas ?? null;
230
+ }
231
+ /**
232
+ * Resolve concrete gas fees for a transaction, by chain fee model:
233
+ * - Legacy chains (no base fee, e.g. BNB Chain): a single gasPrice paid in full,
234
+ * taken from the node unless overridden via custom.gasPrice.
235
+ * - Avalanche C-Chain: EIP-1559 with a protocol-enforced minimum base fee of
236
+ * 25 nAVAX; the node-reported base fee is clamped to that floor.
237
+ * - Other (EIP-1559) chains: tip defaults to 100 wei,
238
+ * maxFeePerGas defaults to 1.1 * baseFee + tip (baseFee from the latest block).
239
+ * Caller-provided fields take precedence. effectiveGasPrice is the expected
240
+ * price actually charged per gas unit.
241
+ */
242
+ async resolveGasFees(custom = {}) {
243
+ const chainId = await this.getChainId();
244
+ const isLegacyChain = LEGACY_GAS_CHAIN_IDS.has(chainId);
245
+ let baseFee = isLegacyChain ? null : await this.getBaseFee();
246
+ if (AVALANCHE_GAS_CHAIN_IDS.has(chainId) && (baseFee == null || baseFee < AVALANCHE_MIN_BASE_FEE_PER_GAS)) {
247
+ baseFee = AVALANCHE_MIN_BASE_FEE_PER_GAS;
248
+ }
249
+ if (baseFee != null) {
250
+ const maxPriorityFeePerGas = custom.maxPriorityFeePerGas ?? DEFAULT_PRIORITY_FEE_PER_GAS;
251
+ const bufferedBaseFee = baseFee * BASE_FEE_MULTIPLIER_NUMERATOR / BASE_FEE_MULTIPLIER_DENOMINATOR;
252
+ const maxFeePerGas = custom.maxFeePerGas ?? bufferedBaseFee + maxPriorityFeePerGas;
253
+ const baseAndTip = baseFee + maxPriorityFeePerGas;
254
+ const effectiveGasPrice = maxFeePerGas < baseAndTip ? maxFeePerGas : baseAndTip;
255
+ return { type: "eip1559", maxFeePerGas, maxPriorityFeePerGas, effectiveGasPrice };
256
+ }
257
+ const feeData = await this.getFeeData();
258
+ const gasPrice = custom.gasPrice ?? feeData.gasPrice;
259
+ if (gasPrice != null) {
260
+ return { type: "legacy", gasPrice, effectiveGasPrice: gasPrice };
261
+ }
262
+ if (feeData.maxFeePerGas != null && feeData.maxPriorityFeePerGas != null) {
263
+ const maxFeePerGas = custom.maxFeePerGas ?? feeData.maxFeePerGas;
264
+ const maxPriorityFeePerGas = custom.maxPriorityFeePerGas ?? feeData.maxPriorityFeePerGas;
265
+ return { type: "eip1559", maxFeePerGas, maxPriorityFeePerGas, effectiveGasPrice: maxFeePerGas };
266
+ }
267
+ throw new Error("Failed to resolve gas fees: the network provides neither base fee nor gas price.");
268
+ }
269
+ async waitForReceipt(hash) {
270
+ if (!hash || !ethers2.isHexString(hash)) throw new Error("Invalid transaction hash");
271
+ return await stableRetry(() => this.#provider.waitForTransaction(hash));
272
+ }
273
+ async getTransactionResult(hash) {
274
+ const receipt = await this.waitForReceipt(hash);
275
+ return { txCost: calcTxCost(receipt), success: receipt?.status === 1 };
276
+ }
277
+ // ====================== Public Send API ======================
278
+ /**
279
+ * Sends a single transaction. No locking or manual nonce management:
280
+ * uploads are strictly sequential, so the wallet's automatic nonce
281
+ * handling is always up to date.
282
+ */
283
+ async sendTx(tx) {
284
+ return stableRetry(() => this.#wallet.sendTransaction(tx));
285
+ }
286
+ };
287
+
288
+ // src/utils/web3.ts
289
+ async function getUploadInfo(contract, hexName) {
290
+ const result = await stableRetry(() => contract["getUploadInfo"](hexName));
291
+ return {
292
+ fileMode: Number(result[0]),
293
+ oldChunkCount: Number(result[1]),
294
+ cost: result[2]
295
+ };
296
+ }
297
+ async function getChunkCounts(contract, batch) {
298
+ const names = batch.map((key) => stringToHex(key));
299
+ const counts = await stableRetry(() => contract["getChunkCountsBatch"](names));
300
+ const results = [];
301
+ let index = 0;
302
+ for (const key of batch) {
303
+ results.push({ key, chunkCount: Number(counts[index++]) });
304
+ }
305
+ return results;
306
+ }
307
+ async function getChunkHashes(contract, batch) {
308
+ const fileChunks = batch.map((file) => [
309
+ stringToHex(file.name),
310
+ file.chunkIds
311
+ ]);
312
+ const hashes = await stableRetry(() => contract["getChunkHashesBatch"](fileChunks));
313
+ const results = [];
314
+ let index = 0;
315
+ for (const file of batch) {
316
+ for (let j = 0; j < file.chunkIds.length; j++) {
317
+ results.push({ name: file.name, chunkId: file.chunkIds[j], hash: hashes[index++] });
318
+ }
319
+ }
320
+ return results;
321
+ }
322
+
323
+ // node_modules/yocto-queue/index.js
324
+ var Node = class {
325
+ value;
326
+ next;
327
+ constructor(value) {
328
+ this.value = value;
329
+ }
330
+ };
331
+ var Queue = class {
332
+ #head;
333
+ #tail;
334
+ #size;
335
+ constructor() {
336
+ this.clear();
337
+ }
338
+ enqueue(value) {
339
+ const node = new Node(value);
340
+ if (this.#head) {
341
+ this.#tail.next = node;
342
+ this.#tail = node;
343
+ } else {
344
+ this.#head = node;
345
+ this.#tail = node;
346
+ }
347
+ this.#size++;
348
+ }
349
+ dequeue() {
350
+ const current = this.#head;
351
+ if (!current) {
352
+ return;
353
+ }
354
+ this.#head = this.#head.next;
355
+ this.#size--;
356
+ if (!this.#head) {
357
+ this.#tail = void 0;
358
+ }
359
+ return current.value;
360
+ }
361
+ peek() {
362
+ if (!this.#head) {
363
+ return;
364
+ }
365
+ return this.#head.value;
366
+ }
367
+ clear() {
368
+ this.#head = void 0;
369
+ this.#tail = void 0;
370
+ this.#size = 0;
371
+ }
372
+ get size() {
373
+ return this.#size;
374
+ }
375
+ *[Symbol.iterator]() {
376
+ let current = this.#head;
377
+ while (current) {
378
+ yield current.value;
379
+ current = current.next;
380
+ }
381
+ }
382
+ *drain() {
383
+ while (this.#head) {
384
+ yield this.dequeue();
385
+ }
386
+ }
387
+ };
388
+
389
+ // node_modules/p-limit/index.js
390
+ function pLimit(concurrency) {
391
+ let rejectOnClear = false;
392
+ if (typeof concurrency === "object") {
393
+ ({ concurrency, rejectOnClear = false } = concurrency);
394
+ }
395
+ validateConcurrency(concurrency);
396
+ if (typeof rejectOnClear !== "boolean") {
397
+ throw new TypeError("Expected `rejectOnClear` to be a boolean");
398
+ }
399
+ const queue = new Queue();
400
+ let activeCount = 0;
401
+ const resumeNext = () => {
402
+ if (activeCount < concurrency && queue.size > 0) {
403
+ activeCount++;
404
+ queue.dequeue().run();
405
+ }
406
+ };
407
+ const next = () => {
408
+ activeCount--;
409
+ resumeNext();
410
+ };
411
+ const run = async (function_, resolve, arguments_) => {
412
+ const result = (async () => function_(...arguments_))();
413
+ resolve(result);
414
+ try {
415
+ await result;
416
+ } catch {
417
+ }
418
+ next();
419
+ };
420
+ const enqueue = (function_, resolve, reject, arguments_) => {
421
+ const queueItem = { reject };
422
+ new Promise((internalResolve) => {
423
+ queueItem.run = internalResolve;
424
+ queue.enqueue(queueItem);
425
+ }).then(run.bind(void 0, function_, resolve, arguments_));
426
+ if (activeCount < concurrency) {
427
+ resumeNext();
428
+ }
429
+ };
430
+ const generator = (function_, ...arguments_) => new Promise((resolve, reject) => {
431
+ enqueue(function_, resolve, reject, arguments_);
432
+ });
433
+ Object.defineProperties(generator, {
434
+ activeCount: {
435
+ get: () => activeCount
436
+ },
437
+ pendingCount: {
438
+ get: () => queue.size
439
+ },
440
+ clearQueue: {
441
+ value() {
442
+ if (!rejectOnClear) {
443
+ queue.clear();
444
+ return;
445
+ }
446
+ const abortError = AbortSignal.abort().reason;
447
+ while (queue.size > 0) {
448
+ queue.dequeue().reject(abortError);
449
+ }
450
+ }
451
+ },
452
+ concurrency: {
453
+ get: () => concurrency,
454
+ set(newConcurrency) {
455
+ validateConcurrency(newConcurrency);
456
+ concurrency = newConcurrency;
457
+ queueMicrotask(() => {
458
+ while (activeCount < concurrency && queue.size > 0) {
459
+ resumeNext();
460
+ }
461
+ });
462
+ }
463
+ },
464
+ map: {
465
+ async value(iterable, function_) {
466
+ const promises = [];
467
+ try {
468
+ Array.from(iterable, (value, index) => {
469
+ const promise = generator(function_, value, index);
470
+ promises.push(promise);
471
+ return promise;
472
+ });
473
+ } catch (error) {
474
+ for (const promise of promises) {
475
+ promise.catch(() => {
476
+ });
477
+ }
478
+ throw error;
479
+ }
480
+ return Promise.all(promises);
481
+ }
482
+ }
483
+ });
484
+ return generator;
485
+ }
486
+ function validateConcurrency(concurrency) {
487
+ if (!((Number.isInteger(concurrency) || concurrency === Number.POSITIVE_INFINITY) && concurrency > 0)) {
488
+ throw new TypeError("Expected `concurrency` to be a number from 1 and up");
489
+ }
490
+ }
491
+
492
+ // src/flatdirectory.ts
493
+ import { ethers as ethers3 } from "ethers";
494
+ var defaultCallback = {
495
+ onProgress: () => {
496
+ },
497
+ onFail: () => {
498
+ },
499
+ onFinish: () => {
500
+ }
501
+ };
502
+ var FlatDirectory = class _FlatDirectory {
503
+ // ======================= Private fields =======================
504
+ #ethStorageRpc;
505
+ #contractAddr;
506
+ #wallet;
507
+ #txSender;
508
+ #isLoggingEnabled = true;
509
+ /**
510
+ * Private constructor - use create() factory method
511
+ */
512
+ constructor() {
513
+ }
514
+ static async create(config) {
515
+ const flatDirectory = new _FlatDirectory();
516
+ await flatDirectory.#initialize(config);
517
+ return flatDirectory;
518
+ }
519
+ // ======================= Public methods =======================
520
+ /**
521
+ * Enable or disable logging
522
+ * @param value - true to enable logging, false to disable
523
+ */
524
+ setLogEnabled(value) {
525
+ this.#isLoggingEnabled = value;
526
+ }
527
+ /**
528
+ * Deploy a new FlatDirectory contract
529
+ * @returns Contract address if successful, null otherwise
530
+ */
531
+ async deploy() {
532
+ const chainId = await this.#txSenderChecked.getChainId();
533
+ const ethStorage = ETHSTORAGE_MAPPING[chainId] || "0x0000000000000000000000000000000000000000";
534
+ try {
535
+ const factory = new ethers3.ContractFactory(FlatDirectoryAbi, FlatDirectoryBytecode);
536
+ const tx = await factory.getDeployTransaction(0, CONTRACT_MAX_CHUNK_SIZE, ethStorage);
537
+ const resolvedFees = await this.#txSenderChecked.resolveGasFees();
538
+ this.#applyGasFees(tx, resolvedFees);
539
+ const txResponse = await this.#txSenderChecked.sendTx(tx);
540
+ this.#log(`Deploy transaction sent. Hash: ${txResponse.hash}`);
541
+ const receipt = await this.#txSenderChecked.waitForReceipt(txResponse.hash);
542
+ if (receipt?.status === 1 && receipt.contractAddress) {
543
+ this.#contractAddr = receipt.contractAddress;
544
+ this.#log(`Contract deployed successfully. Address: ${this.#contractAddr}`);
545
+ return this.#contractAddr;
546
+ }
547
+ this.#log(`Deployment failed! Transaction reverted (Hash: ${txResponse.hash})`, true);
548
+ return null;
549
+ } catch (e) {
550
+ this.#log(`Deployment failed! ${e.message || e}`, true);
551
+ return null;
552
+ }
553
+ }
554
+ /**
555
+ * Set a file as the default file
556
+ * @param filename - Name of the file to set as default
557
+ * @returns true if successful, false otherwise
558
+ */
559
+ async setDefault(filename) {
560
+ const hexName = filename ? stringToHex(filename) : "0x";
561
+ const fileContract = new ethers3.Contract(this.#contractAddrChecked, FlatDirectoryAbi, this.#walletChecked);
562
+ try {
563
+ const tx = await fileContract["setDefault"].populateTransaction(hexName);
564
+ const resolvedFees = await this.#txSenderChecked.resolveGasFees();
565
+ this.#applyGasFees(tx, resolvedFees);
566
+ const txResponse = await this.#txSenderChecked.sendTx(tx);
567
+ this.#log(`Setting default file (Key: ${filename}). Transaction sent (Hash: ${txResponse.hash})`);
568
+ const result = await this.#txSenderChecked.getTransactionResult(txResponse.hash);
569
+ return result.success;
570
+ } catch (e) {
571
+ this.#log(`Failed to set default file (Key: ${filename}). ${e.message || e}`, true);
572
+ }
573
+ return false;
574
+ }
575
+ /**
576
+ * Remove a file from the contract
577
+ * @param key - File key to remove
578
+ * @returns true if successful, false otherwise
579
+ */
580
+ async remove(key) {
581
+ const fileContract = new ethers3.Contract(this.#contractAddrChecked, FlatDirectoryAbi, this.#walletChecked);
582
+ try {
583
+ const tx = await fileContract["remove"].populateTransaction(stringToHex(key));
584
+ const resolvedFees = await this.#txSenderChecked.resolveGasFees();
585
+ this.#applyGasFees(tx, resolvedFees);
586
+ const txResponse = await this.#txSenderChecked.sendTx(tx);
587
+ this.#log(`File removal initiated (Key: ${key}). Hash: ${txResponse.hash}`);
588
+ const result = await this.#txSenderChecked.getTransactionResult(txResponse.hash);
589
+ return result.success;
590
+ } catch (e) {
591
+ this.#log(`Failed to remove file (Key: ${key}). ${e.message || e}`, true);
592
+ }
593
+ return false;
594
+ }
595
+ /**
596
+ * Download a file from the contract
597
+ * @param key - File key to download
598
+ * @param cb - Download callback object
599
+ */
600
+ async download(key, cb = defaultCallback) {
601
+ const hexName = stringToHex(key);
602
+ const provider = new ethers3.JsonRpcProvider(this.#ethStorageRpcChecked);
603
+ const contract = new ethers3.Contract(this.#contractAddrChecked, FlatDirectoryAbi, provider);
604
+ try {
605
+ const result = await getChunkCounts(contract, [key]);
606
+ const totalChunks = result[0].chunkCount;
607
+ if (totalChunks === 0) {
608
+ cb.onFinish();
609
+ return;
610
+ }
611
+ await this.#download(contract, hexName, totalChunks, cb);
612
+ cb.onFinish();
613
+ } catch (err) {
614
+ cb.onFail(err);
615
+ }
616
+ }
617
+ /**
618
+ * Fetch chunk hashes for multiple files
619
+ * @param keys - Array of file keys
620
+ * @param maxChunks - Maximum number of chunks requested in a single call, defaults to MAX_CHUNKS
621
+ * @returns Object mapping file keys to their chunk hashes
622
+ */
623
+ async fetchHashes(keys, maxChunks) {
624
+ if (!keys || !Array.isArray(keys)) {
625
+ throw new Error("Invalid keys.");
626
+ }
627
+ const contract = new ethers3.Contract(this.#contractAddrChecked, FlatDirectoryAbi, this.#walletChecked);
628
+ const fileInfos = await getChunkCounts(contract, keys);
629
+ return this.#fetchChunkHashes(fileInfos, maxChunks);
630
+ }
631
+ /**
632
+ * Estimate cost for uploading a file
633
+ * @param request - Upload request details
634
+ * @returns Cost estimation object
635
+ */
636
+ async estimateCost(request) {
637
+ const { key } = request;
638
+ if (!key) {
639
+ throw new Error(`FlatDirectory: Invalid key!`);
640
+ }
641
+ return await this.#estimateCostByCallData(request);
642
+ }
643
+ /**
644
+ * Upload a file to the contract
645
+ * @param request - Upload request details
646
+ * @throws Error if upload fails
647
+ */
648
+ async upload(request) {
649
+ const { key, callback } = request;
650
+ if (!callback) {
651
+ throw new Error(`FlatDirectory: Invalid callback object!`);
652
+ }
653
+ if (!key) {
654
+ callback.onFail(new Error(`FlatDirectory: Invalid key!`));
655
+ callback.onFinish(0, 0, 0n);
656
+ return;
657
+ }
658
+ if (!this.#contractAddr) {
659
+ callback.onFail(new Error(`FlatDirectory: FlatDirectory not deployed!`));
660
+ callback.onFinish(0, 0, 0n);
661
+ return;
662
+ }
663
+ if (!this.#wallet) {
664
+ callback.onFail(new Error(`FlatDirectory: Private key is required for this operation.`));
665
+ callback.onFinish(0, 0, 0n);
666
+ return;
667
+ }
668
+ await this.#uploadByCalldata(request);
669
+ }
670
+ // -------------------- Private Methods --------------------
671
+ async #initialize(config) {
672
+ const { privateKey, rpc, address, ethStorageRpc } = config;
673
+ this.#contractAddr = address;
674
+ this.#ethStorageRpc = ethStorageRpc;
675
+ if (privateKey && rpc) {
676
+ const provider = new ethers3.JsonRpcProvider(rpc);
677
+ this.#wallet = new ethers3.Wallet(privateKey, provider);
678
+ this.#txSender = new TxSender(rpc, privateKey);
679
+ if (!address) return;
680
+ } else if (!ethStorageRpc || !address) {
681
+ throw new Error("FlatDirectory: Read-only mode requires both 'ethStorageRpc' and 'address'");
682
+ }
683
+ }
684
+ async #download(contract, hexName, totalChunks, cb) {
685
+ const downloadedResults = /* @__PURE__ */ new Map();
686
+ let nextCallbackStart = 0;
687
+ const flushReadyChunks = () => {
688
+ while (downloadedResults.has(nextCallbackStart)) {
689
+ const data = downloadedResults.get(nextCallbackStart);
690
+ cb.onProgress(nextCallbackStart, totalChunks, data);
691
+ downloadedResults.delete(nextCallbackStart);
692
+ nextCallbackStart++;
693
+ }
694
+ };
695
+ const fetchChunk = (i) => stableRetry(() => contract["readChunk"](hexName, i));
696
+ const fetchSingle = async (i) => {
697
+ const [data] = await fetchChunk(i);
698
+ downloadedResults.set(i, ethers3.getBytes(data));
699
+ flushReadyChunks();
700
+ };
701
+ let maxConcurrency = 6;
702
+ if (typeof process !== "undefined" && process.versions?.node) {
703
+ try {
704
+ const os = await import("os");
705
+ const cores = os.cpus().length;
706
+ maxConcurrency = Math.max(2, Math.min(20, cores * 2));
707
+ } catch (err) {
708
+ maxConcurrency = 10;
709
+ }
710
+ }
711
+ const limit = pLimit(maxConcurrency);
712
+ const quests = Array.from(
713
+ { length: totalChunks },
714
+ (_, i) => limit(() => fetchSingle(i))
715
+ );
716
+ await Promise.all(quests);
717
+ await new Promise((r) => setTimeout(r, 0));
718
+ flushReadyChunks();
719
+ }
720
+ async #fetchChunkHashes(fileInfos, maxChunks) {
721
+ const allHashes = {};
722
+ const chunkLimit = maxChunks && maxChunks > 0 ? maxChunks : MAX_CHUNKS;
723
+ const batchArray = [];
724
+ let currentBatch = {};
725
+ let currentChunkCount = 0;
726
+ for (const { key, chunkCount } of fileInfos) {
727
+ allHashes[key] = chunkCount === 0 ? [] : new Array(chunkCount);
728
+ for (let i = 0; i < chunkCount; i++) {
729
+ if (!currentBatch[key]) {
730
+ currentBatch[key] = [];
731
+ }
732
+ currentBatch[key].push(i);
733
+ currentChunkCount++;
734
+ if (currentChunkCount === chunkLimit) {
735
+ batchArray.push(currentBatch);
736
+ currentBatch = {};
737
+ currentChunkCount = 0;
738
+ }
739
+ }
740
+ }
741
+ if (Object.keys(currentBatch).length > 0) {
742
+ batchArray.push(currentBatch);
743
+ }
744
+ if (batchArray.length > 0) {
745
+ const contract = new ethers3.Contract(this.#contractAddrChecked, FlatDirectoryAbi, this.#walletChecked);
746
+ const hashResults = await Promise.all(batchArray.map((batch) => {
747
+ const fileChunksArray = Object.keys(batch).map((name) => ({
748
+ name,
749
+ chunkIds: batch[name]
750
+ }));
751
+ return getChunkHashes(contract, fileChunksArray);
752
+ }));
753
+ hashResults.flat().forEach(({ name, chunkId, hash }) => {
754
+ allHashes[name][chunkId] = hash;
755
+ });
756
+ }
757
+ return allHashes;
758
+ }
759
+ // estimate cost
760
+ async #estimateCostByCallData(request) {
761
+ let { key, content, chunkHashes, maxFeePerGas: customMaxFee, maxPriorityFeePerGas: customTip, gasPrice: customGasPrice, maxChunkSize, maxChunks } = request;
762
+ if (toChunkSizeBytes(maxChunkSize) > CONTRACT_MAX_CHUNK_SIZE) {
763
+ throw new Error(`FlatDirectory: Chunk size ${maxChunkSize} KB exceeds the on-chain max payload of ${CONTRACT_MAX_CHUNK_SIZE} bytes.`);
764
+ }
765
+ const { chunkDataSize, calldataChunkCount } = this.#calculateCalldataChunkDetails(content, maxChunkSize);
766
+ if (chunkDataSize === -1) {
767
+ throw new Error(`FlatDirectory: Invalid upload content!`);
768
+ }
769
+ const hexName = stringToHex(key);
770
+ const fileContract = new ethers3.Contract(this.#contractAddrChecked, FlatDirectoryAbi, this.#walletChecked);
771
+ const [{ oldChunkCount, fileMode }, resolvedFees] = await Promise.all([
772
+ getUploadInfo(fileContract, hexName),
773
+ this.#txSenderChecked.resolveGasFees({ maxFeePerGas: customMaxFee, maxPriorityFeePerGas: customTip, gasPrice: customGasPrice })
774
+ ]);
775
+ if (fileMode !== 0 && fileMode !== 1) {
776
+ throw new Error(`FlatDirectory: This file does not support calldata upload!`);
777
+ }
778
+ if (!chunkHashes) {
779
+ const hashes = await this.#fetchChunkHashes([{ key, chunkCount: oldChunkCount }], maxChunks);
780
+ chunkHashes = hashes[key];
781
+ }
782
+ const effectiveGasPrice = resolvedFees.effectiveGasPrice;
783
+ let totalGasCost = 0n;
784
+ if (calldataChunkCount < oldChunkCount) {
785
+ const truncateGas = await stableRetry(() => fileContract["truncate"].estimateGas(hexName, calldataChunkCount));
786
+ totalGasCost += effectiveGasPrice * truncateGas;
787
+ }
788
+ let overwriteGasLimit = 0n;
789
+ let appendGasLimit = 0n;
790
+ const estimateChunk = (chunkId, hexData) => stableRetry(
791
+ () => fileContract["writeChunkByCalldata"].estimateGas(hexName, chunkId, hexData)
792
+ );
793
+ for (let i = 0; i < calldataChunkCount; i++) {
794
+ const chunk = await getContentChunk(content, i * chunkDataSize, (i + 1) * chunkDataSize);
795
+ if (i < chunkHashes.length && ethers3.keccak256(chunk) === chunkHashes[i]) {
796
+ continue;
797
+ }
798
+ const hexData = ethers3.hexlify(chunk);
799
+ const isAppend = i >= oldChunkCount;
800
+ const estChunkId = isAppend ? oldChunkCount : i;
801
+ let chunkGas;
802
+ if (i === calldataChunkCount - 1) {
803
+ chunkGas = await estimateChunk(estChunkId, hexData);
804
+ } else if (isAppend) {
805
+ if (appendGasLimit === 0n) {
806
+ appendGasLimit = await estimateChunk(estChunkId, hexData);
807
+ }
808
+ chunkGas = appendGasLimit;
809
+ } else {
810
+ if (overwriteGasLimit === 0n) {
811
+ overwriteGasLimit = await estimateChunk(estChunkId, hexData);
812
+ }
813
+ chunkGas = overwriteGasLimit;
814
+ }
815
+ totalGasCost += effectiveGasPrice * chunkGas;
816
+ }
817
+ return {
818
+ storageCost: 0n,
819
+ gasCost: totalGasCost
820
+ };
821
+ }
822
+ // upload
823
+ async #uploadByCalldata(request) {
824
+ let totalUploadChunks = 0, totalUploadSize = 0;
825
+ let totalCost = 0n;
826
+ let { key, content, callback, chunkHashes, maxFeePerGas, maxPriorityFeePerGas, gasPrice, maxChunkSize, maxChunks } = request;
827
+ const gasFee = { maxFeePerGas, maxPriorityFeePerGas, gasPrice };
828
+ if (toChunkSizeBytes(maxChunkSize) > CONTRACT_MAX_CHUNK_SIZE) {
829
+ callback.onFail(new Error(`FlatDirectory: Chunk size ${maxChunkSize} KB exceeds the on-chain max payload of ${CONTRACT_MAX_CHUNK_SIZE} bytes.`));
830
+ callback.onFinish(totalUploadChunks, totalUploadSize, totalCost);
831
+ return;
832
+ }
833
+ const { chunkDataSize, calldataChunkCount } = this.#calculateCalldataChunkDetails(content, maxChunkSize);
834
+ if (chunkDataSize === -1) {
835
+ callback.onFail(new Error(`FlatDirectory: Invalid upload content!`));
836
+ callback.onFinish(totalUploadChunks, totalUploadSize, totalCost);
837
+ return;
838
+ }
839
+ const hexName = stringToHex(key);
840
+ const fileContract = new ethers3.Contract(this.#contractAddrChecked, FlatDirectoryAbi, this.#walletChecked);
841
+ const { oldChunkCount, fileMode } = await getUploadInfo(fileContract, hexName);
842
+ if (fileMode !== 0 && fileMode !== 1) {
843
+ callback.onFail(new Error(`FlatDirectory: This file does not support calldata upload!`));
844
+ callback.onFinish(totalUploadChunks, totalUploadSize, totalCost);
845
+ return;
846
+ }
847
+ let resolvedFees;
848
+ try {
849
+ resolvedFees = await this.#txSenderChecked.resolveGasFees(gasFee);
850
+ } catch (e) {
851
+ callback.onFail(e);
852
+ callback.onFinish(totalUploadChunks, totalUploadSize, totalCost);
853
+ return;
854
+ }
855
+ const clearResult = await this.#clearOldFile(
856
+ fileContract,
857
+ hexName,
858
+ calldataChunkCount,
859
+ oldChunkCount,
860
+ resolvedFees
861
+ );
862
+ totalCost += clearResult.gasCost;
863
+ if (!clearResult.success) {
864
+ callback.onFail(new Error(`FlatDirectory: Failed to truncate old data!`));
865
+ callback.onFinish(totalUploadChunks, totalUploadSize, totalCost);
866
+ return;
867
+ }
868
+ if (!chunkHashes) {
869
+ try {
870
+ const hashes = await this.#fetchChunkHashes([{ key, chunkCount: oldChunkCount }], maxChunks);
871
+ chunkHashes = hashes[key];
872
+ } catch (e) {
873
+ callback.onFail(e);
874
+ callback.onFinish(totalUploadChunks, totalUploadSize, totalCost);
875
+ return;
876
+ }
877
+ }
878
+ for (let i = 0; i < calldataChunkCount; i++) {
879
+ const chunk = await getContentChunk(content, i * chunkDataSize, (i + 1) * chunkDataSize);
880
+ if (i < chunkHashes.length && ethers3.keccak256(chunk) === chunkHashes[i]) {
881
+ callback.onProgress(i, calldataChunkCount, false);
882
+ continue;
883
+ }
884
+ let uploadResult;
885
+ try {
886
+ const txResponse = await this.#sendCalldataTx(
887
+ fileContract,
888
+ key,
889
+ hexName,
890
+ i,
891
+ chunk,
892
+ resolvedFees,
893
+ callback
894
+ );
895
+ uploadResult = await this.#txSenderChecked.getTransactionResult(txResponse.hash);
896
+ } catch (e) {
897
+ callback.onFail(e);
898
+ break;
899
+ }
900
+ totalCost += uploadResult.txCost.normalGasCost;
901
+ if (!uploadResult.success) {
902
+ callback.onFail(new Error("FlatDirectory: Sending transaction failed."));
903
+ break;
904
+ }
905
+ callback.onProgress(i, calldataChunkCount, true);
906
+ totalUploadChunks++;
907
+ totalUploadSize += chunk.length;
908
+ }
909
+ callback.onFinish(totalUploadChunks, totalUploadSize, totalCost);
910
+ }
911
+ async #clearOldFile(contract, key, chunkLength, oldChunkLength, resolvedFees) {
912
+ if (oldChunkLength <= chunkLength) {
913
+ return { success: true, gasCost: 0n };
914
+ }
915
+ try {
916
+ const tx = await contract.truncate.populateTransaction(key, chunkLength);
917
+ this.#applyGasFees(tx, resolvedFees);
918
+ const txResponse = await this.#txSenderChecked.sendTx(tx);
919
+ this.#log(`Truncate transaction sent (Key: ${key}, New length: ${chunkLength}). Hash: ${txResponse.hash}`);
920
+ let receipt;
921
+ try {
922
+ receipt = await txResponse.wait();
923
+ } catch {
924
+ const result = await this.#txSenderChecked.getTransactionResult(txResponse.hash).catch(() => null);
925
+ return {
926
+ success: result?.success === true,
927
+ gasCost: result?.txCost.normalGasCost ?? 0n
928
+ };
929
+ }
930
+ const gasCost = receipt ? receipt.gasUsed * receipt.gasPrice : 0n;
931
+ return { success: receipt?.status === 1, gasCost };
932
+ } catch (e) {
933
+ this.#log(`Failed to truncate old data for file (Key: ${key}). ${e.message || e}`, true);
934
+ return { success: false, gasCost: 0n };
935
+ }
936
+ }
937
+ // call data helper
938
+ #calculateCalldataChunkDetails(content, maxChunkSize) {
939
+ const maxChunkSizeBytes = toChunkSizeBytes(maxChunkSize);
940
+ const getChunkInfo = (size) => ({
941
+ chunkDataSize: size > maxChunkSizeBytes ? maxChunkSizeBytes : size,
942
+ calldataChunkCount: size > maxChunkSizeBytes ? Math.ceil(size / maxChunkSizeBytes) : 1
943
+ });
944
+ if (isFile(content)) {
945
+ return getChunkInfo(content.size);
946
+ } else if (isBuffer(content)) {
947
+ return getChunkInfo(content.length);
948
+ }
949
+ return { chunkDataSize: -1, calldataChunkCount: 1 };
950
+ }
951
+ async #sendCalldataTx(fileContract, key, hexName, chunkId, chunk, resolvedFees, callback) {
952
+ const hexData = ethers3.hexlify(chunk);
953
+ const tx = await fileContract["writeChunkByCalldata"].populateTransaction(hexName, chunkId, hexData);
954
+ this.#applyGasFees(tx, resolvedFees);
955
+ const txResponse = await this.#txSenderChecked.sendTx(tx);
956
+ this.#logTransactionHash(key, chunkId, txResponse.hash, callback);
957
+ return txResponse;
958
+ }
959
+ /**
960
+ * Copy resolved gas fees onto a transaction request, by fee model:
961
+ * legacy chains use gasPrice, EIP-1559 chains use max/priority fee fields.
962
+ */
963
+ #applyGasFees(tx, resolvedFees) {
964
+ if (resolvedFees.type === "legacy") {
965
+ tx.gasPrice = resolvedFees.gasPrice;
966
+ return;
967
+ }
968
+ tx.maxFeePerGas = resolvedFees.maxFeePerGas;
969
+ tx.maxPriorityFeePerGas = resolvedFees.maxPriorityFeePerGas;
970
+ }
971
+ #logTransactionHash(key, chunkId, hash, callback) {
972
+ const primaryMessage = `Transaction hash: ${hash} for chunk ${chunkId}.`;
973
+ const fullMessage = `${primaryMessage} (Key: ${key})`;
974
+ this.#log(fullMessage);
975
+ if (callback?.onTransactionSent) {
976
+ callback.onTransactionSent(hash, chunkId);
977
+ }
978
+ }
979
+ #log(message, isError = false) {
980
+ if (!this.#isLoggingEnabled) return;
981
+ const prefix = "FlatDirectory: ";
982
+ if (isError) {
983
+ console.error(`${prefix}${message}`);
984
+ } else {
985
+ console.log(`${prefix}${message}`);
986
+ }
987
+ }
988
+ // -------------------- Getters --------------------
989
+ get #contractAddrChecked() {
990
+ if (!this.#contractAddr) throw new Error("FlatDirectory: Not deployed!");
991
+ return this.#contractAddr;
992
+ }
993
+ get #ethStorageRpcChecked() {
994
+ if (!this.#ethStorageRpc) throw new Error("FlatDirectory: 'ethStorageRpc' required.");
995
+ return this.#ethStorageRpc;
996
+ }
997
+ get #walletChecked() {
998
+ if (!this.#wallet) throw new Error("FlatDirectory: Private key required.");
999
+ return this.#wallet;
1000
+ }
1001
+ get #txSenderChecked() {
1002
+ if (!this.#txSender) throw new Error("FlatDirectory: TxSender not initialized.");
1003
+ return this.#txSender;
1004
+ }
1005
+ };
1006
+ export {
1007
+ AVALANCHE_GAS_CHAIN_IDS,
1008
+ AVALANCHE_MIN_BASE_FEE_PER_GAS,
1009
+ BASE_FEE_MULTIPLIER_DENOMINATOR,
1010
+ BASE_FEE_MULTIPLIER_NUMERATOR,
1011
+ CALLDATA_CHUNK_OVERHEAD,
1012
+ CONTRACT_MAX_CHUNK_SIZE,
1013
+ DEFAULT_MAX_CHUNK_SIZE_KB,
1014
+ DEFAULT_PRIORITY_FEE_PER_GAS,
1015
+ ETHSTORAGE_MAPPING,
1016
+ FlatDirectory,
1017
+ FlatDirectoryAbi,
1018
+ FlatDirectoryBytecode,
1019
+ LEGACY_GAS_CHAIN_IDS,
1020
+ MAX_CHUNKS,
1021
+ toChunkSizeBytes,
1022
+ utils_exports as utils
1023
+ };