UNPKG

@depay/web3-payments

Version:

JavaScript library to scan crypto wallets for liquefiable assets and perform cost-effective, auto-converted payments on-chain.

1,365 lines (1,203 loc) 198 kB
(function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('@depay/web3-blockchains'), require('@depay/solana-web3.js'), require('ethers'), require('@depay/web3-exchanges-svm'), require('@depay/web3-tokens-svm')) : typeof define === 'function' && define.amd ? define(['exports', '@depay/web3-blockchains', '@depay/solana-web3.js', 'ethers', '@depay/web3-exchanges-svm', '@depay/web3-tokens-svm'], factory) : (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.Web3Payments = {}, global.Web3Blockchains, global.SolanaWeb3js, global.ethers, global.Web3Exchanges, global.Web3Tokens)); })(this, (function (exports, Blockchains, solanaWeb3_js, ethers, Exchanges, Token$1) { 'use strict'; function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; } var Blockchains__default = /*#__PURE__*/_interopDefaultLegacy(Blockchains); var Exchanges__default = /*#__PURE__*/_interopDefaultLegacy(Exchanges); var Token__default = /*#__PURE__*/_interopDefaultLegacy(Token$1); var routers$1 = { solana: { address: 'DePayR1gQfDmViCPKctnZXNtUgqRwnEqMax8LX9ho1Zg', exchanges: { orca: 'whirLbMiicVdio4qvUfM5KAg6Ct8VwpYzGff3uctyCc', raydiumCP: 'CPMMoo8L3F4NbTegBCKVNunggL7H1ZpdTHKxQB5qKP1C', raydiumCL: 'CAMMCzo5YL8w4VFF8KVHrK22GGUsp5VTaW7grrKgrWqK', }, alt: '8bYq3tcwX1NM2K2JYMjrEqAPtCXFPCjzPazFothc618e', api: { createEscrowSolAccount: { anchorDiscriminator: new solanaWeb3_js.BN("2482112285991870004"), layout: solanaWeb3_js.struct([ solanaWeb3_js.u64("anchorDiscriminator"), ]) }, createEscrowTokenAccount: { anchorDiscriminator: new solanaWeb3_js.BN("16156440424245087"), layout: solanaWeb3_js.struct([ solanaWeb3_js.u64("anchorDiscriminator"), ]) }, routeSol: { anchorDiscriminator: new solanaWeb3_js.BN("6497164560834983274"), layout: solanaWeb3_js.struct([ solanaWeb3_js.u64("anchorDiscriminator"), solanaWeb3_js.u64("paymentAmount"), solanaWeb3_js.u64("feeAmount"), solanaWeb3_js.u64("feeAmount2"), solanaWeb3_js.u64("protocolAmount"), solanaWeb3_js.i64("deadline"), ]) }, routeToken: { anchorDiscriminator: new solanaWeb3_js.BN("13483873682232752277"), layout: solanaWeb3_js.struct([ solanaWeb3_js.u64("anchorDiscriminator"), solanaWeb3_js.u64("paymentAmount"), solanaWeb3_js.u64("feeAmount"), solanaWeb3_js.u64("feeAmount2"), solanaWeb3_js.u64("protocolAmount"), solanaWeb3_js.i64("deadline"), ]) }, routeOrcaSwap: { anchorDiscriminator: new solanaWeb3_js.BN("9797248061404332986"), layout: solanaWeb3_js.struct([ solanaWeb3_js.u64("anchorDiscriminator"), solanaWeb3_js.u64("amountIn"), solanaWeb3_js.bool("aToB"), solanaWeb3_js.u64("paymentAmount"), solanaWeb3_js.u64("feeAmount"), solanaWeb3_js.u64("feeAmount2"), solanaWeb3_js.u64("protocolAmount"), solanaWeb3_js.i64("deadline"), ]) }, routeOrcaSwapSolOut: { anchorDiscriminator: new solanaWeb3_js.BN("13662217913752830165"), layout: solanaWeb3_js.struct([ solanaWeb3_js.u64("anchorDiscriminator"), solanaWeb3_js.u64("amountIn"), solanaWeb3_js.bool("aToB"), solanaWeb3_js.u64("paymentAmount"), solanaWeb3_js.u64("feeAmount"), solanaWeb3_js.u64("feeAmount2"), solanaWeb3_js.u64("protocolAmount"), solanaWeb3_js.i64("deadline"), ]) }, routeOrcaSwapSolIn: { anchorDiscriminator: new solanaWeb3_js.BN("16115018480206947614"), layout: solanaWeb3_js.struct([ solanaWeb3_js.u64("anchorDiscriminator"), solanaWeb3_js.u64("amountIn"), solanaWeb3_js.bool("aToB"), solanaWeb3_js.u64("paymentAmount"), solanaWeb3_js.u64("feeAmount"), solanaWeb3_js.u64("feeAmount2"), solanaWeb3_js.u64("protocolAmount"), solanaWeb3_js.i64("deadline"), ]) }, routeOrcaTwoHopSwap: { anchorDiscriminator: new solanaWeb3_js.BN("15695720599845325801"), layout: solanaWeb3_js.struct([ solanaWeb3_js.u64("anchorDiscriminator"), solanaWeb3_js.u64("amountInOne"), solanaWeb3_js.u64("amountInTwo"), solanaWeb3_js.bool("aToBOne"), solanaWeb3_js.bool("aToBTwo"), solanaWeb3_js.u64("paymentAmount"), solanaWeb3_js.u64("feeAmount"), solanaWeb3_js.u64("feeAmount2"), solanaWeb3_js.u64("protocolAmount"), solanaWeb3_js.i64("deadline"), ]) }, routeOrcaTwoHopSwapSolOut: { anchorDiscriminator: new solanaWeb3_js.BN("15074061855608091530"), layout: solanaWeb3_js.struct([ solanaWeb3_js.u64("anchorDiscriminator"), solanaWeb3_js.u64("amountInOne"), solanaWeb3_js.u64("amountInTwo"), solanaWeb3_js.bool("aToBOne"), solanaWeb3_js.bool("aToBTwo"), solanaWeb3_js.u64("paymentAmount"), solanaWeb3_js.u64("feeAmount"), solanaWeb3_js.u64("feeAmount2"), solanaWeb3_js.u64("protocolAmount"), solanaWeb3_js.i64("deadline"), ]) }, routeOrcaTwoHopSwapSolIn: { anchorDiscriminator: new solanaWeb3_js.BN("2678451299937372540"), layout: solanaWeb3_js.struct([ solanaWeb3_js.u64("anchorDiscriminator"), solanaWeb3_js.u64("amountInOne"), solanaWeb3_js.u64("amountInTwo"), solanaWeb3_js.bool("aToBOne"), solanaWeb3_js.bool("aToBTwo"), solanaWeb3_js.u64("paymentAmount"), solanaWeb3_js.u64("feeAmount"), solanaWeb3_js.u64("feeAmount2"), solanaWeb3_js.u64("protocolAmount"), solanaWeb3_js.i64("deadline"), ]) }, routeRaydiumClSwap: { anchorDiscriminator: new solanaWeb3_js.BN("2954182973248174268"), layout: solanaWeb3_js.struct([ solanaWeb3_js.u64("anchorDiscriminator"), solanaWeb3_js.u64("amountIn"), solanaWeb3_js.u64("paymentAmount"), solanaWeb3_js.u64("feeAmount"), solanaWeb3_js.u64("feeAmount2"), solanaWeb3_js.u64("protocolAmount"), solanaWeb3_js.i64("deadline"), ]) }, routeRaydiumClSwapSolOut: { anchorDiscriminator: new solanaWeb3_js.BN("18389700643710627390"), layout: solanaWeb3_js.struct([ solanaWeb3_js.u64("anchorDiscriminator"), solanaWeb3_js.u64("amountIn"), solanaWeb3_js.u64("paymentAmount"), solanaWeb3_js.u64("feeAmount"), solanaWeb3_js.u64("feeAmount2"), solanaWeb3_js.u64("protocolAmount"), solanaWeb3_js.i64("deadline"), ]) }, routeRaydiumClSwapSolIn: { anchorDiscriminator: new solanaWeb3_js.BN("564150378912976829"), layout: solanaWeb3_js.struct([ solanaWeb3_js.u64("anchorDiscriminator"), solanaWeb3_js.u64("amountIn"), solanaWeb3_js.u64("paymentAmount"), solanaWeb3_js.u64("feeAmount"), solanaWeb3_js.u64("feeAmount2"), solanaWeb3_js.u64("protocolAmount"), solanaWeb3_js.i64("deadline"), ]) }, routeRaydiumClTwoHopSwap: { anchorDiscriminator: new solanaWeb3_js.BN("3828760301615328551"), layout: solanaWeb3_js.struct([ solanaWeb3_js.u64("anchorDiscriminator"), solanaWeb3_js.u64("amountInOne"), solanaWeb3_js.u64("amountInTwo"), solanaWeb3_js.u64("paymentAmount"), solanaWeb3_js.u64("feeAmount"), solanaWeb3_js.u64("feeAmount2"), solanaWeb3_js.u64("protocolAmount"), solanaWeb3_js.i64("deadline"), solanaWeb3_js.u8("remainingAccountsSplit"), ]) }, routeRaydiumClTwoHopSwapSolOut: { anchorDiscriminator: new solanaWeb3_js.BN("11373220799455718953"), layout: solanaWeb3_js.struct([ solanaWeb3_js.u64("anchorDiscriminator"), solanaWeb3_js.u64("amountInOne"), solanaWeb3_js.u64("amountInTwo"), solanaWeb3_js.u64("paymentAmount"), solanaWeb3_js.u64("feeAmount"), solanaWeb3_js.u64("feeAmount2"), solanaWeb3_js.u64("protocolAmount"), solanaWeb3_js.i64("deadline"), solanaWeb3_js.u8("remainingAccountsSplit"), ]) }, routeRaydiumClTwoHopSwapSolIn: { anchorDiscriminator: new solanaWeb3_js.BN("1635173573630140652"), layout: solanaWeb3_js.struct([ solanaWeb3_js.u64("anchorDiscriminator"), solanaWeb3_js.u64("amountInOne"), solanaWeb3_js.u64("amountInTwo"), solanaWeb3_js.u64("paymentAmount"), solanaWeb3_js.u64("feeAmount"), solanaWeb3_js.u64("feeAmount2"), solanaWeb3_js.u64("protocolAmount"), solanaWeb3_js.i64("deadline"), solanaWeb3_js.u8("remainingAccountsSplit"), ]) }, routeRaydiumCpSwap: { anchorDiscriminator: new solanaWeb3_js.BN("7437765211943645137"), layout: solanaWeb3_js.struct([ solanaWeb3_js.u64("anchorDiscriminator"), solanaWeb3_js.u64("amountIn"), solanaWeb3_js.u64("paymentAmount"), solanaWeb3_js.u64("feeAmount"), solanaWeb3_js.u64("feeAmount2"), solanaWeb3_js.u64("protocolAmount"), solanaWeb3_js.i64("deadline"), ]) }, routeRaydiumCpSwapSolOut: { anchorDiscriminator: new solanaWeb3_js.BN("9045257739866411286"), layout: solanaWeb3_js.struct([ solanaWeb3_js.u64("anchorDiscriminator"), solanaWeb3_js.u64("amountIn"), solanaWeb3_js.u64("paymentAmount"), solanaWeb3_js.u64("feeAmount"), solanaWeb3_js.u64("feeAmount2"), solanaWeb3_js.u64("protocolAmount"), solanaWeb3_js.i64("deadline"), ]) }, routeRaydiumCpSwapSolIn: { anchorDiscriminator: new solanaWeb3_js.BN("432305509198797158"), layout: solanaWeb3_js.struct([ solanaWeb3_js.u64("anchorDiscriminator"), solanaWeb3_js.u64("amountIn"), solanaWeb3_js.u64("paymentAmount"), solanaWeb3_js.u64("feeAmount"), solanaWeb3_js.u64("feeAmount2"), solanaWeb3_js.u64("protocolAmount"), solanaWeb3_js.i64("deadline"), ]) }, routeRaydiumCpTwoHopSwap: { anchorDiscriminator: new solanaWeb3_js.BN("3384279312781294015"), layout: solanaWeb3_js.struct([ solanaWeb3_js.u64("anchorDiscriminator"), solanaWeb3_js.u64("amountInOne"), solanaWeb3_js.u64("amountInTwo"), solanaWeb3_js.u64("paymentAmount"), solanaWeb3_js.u64("feeAmount"), solanaWeb3_js.u64("feeAmount2"), solanaWeb3_js.u64("protocolAmount"), solanaWeb3_js.i64("deadline"), ]) }, routeRaydiumCpTwoHopSwapSolOut: { anchorDiscriminator: new solanaWeb3_js.BN("18428464202744806632"), layout: solanaWeb3_js.struct([ solanaWeb3_js.u64("anchorDiscriminator"), solanaWeb3_js.u64("amountInOne"), solanaWeb3_js.u64("amountInTwo"), solanaWeb3_js.u64("paymentAmount"), solanaWeb3_js.u64("feeAmount"), solanaWeb3_js.u64("feeAmount2"), solanaWeb3_js.u64("protocolAmount"), solanaWeb3_js.i64("deadline"), ]) }, routeRaydiumCpTwoHopSwapSolIn: { anchorDiscriminator: new solanaWeb3_js.BN("16266677464406446072"), layout: solanaWeb3_js.struct([ solanaWeb3_js.u64("anchorDiscriminator"), solanaWeb3_js.u64("amountInOne"), solanaWeb3_js.u64("amountInTwo"), solanaWeb3_js.u64("paymentAmount"), solanaWeb3_js.u64("feeAmount"), solanaWeb3_js.u64("feeAmount2"), solanaWeb3_js.u64("protocolAmount"), solanaWeb3_js.i64("deadline"), ]) } } }, }; let _window; let getWindow = () => { if(_window) { return _window } if (typeof global == 'object') { _window = global; } else { _window = window; } return _window }; const getConfiguration = () =>{ if(getWindow()._Web3ClientConfiguration === undefined) { getWindow()._Web3ClientConfiguration = {}; } return getWindow()._Web3ClientConfiguration }; function _optionalChain$5$1(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; } const BATCH_INTERVAL$1 = 10; const CHUNK_SIZE$1 = 50; const MAX_RETRY$1 = 5; class StaticJsonRpcBatchProvider extends ethers.ethers.providers.JsonRpcProvider { constructor(url, network, endpoints, failover) { super(url); this._network = network; this._endpoint = url; this._endpoints = endpoints; this._failover = failover; this._pendingBatch = []; } handleError(error, attempt, chunk) { if(attempt < MAX_RETRY$1 && error) { const index = this._endpoints.indexOf(this._endpoint)+1; this._failover(); this._endpoint = index >= this._endpoints.length ? this._endpoints[0] : this._endpoints[index]; this.requestChunk(chunk, this._endpoint, attempt+1); } else { chunk.forEach((inflightRequest) => { inflightRequest.reject(error); }); } } detectNetwork() { return Promise.resolve(Blockchains__default["default"].findByName(this._network).id) } batchRequest(batch, attempt) { return new Promise((resolve, reject) => { if (batch.length === 0) resolve([]); // Do nothing if requests is empty fetch( this._endpoint, { method: 'POST', body: JSON.stringify(batch), headers: { 'Content-Type': 'application/json' }, signal: _optionalChain$5$1([AbortSignal, 'optionalAccess', _ => _.timeout]) ? AbortSignal.timeout(10000) : undefined // 10-second timeout } ).then((response)=>{ if(response.ok) { response.json().then((parsedJson)=>{ if(parsedJson.find((entry)=>{ return _optionalChain$5$1([entry, 'optionalAccess', _2 => _2.error]) && [-32062,-32016].includes(_optionalChain$5$1([entry, 'optionalAccess', _3 => _3.error, 'optionalAccess', _4 => _4.code])) })) { if(attempt < MAX_RETRY$1) { reject('Error in batch found!'); } else { resolve(parsedJson); } } else { resolve(parsedJson); } }).catch(reject); } else { reject(`${response.status} ${response.text}`); } }).catch(reject); }) } requestChunk(chunk, endpoint, attempt) { const batch = chunk.map((inflight) => inflight.request); try { return this.batchRequest(batch, attempt) .then((result) => { // For each result, feed it to the correct Promise, depending // on whether it was a success or error chunk.forEach((inflightRequest, index) => { const payload = result[index]; if (_optionalChain$5$1([payload, 'optionalAccess', _5 => _5.error])) { const error = new Error(payload.error.message); error.code = payload.error.code; error.data = payload.error.data; inflightRequest.reject(error); } else if(_optionalChain$5$1([payload, 'optionalAccess', _6 => _6.result])) { inflightRequest.resolve(payload.result); } else { inflightRequest.reject(); } }); }).catch((error) => this.handleError(error, attempt, chunk)) } catch (error){ this.handleError(error, attempt, chunk); } } send(method, params) { const request = { method: method, params: params, id: (this._nextId++), jsonrpc: "2.0" }; if (this._pendingBatch == null) { this._pendingBatch = []; } const inflightRequest = { request, resolve: null, reject: null }; const promise = new Promise((resolve, reject) => { inflightRequest.resolve = resolve; inflightRequest.reject = reject; }); this._pendingBatch.push(inflightRequest); if (!this._pendingBatchAggregator) { // Schedule batch for next event loop + short duration this._pendingBatchAggregator = setTimeout(() => { // Get the current batch and clear it, so new requests // go into the next batch const batch = this._pendingBatch; this._pendingBatch = []; this._pendingBatchAggregator = null; // Prepare Chunks of CHUNK_SIZE const chunks = []; for (let i = 0; i < Math.ceil(batch.length / CHUNK_SIZE$1); i++) { chunks[i] = batch.slice(i*CHUNK_SIZE$1, (i+1)*CHUNK_SIZE$1); } chunks.forEach((chunk)=>{ // Get the request as an array of requests chunk.map((inflight) => inflight.request); return this.requestChunk(chunk, this._endpoint, 1) }); }, getConfiguration().batchInterval || BATCH_INTERVAL$1); } return promise } } function _optionalChain$4$1(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; } const getAllProviders$1 = ()=> { if(getWindow()._Web3ClientProviders == undefined) { getWindow()._Web3ClientProviders = {}; } return getWindow()._Web3ClientProviders }; const setProvider$2 = (blockchain, provider)=> { if(provider == undefined) { return } if(getAllProviders$1()[blockchain] === undefined) { getAllProviders$1()[blockchain] = []; } const index = getAllProviders$1()[blockchain].indexOf(provider); if(index > -1) { getAllProviders$1()[blockchain].splice(index, 1); } getAllProviders$1()[blockchain].unshift(provider); }; const setProviderEndpoints$2 = async (blockchain, endpoints, detectFastest = true)=> { getAllProviders$1()[blockchain] = endpoints.map((endpoint, index)=> new StaticJsonRpcBatchProvider(endpoint, blockchain, endpoints, ()=>{ if(getAllProviders$1()[blockchain].length === 1) { setProviderEndpoints$2(blockchain, endpoints, detectFastest); } else { getAllProviders$1()[blockchain].splice(index, 1); } }) ); let provider; let window = getWindow(); if( window.fetch == undefined || (typeof process != 'undefined' && process['env'] && process['env']['NODE_ENV'] == 'test') || (typeof window.cy != 'undefined') || detectFastest === false ) { provider = getAllProviders$1()[blockchain][0]; } else { let responseTimes = await Promise.all(endpoints.map((endpoint)=>{ return new Promise(async (resolve)=>{ let timeout = 900; let before = new Date().getTime(); setTimeout(()=>resolve(timeout), timeout); let response; try { response = await fetch(endpoint, { method: 'POST', headers: { 'Accept': 'application/json', 'Content-Type': 'application/json' }, referrer: "", referrerPolicy: "no-referrer", body: JSON.stringify({ method: 'net_version', id: 1, jsonrpc: '2.0' }), signal: _optionalChain$4$1([AbortSignal, 'optionalAccess', _ => _.timeout]) ? AbortSignal.timeout(10000) : undefined // 10-second timeout }); } catch (e) {} if(!_optionalChain$4$1([response, 'optionalAccess', _2 => _2.ok])) { return resolve(999) } let after = new Date().getTime(); resolve(after-before); }) })); const fastestResponse = Math.min(...responseTimes); const fastestIndex = responseTimes.indexOf(fastestResponse); provider = getAllProviders$1()[blockchain][fastestIndex]; } setProvider$2(blockchain, provider); }; const getProvider$2 = async (blockchain)=> { let providers = getAllProviders$1(); if(providers && providers[blockchain]){ return providers[blockchain][0] } let window = getWindow(); if(window._Web3ClientGetProviderPromise && window._Web3ClientGetProviderPromise[blockchain]) { return await window._Web3ClientGetProviderPromise[blockchain] } if(!window._Web3ClientGetProviderPromise){ window._Web3ClientGetProviderPromise = {}; } window._Web3ClientGetProviderPromise[blockchain] = new Promise(async(resolve)=> { await setProviderEndpoints$2(blockchain, Blockchains__default["default"][blockchain].endpoints); resolve(getWindow()._Web3ClientProviders[blockchain][0]); }); return await window._Web3ClientGetProviderPromise[blockchain] }; const getProviders$2 = async(blockchain)=>{ let providers = getAllProviders$1(); if(providers && providers[blockchain]){ return providers[blockchain] } let window = getWindow(); if(window._Web3ClientGetProvidersPromise && window._Web3ClientGetProvidersPromise[blockchain]) { return await window._Web3ClientGetProvidersPromise[blockchain] } if(!window._Web3ClientGetProvidersPromise){ window._Web3ClientGetProvidersPromise = {}; } window._Web3ClientGetProvidersPromise[blockchain] = new Promise(async(resolve)=> { await setProviderEndpoints$2(blockchain, Blockchains__default["default"][blockchain].endpoints); resolve(getWindow()._Web3ClientProviders[blockchain]); }); return await window._Web3ClientGetProvidersPromise[blockchain] }; var EVM = { getProvider: getProvider$2, getProviders: getProviders$2, setProviderEndpoints: setProviderEndpoints$2, setProvider: setProvider$2, }; function _optionalChain$3$1(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; } const BATCH_INTERVAL = 10; const CHUNK_SIZE = 25; const MAX_RETRY = 10; class StaticJsonRpcSequentialProvider extends solanaWeb3_js.Connection { constructor(url, network, endpoints, failover) { super(url); this._provider = new solanaWeb3_js.Connection(url); this._network = network; this._endpoint = url; this._endpoints = endpoints; this._failover = failover; this._pendingBatch = []; this._rpcRequest = this._rpcRequestReplacement.bind(this); } handleError(error, attempt, chunk) { if(attempt < MAX_RETRY) { const index = this._endpoints.indexOf(this._endpoint)+1; this._endpoint = index >= this._endpoints.length ? this._endpoints[0] : this._endpoints[index]; this._provider = new solanaWeb3_js.Connection(this._endpoint); this.requestChunk(chunk, attempt+1); } else { chunk.forEach((inflightRequest) => { inflightRequest.reject(error); }); } } batchRequest(requests, attempt) { return new Promise((resolve, reject) => { if (requests.length === 0) resolve([]); // Do nothing if requests is empty const batch = requests.map(params => { return this._rpcClient.request(params.methodName, params.args) }); fetch( this._endpoint, { method: 'POST', body: JSON.stringify(batch), headers: { 'Content-Type': 'application/json' }, signal: _optionalChain$3$1([AbortSignal, 'optionalAccess', _ => _.timeout]) ? AbortSignal.timeout(60000) : undefined // 60-second timeout } ).then((response)=>{ if(response.ok) { response.json().then((parsedJson)=>{ if(parsedJson.find((entry)=>_optionalChain$3$1([entry, 'optionalAccess', _2 => _2.error]))) { if(attempt < MAX_RETRY) { reject('Error in batch found!'); } else { resolve(parsedJson); } } else { resolve(parsedJson); } }).catch(reject); } else { reject(`${response.status} ${response.text}`); } }).catch(reject); }) } requestChunk(chunk, attempt) { const batch = chunk.map((inflight) => inflight.request); try { return this.batchRequest(batch, attempt) .then((result) => { chunk.forEach((inflightRequest, index) => { const payload = result[index]; if (_optionalChain$3$1([payload, 'optionalAccess', _3 => _3.error])) { const error = new Error(payload.error.message); error.code = payload.error.code; error.data = payload.error.data; inflightRequest.reject(error); } else if(payload) { inflightRequest.resolve(payload); } else { inflightRequest.reject(); } }); }).catch((error)=>this.handleError(error, attempt, chunk)) } catch (error){ return this.handleError(error, attempt, chunk) } } _rpcRequestReplacement(methodName, args) { const request = { methodName, args }; if (this._pendingBatch == null) { this._pendingBatch = []; } const inflightRequest = { request, resolve: null, reject: null }; const promise = new Promise((resolve, reject) => { inflightRequest.resolve = resolve; inflightRequest.reject = reject; }); this._pendingBatch.push(inflightRequest); if (!this._pendingBatchAggregator) { // Schedule batch for next event loop + short duration this._pendingBatchAggregator = setTimeout(() => { // Get the current batch and clear it, so new requests // go into the next batch const batch = this._pendingBatch; this._pendingBatch = []; this._pendingBatchAggregator = null; // Prepare Chunks of CHUNK_SIZE const chunks = []; for (let i = 0; i < Math.ceil(batch.length / CHUNK_SIZE); i++) { chunks[i] = batch.slice(i*CHUNK_SIZE, (i+1)*CHUNK_SIZE); } chunks.forEach((chunk)=>{ // Get the request as an array of requests chunk.map((inflight) => inflight.request); return this.requestChunk(chunk, 1) }); }, getConfiguration().batchInterval || BATCH_INTERVAL); } return promise } } function _optionalChain$2$1(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; } const getAllProviders = ()=> { if(getWindow()._Web3ClientProviders == undefined) { getWindow()._Web3ClientProviders = {}; } return getWindow()._Web3ClientProviders }; const setProvider$1 = (blockchain, provider)=> { if(provider == undefined) { return } if(getAllProviders()[blockchain] === undefined) { getAllProviders()[blockchain] = []; } const index = getAllProviders()[blockchain].indexOf(provider); if(index > -1) { getAllProviders()[blockchain].splice(index, 1); } getAllProviders()[blockchain].unshift(provider); }; const setProviderEndpoints$1 = async (blockchain, endpoints, detectFastest = true)=> { getAllProviders()[blockchain] = endpoints.map((endpoint, index)=> new StaticJsonRpcSequentialProvider(endpoint, blockchain, endpoints, ()=>{ if(getAllProviders()[blockchain].length === 1) { setProviderEndpoints$1(blockchain, endpoints, detectFastest); } else { getAllProviders()[blockchain].splice(index, 1); } }) ); let provider; let window = getWindow(); if( window.fetch == undefined || (typeof process != 'undefined' && process['env'] && process['env']['NODE_ENV'] == 'test') || (typeof window.cy != 'undefined') || detectFastest === false ) { provider = getAllProviders()[blockchain][0]; } else { let responseTimes = await Promise.all(endpoints.map((endpoint)=>{ return new Promise(async (resolve)=>{ let timeout = 900; let before = new Date().getTime(); setTimeout(()=>resolve(timeout), timeout); let response; try { response = await fetch(endpoint, { method: 'POST', headers: { 'Accept': 'application/json', 'Content-Type': 'application/json' }, referrer: "", referrerPolicy: "no-referrer", body: JSON.stringify({ method: 'getIdentity', id: 1, jsonrpc: '2.0' }), signal: _optionalChain$2$1([AbortSignal, 'optionalAccess', _ => _.timeout]) ? AbortSignal.timeout(60000) : undefined // 60-second timeout }); } catch (e) {} if(!_optionalChain$2$1([response, 'optionalAccess', _2 => _2.ok])) { return resolve(999) } let after = new Date().getTime(); resolve(after-before); }) })); const fastestResponse = Math.min(...responseTimes); const fastestIndex = responseTimes.indexOf(fastestResponse); provider = getAllProviders()[blockchain][fastestIndex]; } setProvider$1(blockchain, provider); }; const getProvider$1 = async (blockchain)=> { let providers = getAllProviders(); if(providers && providers[blockchain]){ return providers[blockchain][0] } let window = getWindow(); if(window._Web3ClientGetProviderPromise && window._Web3ClientGetProviderPromise[blockchain]) { return await window._Web3ClientGetProviderPromise[blockchain] } if(!window._Web3ClientGetProviderPromise){ window._Web3ClientGetProviderPromise = {}; } window._Web3ClientGetProviderPromise[blockchain] = new Promise(async(resolve)=> { await setProviderEndpoints$1(blockchain, Blockchains__default["default"][blockchain].endpoints); resolve(getWindow()._Web3ClientProviders[blockchain][0]); }); return await window._Web3ClientGetProviderPromise[blockchain] }; const getProviders$1 = async(blockchain)=>{ let providers = getAllProviders(); if(providers && providers[blockchain]){ return providers[blockchain] } let window = getWindow(); if(window._Web3ClientGetProvidersPromise && window._Web3ClientGetProvidersPromise[blockchain]) { return await window._Web3ClientGetProvidersPromise[blockchain] } if(!window._Web3ClientGetProvidersPromise){ window._Web3ClientGetProvidersPromise = {}; } window._Web3ClientGetProvidersPromise[blockchain] = new Promise(async(resolve)=> { await setProviderEndpoints$1(blockchain, Blockchains__default["default"][blockchain].endpoints); resolve(getWindow()._Web3ClientProviders[blockchain]); }); return await window._Web3ClientGetProvidersPromise[blockchain] }; var Solana = { getProvider: getProvider$1, getProviders: getProviders$1, setProviderEndpoints: setProviderEndpoints$1, setProvider: setProvider$1, }; let supported$2 = ['ethereum', 'bsc', 'polygon', 'solana', 'fantom', 'arbitrum', 'avalanche', 'gnosis', 'optimism', 'base', 'worldchain']; supported$2.evm = ['ethereum', 'bsc', 'polygon', 'fantom', 'arbitrum', 'avalanche', 'gnosis', 'optimism', 'base', 'worldchain']; supported$2.svm = ['solana']; function _optionalChain$1$1(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; } let getCacheStore = () => { if (getWindow()._Web3ClientCacheStore == undefined) { getWindow()._Web3ClientCacheStore = {}; } return getWindow()._Web3ClientCacheStore }; let getPromiseStore = () => { if (getWindow()._Web3ClientPromiseStore == undefined) { getWindow()._Web3ClientPromiseStore = {}; } return getWindow()._Web3ClientPromiseStore }; let set = function ({ key, value, expires }) { getCacheStore()[key] = { expiresAt: Date.now() + expires, value, }; }; let get = function ({ key, expires }) { let cachedEntry = getCacheStore()[key]; if (_optionalChain$1$1([cachedEntry, 'optionalAccess', _ => _.expiresAt]) > Date.now()) { return cachedEntry.value } }; let getPromise = function({ key }) { return getPromiseStore()[key] }; let setPromise = function({ key, promise }) { getPromiseStore()[key] = promise; return promise }; let deletePromise = function({ key }) { getPromiseStore()[key] = undefined; }; let cache = function ({ call, key, expires = 0 }) { return new Promise((resolve, reject)=>{ let value; key = JSON.stringify(key); // get existing promise (of a previous pending request asking for the exact same thing) let existingPromise = getPromise({ key }); if(existingPromise) { return existingPromise .then(resolve) .catch(reject) } setPromise({ key, promise: new Promise((resolveQueue, rejectQueue)=>{ if (expires === 0) { return call() .then((value)=>{ resolve(value); resolveQueue(value); }) .catch((error)=>{ reject(error); rejectQueue(error); }) } // get cached value value = get({ key, expires }); if (value) { resolve(value); resolveQueue(value); return value } // set new cache value call() .then((value)=>{ if (value) { set({ key, value, expires }); } resolve(value); resolveQueue(value); }) .catch((error)=>{ reject(error); rejectQueue(error); }); }) }).then(()=>{ deletePromise({ key }); }).catch(()=>{ deletePromise({ key }); }); }) }; // Periodically clean up expired cache entries (every 5 minutes), to prevent memory leaks if (typeof process == 'undefined' || process.env && "production" === 'test') { setInterval(() => { const store = getCacheStore(); const now = Date.now(); for (const key in store) { if (store[key].expiresAt < now) { delete store[key]; } } }, 10 * 60 * 1000); // 10 minutes in milliseconds } const getProvider = async (blockchain)=>{ if(supported$2.evm.includes(blockchain)) { return await EVM.getProvider(blockchain) } else if(supported$2.svm.includes(blockchain)) { return await Solana.getProvider(blockchain) } else { throw 'Unknown blockchain: ' + blockchain } }; let paramsToContractArgs = ({ contract, method, params }) => { let fragment = contract.interface.fragments.find((fragment) => { return fragment.name == method }); return fragment.inputs.map((input, index) => { if (Array.isArray(params)) { return params[index] } else { return params[input.name] } }) }; const contractCall = ({ address, api, method, params, provider, block }) => { const contract = new ethers.ethers.Contract(address, api, provider); const args = paramsToContractArgs({ contract, method, params }); const fragment = contract.interface.fragments.find((fragment)=>fragment.name === method); if(contract[method] === undefined) { method = `${method}(${fragment.inputs.map((input)=>input.type).join(',')})`; } if(fragment && fragment.stateMutability === 'nonpayable') { return contract.callStatic[method](...args, { blockTag: block }) } else { return contract[method](...args, { blockTag: block }) } }; const balance$1 = ({ address, provider }) => { return provider.getBalance(address) }; const transactionCount = ({ address, provider }) => { return provider.getTransactionCount(address) }; const singleRequest$1 = ({ blockchain, address, api, method, params, block, provider }) =>{ if (api) { return contractCall({ address, api, method, params, provider, block }) } else if (method === 'latestBlockNumber') { return provider.getBlockNumber() } else if (method === 'balance') { return balance$1({ address, provider }) } else if (method === 'transactionCount') { return transactionCount({ address, provider }) } }; var requestEVM = async ({ blockchain, address, api, method, params, block, timeout, strategy }) => { strategy = strategy ? strategy : (getConfiguration().strategy || 'failover'); timeout = timeout ? timeout : (getConfiguration().timeout || undefined); if(strategy === 'fastest') { const providers = await EVM.getProviders(blockchain); let allRequestsFailed = []; const allRequestsInParallel = providers.map((provider)=>{ return new Promise((resolve)=>{ allRequestsFailed.push( singleRequest$1({ blockchain, address, api, method, params, block, provider }).then(resolve) ); }) }); const timeoutPromise = new Promise((_, reject)=>setTimeout(()=>{ reject(new Error("Web3ClientTimeout")); }, timeout || 10000)); allRequestsFailed = Promise.all(allRequestsFailed.map((request)=>{ return new Promise((resolve)=>{ request.catch(resolve); }) })).then(()=>{ return }); return Promise.race([...allRequestsInParallel, timeoutPromise, allRequestsFailed]) } else { // failover const provider = await EVM.getProvider(blockchain); const request = singleRequest$1({ blockchain, address, api, method, params, block, provider }); if(timeout) { timeout = new Promise((_, reject)=>setTimeout(()=>{ reject(new Error("Web3ClientTimeout")); }, timeout)); return Promise.race([request, timeout]) } else { return request } } }; const accountInfo = async ({ address, api, method, params, provider, block }) => { const info = await provider.getAccountInfo(new solanaWeb3_js.PublicKey(address)); if(!info || !info.data) { return } return api.decode(info.data) }; const balance = ({ address, provider }) => { return provider.getBalance(new solanaWeb3_js.PublicKey(address)) }; const singleRequest = async({ blockchain, address, api, method, params, block, provider, providers })=> { try { if(method == undefined || method === 'getAccountInfo') { if(api == undefined) { api = solanaWeb3_js.ACCOUNT_LAYOUT; } return await accountInfo({ address, api, method, params, provider, block }) } else if(method === 'getProgramAccounts') { return await provider.getProgramAccounts(new solanaWeb3_js.PublicKey(address), params).then((accounts)=>{ if(api){ return accounts.map((account)=>{ account.data = api.decode(account.account.data); return account }) } else { return accounts } }) } else if(method === 'getTokenAccountBalance') { return await provider.getTokenAccountBalance(new solanaWeb3_js.PublicKey(address)) } else if (method === 'latestBlockNumber') { return await provider.getSlot(params ? params : undefined) } else if (method === 'balance') { return await balance({ address, provider }) } } catch (error){ if(providers && error && [ 'Failed to fetch', 'limit reached', '504', '503', '502', '500', '429', '426', '422', '413', '409', '408', '406', '405', '404', '403', '402', '401', '400' ].some((errorType)=>error.toString().match(errorType))) { let nextProvider = providers[providers.indexOf(provider)+1] || providers[0]; return singleRequest({ blockchain, address, api, method, params, block, provider: nextProvider, providers }) } else { throw error } } }; var requestSolana = async ({ blockchain, address, api, method, params, block, timeout, strategy }) => { strategy = strategy ? strategy : (getConfiguration().strategy || 'failover'); timeout = timeout ? timeout : (getConfiguration().timeout || undefined); const providers = await Solana.getProviders(blockchain); if(strategy === 'fastest') { let allRequestsFailed = []; const allRequestsInParallel = providers.map((provider)=>{ return new Promise((resolve)=>{ allRequestsFailed.push( singleRequest({ blockchain, address, api, method, params, block, provider }).then(resolve) ); }) }); const timeoutPromise = new Promise((_, reject)=>setTimeout(()=>{ reject(new Error("Web3ClientTimeout")); }, timeout || 60000)); // 60s default timeout allRequestsFailed = Promise.all(allRequestsFailed.map((request)=>{ return new Promise((resolve)=>{ request.catch(resolve); }) })).then(()=>{ return }); return Promise.race([...allRequestsInParallel, timeoutPromise, allRequestsFailed]) } else { // failover const provider = await Solana.getProvider(blockchain); const request = singleRequest({ blockchain, address, api, method, params, block, provider, providers }); if(timeout) { timeout = new Promise((_, reject)=>setTimeout(()=>{ reject(new Error("Web3ClientTimeout")); }, timeout)); return Promise.race([request, timeout]) } else { return request } } }; var parseUrl = (url) => { if (typeof url == 'object') { return url } let deconstructed = url.match(/(?<blockchain>\w+):\/\/(?<part1>[\w\d]+)(\/(?<part2>[\w\d]+)*)?/); if(deconstructed.groups.part2 == undefined) { if(deconstructed.groups.part1.match(/\d/)) { return { blockchain: deconstructed.groups.blockchain, address: deconstructed.groups.part1 } } else { return { blockchain: deconstructed.groups.blockchain, method: deconstructed.groups.part1 } } } else { return { blockchain: deconstructed.groups.blockchain, address: deconstructed.groups.part1, method: deconstructed.groups.part2 } } }; const request = async function (url, options) { const { blockchain, address, method } = parseUrl(url); const { api, params, cache: cache$1, block, timeout, strategy, cacheKey } = (typeof(url) == 'object' ? url : options) || {}; return await cache({ expires: cache$1 || 0, key: cacheKey || [blockchain, address, method, params, block], call: async()=>{ if(supported$2.evm.includes(blockchain)) { return await requestEVM({ blockchain, address, api, method, params, block, strategy, timeout }) } else if(supported$2.svm.includes(blockchain)) { return await requestSolana({ blockchain, address, api, method, params, block, strategy, timeout }) } else { throw 'Unknown blockchain: ' + blockchain } } }) }; var allowanceOnEVM = ({ blockchain, address, api, owner, spender })=>{ return request( { blockchain, address, api, method: 'allowance', params: [owner, spender], // no cache for allowance! }, ) }; var balanceOnEVM = async ({ blockchain, address, account, api, id })=>{ if (address == Blockchains__default["default"][blockchain].currency.address) { return await request( { blockchain: blockchain, address: account, method: 'balance', }, ) } else { return await request( { blockchain: blockchain, address: address, method: 'balanceOf', api, params: id ? [account, id] : [account], }, ) } }; var decimalsOnEVM = ({ blockchain, address, api })=>{ return request({ blockchain, address, api, method: 'decimals', cache: 86400000, // 1 day }) }; var ERC1155 = [ { "anonymous": false, "inputs": [ { "indexed": true, "internalType": "address", "name": "account", "type": "address" }, { "indexed": true, "internalType": "address", "name": "operator", "type": "address" }, { "indexed": false, "internalType": "bool", "name": "approved", "type": "bool" } ], "name": "ApprovalForAll", "type": "event" }, { "anonymous": false, "inputs": [ { "indexed": true, "internalType": "address", "name": "operator", "type": "address" }, { "indexed": true, "internalType": "address", "name": "from", "type": "address" }, { "indexed": true, "internalType": "address", "name": "to", "type": "address" }, { "indexed": false, "internalType": "uint256[]", "name": "ids", "type": "uint256[]" }, { "indexed": false, "internalType": "uint256[]", "name": "values", "type": "uint256[]" } ], "name": "TransferBatch", "type": "event" }, { "anonymous": false, "inputs": [ { "indexed": true, "internalType": "address", "name": "operator", "type": "address" }, { "indexed": true, "internalType": "address", "name": "from", "type": "address" }, { "indexed": true, "internalType": "address", "name": "to", "type": "address" }, { "indexed": false, "internalType": "uint256", "name": "id", "type": "uint256" }, { "indexed": false, "internalType": "uint256", "name": "value", "type": "uint256" } ], "name": "TransferSingle", "type": "event" }, { "anonymous": false, "inputs": [ { "indexed": false, "internalType": "string", "name": "value", "type": "string" }, { "indexed": true, "internalType": "uint256", "name": "id", "type": "uint256" } ], "name": "URI", "type": "event" }, { "inputs": [ { "internalType": "address", "name": "account", "type": "address" }, {