UNPKG

wido

Version:

JavaScript library for interacting with the Wido protocol which allows you to seamlessly move liquidity across vaults and chains.

797 lines (796 loc) 23.1 kB
var __defProp = Object.defineProperty; var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __publicField = (obj, key, value) => { __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value); return value; }; class WidoError extends Error { constructor(code, detail, validationErrors) { let message; switch (code) { case "INVALID_REQUEST": message = `${detail}: ${validationErrors == null ? void 0 : validationErrors.map((err) => err.msg).join(", ")}`; break; default: message = `${code}: ${detail}`; break; } super(message); __publicField(this, "name", "WidoError"); __publicField(this, "code"); __publicField(this, "detail"); __publicField(this, "validationErrors"); this.detail = detail; this.code = code; this.validationErrors = validationErrors; } static from_api_response(response) { return new WidoError( response.code, response.detail, response.validationErrors ); } } async function approve(request) { const { tokenAddress, fromToken, toToken, chainId, fromChainId, toChainId, amount = MAX_UINT256, tokenId } = request; const endpoint = `approve`; if (!chainId && !fromChainId) { throw new Error(`fromChainId must be set`); } const paramsObj = { chain_id: fromChainId ? String(fromChainId) : String(chainId), amount, from_token: fromToken, to_token: toToken }; if (tokenAddress) { paramsObj.token_address = tokenAddress; } if (tokenId) { paramsObj.token_id = tokenId; } if (toChainId) { paramsObj.to_chain_id = String(toChainId); } const params = new URLSearchParams(paramsObj); const url = `${CONFIG.WIDO_API_URL}/${endpoint}?${params}`; const res = await fetch(url); if (!res.ok) { throw WidoError.from_api_response(await res.json()); } const data = await res.json(); return { to: data.to, data: data.data }; } const ZERO_ADDRESS = "0x0000000000000000000000000000000000000000"; const CONFIG = { WIDO_API_URL: "https://api.joinwido.com", SEGMENT_KEY: "G4ttHjzxUXZ2ORLGHpXE8yEfCCkqjPXx", DEBUG: false }; const useLocalApi = () => { console.log("Using local Wido API URL..."); CONFIG.WIDO_API_URL = "http://127.0.0.1:8080"; CONFIG.SEGMENT_KEY = "qu7qvYAa1ziyWWkgsInDw4K2YQDFxWOR"; }; const useProdApi = () => { CONFIG.WIDO_API_URL = "https://api.joinwido.com"; CONFIG.SEGMENT_KEY = "G4ttHjzxUXZ2ORLGHpXE8yEfCCkqjPXx"; }; async function getStatus(request) { const { txHash, chainId } = request; const endpoint = `status`; const paramsObj = { chain_id: String(chainId), tx_hash: txHash }; const params = new URLSearchParams(paramsObj); const url = `${CONFIG.WIDO_API_URL}/${endpoint}?${params}`; const res = await fetch(url); if (!res.ok) { throw WidoError.from_api_response(await res.json()); } const data = await res.json(); return { status: data.status, substatus: data.substatus, substatusMessage: data.substatus_message, toChainId: data.to_chain_id, toTxHash: data.to_tx_hash }; } async function getTokenAllowance(request) { const { accountAddress, tokenAddress, chainId, fromToken, toToken, fromChainId, toChainId, tokenId } = request; const endpoint = `allowance`; if (!chainId && !fromChainId) { throw new Error(`fromChainId must be set`); } const paramsObj = { chain_id: fromChainId ? String(fromChainId) : String(chainId), account_address: accountAddress, from_token: fromToken, to_token: toToken }; if (tokenAddress) { paramsObj.token_address = tokenAddress; } if (tokenId) { paramsObj.token_id = tokenId; } if (toChainId) { paramsObj.to_chain_id = String(toChainId); } const params = new URLSearchParams(paramsObj); const url = `${CONFIG.WIDO_API_URL}/${endpoint}?${params}`; const res = await fetch(url); if (!res.ok) { throw WidoError.from_api_response(await res.json()); } const data = await res.json(); return { spender: data.spender, allowance: data.allowance }; } async function getWidoContractAddress(chainId) { const endpoint = `contract_address`; const params = new URLSearchParams({ chain_id: String(chainId) }); const url = `${CONFIG.WIDO_API_URL}/${endpoint}?${params}`; const res = await fetch(url); if (!res.ok) { throw WidoError.from_api_response(await res.json()); } const data = await res.json(); return data.spender; } async function getWidoSpender(request) { const { chainId, fromToken, toChainId, toToken } = request; const endpoint = `contract_address`; const paramsObj = { chain_id: String(chainId), from_token: fromToken, to_chain_id: String(toChainId), to_token: toToken }; const params = new URLSearchParams(paramsObj); const url = `${CONFIG.WIDO_API_URL}/${endpoint}?${params}`; const res = await fetch(url); if (!res.ok) { throw WidoError.from_api_response(await res.json()); } const data = await res.json(); return data.spender; } async function getSupportedTokensInternal(request) { const { chainId = [], protocol = [], includePricing = false, includePreview = false, toChainId, toToken } = request || {}; const endpoint = `tokens`; const paramsObj = { include_pricing: String(includePricing), include_preview: String(includePreview) }; if (toChainId) { paramsObj.to_chain_id = String(toChainId); } if (toToken) { paramsObj.to_token = toToken; } const params = new URLSearchParams(paramsObj); chainId.forEach((chainId2) => params.append("chain_id", String(chainId2))); protocol.forEach((protocol2) => params.append("protocol", protocol2)); const url = `${CONFIG.WIDO_API_URL}/${endpoint}?${params}`; const res = await fetch(url); if (!res.ok) { throw WidoError.from_api_response(await res.json()); } return (await res.json()).tokens; } async function getSupportedTokens(request) { return await getSupportedTokensInternal(request); } async function getBalances(user, chainId) { const endpoint = `balances`; const params = new URLSearchParams({ user }); chainId == null ? void 0 : chainId.forEach((chainId2) => params.append("chain_id", String(chainId2))); const url = `${CONFIG.WIDO_API_URL}/${endpoint}?${params}`; const res = await fetch(url); if (!res.ok) { throw WidoError.from_api_response(await res.json()); } return (await res.json()).balances; } async function quote(request) { const { user, fromChainId, fromToken, toChainId, toToken, amount, slippagePercentage = 0.01, varsOverride = {}, partner, lowerTick, upperTick, tokenId, recipient, gaslessType, providers } = request; const endpoint = "quote_v2"; const paramsObj = { from_chain_id: String(fromChainId), from_token: fromToken, to_chain_id: String(toChainId), to_token: toToken, ...varsOverride }; if (slippagePercentage) { paramsObj.slippage_percentage = String(slippagePercentage); } if (amount) { paramsObj.amount = amount; } if (user) { paramsObj.user = user; } if (partner) { paramsObj.partner = partner; } if (lowerTick) { paramsObj.lower_tick = lowerTick; } if (upperTick) { paramsObj.upper_tick = upperTick; } if (tokenId) { paramsObj.token_id = tokenId; } if (recipient) { paramsObj.recipient = recipient; } if (gaslessType) { paramsObj.gasless_type = gaslessType; } const params = new URLSearchParams(paramsObj); if (providers) { for (const provider of providers) { params.append("providers", provider); } } const url = `${CONFIG.WIDO_API_URL}/${endpoint}?${params}`; const res = await fetch(url); if (!res.ok) { throw WidoError.from_api_response(await res.json()); } const body = await res.json(); const { is_supported, steps, steps_count, messages } = body; const baseQuoteResult = { isSupported: is_supported, steps, stepsCount: steps_count, messages: messages || [] }; if (!amount && !user) { return baseQuoteResult; } const { price, min_price, from_token_usd_price, from_token_amount, from_token_amount_usd_value, to_token_usd_price, to_token_amount, to_token_amount_usd_value, expected_slippage, min_to_token_amount, from, to, data, value, gas_fee, gas_fee_usd, fee_in_from_token, bridge_fee_usd_value, fee_usd_value } = body; return { ...baseQuoteResult, price, minPrice: min_price, fromTokenUsdPrice: from_token_usd_price, fromTokenAmount: from_token_amount, fromTokenAmountUsdValue: from_token_amount_usd_value, toTokenUsdPrice: to_token_usd_price, toTokenAmount: to_token_amount, toTokenAmountUsdValue: to_token_amount_usd_value, expectedSlippage: expected_slippage, minToTokenAmount: min_to_token_amount, from, to, data, value, gasFee: gas_fee, gasFeeUsdValue: gas_fee_usd, feeBps: body.fee_bps, feeInFromToken: fee_in_from_token, bridgeFeeUsdValue: bridge_fee_usd_value, feeUsdValue: fee_usd_value }; } const version$1 = "logger/5.7.0"; let _permanentCensorErrors = false; let _censorErrors = false; const LogLevels = { debug: 1, "default": 2, info: 2, warning: 3, error: 4, off: 5 }; let _logLevel = LogLevels["default"]; let _globalLogger = null; function _checkNormalize() { try { const missing = []; ["NFD", "NFC", "NFKD", "NFKC"].forEach((form) => { try { if ("test".normalize(form) !== "test") { throw new Error("bad normalize"); } ; } catch (error) { missing.push(form); } }); if (missing.length) { throw new Error("missing " + missing.join(", ")); } if (String.fromCharCode(233).normalize("NFD") !== String.fromCharCode(101, 769)) { throw new Error("broken implementation"); } } catch (error) { return error.message; } return null; } const _normalizeError = _checkNormalize(); var LogLevel; (function(LogLevel2) { LogLevel2["DEBUG"] = "DEBUG"; LogLevel2["INFO"] = "INFO"; LogLevel2["WARNING"] = "WARNING"; LogLevel2["ERROR"] = "ERROR"; LogLevel2["OFF"] = "OFF"; })(LogLevel || (LogLevel = {})); var ErrorCode; (function(ErrorCode2) { ErrorCode2["UNKNOWN_ERROR"] = "UNKNOWN_ERROR"; ErrorCode2["NOT_IMPLEMENTED"] = "NOT_IMPLEMENTED"; ErrorCode2["UNSUPPORTED_OPERATION"] = "UNSUPPORTED_OPERATION"; ErrorCode2["NETWORK_ERROR"] = "NETWORK_ERROR"; ErrorCode2["SERVER_ERROR"] = "SERVER_ERROR"; ErrorCode2["TIMEOUT"] = "TIMEOUT"; ErrorCode2["BUFFER_OVERRUN"] = "BUFFER_OVERRUN"; ErrorCode2["NUMERIC_FAULT"] = "NUMERIC_FAULT"; ErrorCode2["MISSING_NEW"] = "MISSING_NEW"; ErrorCode2["INVALID_ARGUMENT"] = "INVALID_ARGUMENT"; ErrorCode2["MISSING_ARGUMENT"] = "MISSING_ARGUMENT"; ErrorCode2["UNEXPECTED_ARGUMENT"] = "UNEXPECTED_ARGUMENT"; ErrorCode2["CALL_EXCEPTION"] = "CALL_EXCEPTION"; ErrorCode2["INSUFFICIENT_FUNDS"] = "INSUFFICIENT_FUNDS"; ErrorCode2["NONCE_EXPIRED"] = "NONCE_EXPIRED"; ErrorCode2["REPLACEMENT_UNDERPRICED"] = "REPLACEMENT_UNDERPRICED"; ErrorCode2["UNPREDICTABLE_GAS_LIMIT"] = "UNPREDICTABLE_GAS_LIMIT"; ErrorCode2["TRANSACTION_REPLACED"] = "TRANSACTION_REPLACED"; ErrorCode2["ACTION_REJECTED"] = "ACTION_REJECTED"; })(ErrorCode || (ErrorCode = {})); const HEX = "0123456789abcdef"; class Logger { constructor(version2) { Object.defineProperty(this, "version", { enumerable: true, value: version2, writable: false }); } _log(logLevel, args) { const level = logLevel.toLowerCase(); if (LogLevels[level] == null) { this.throwArgumentError("invalid log level name", "logLevel", logLevel); } if (_logLevel > LogLevels[level]) { return; } console.log.apply(console, args); } debug(...args) { this._log(Logger.levels.DEBUG, args); } info(...args) { this._log(Logger.levels.INFO, args); } warn(...args) { this._log(Logger.levels.WARNING, args); } makeError(message, code, params) { if (_censorErrors) { return this.makeError("censored error", code, {}); } if (!code) { code = Logger.errors.UNKNOWN_ERROR; } if (!params) { params = {}; } const messageDetails = []; Object.keys(params).forEach((key) => { const value = params[key]; try { if (value instanceof Uint8Array) { let hex = ""; for (let i = 0; i < value.length; i++) { hex += HEX[value[i] >> 4]; hex += HEX[value[i] & 15]; } messageDetails.push(key + "=Uint8Array(0x" + hex + ")"); } else { messageDetails.push(key + "=" + JSON.stringify(value)); } } catch (error2) { messageDetails.push(key + "=" + JSON.stringify(params[key].toString())); } }); messageDetails.push(`code=${code}`); messageDetails.push(`version=${this.version}`); const reason = message; let url = ""; switch (code) { case ErrorCode.NUMERIC_FAULT: { url = "NUMERIC_FAULT"; const fault = message; switch (fault) { case "overflow": case "underflow": case "division-by-zero": url += "-" + fault; break; case "negative-power": case "negative-width": url += "-unsupported"; break; case "unbound-bitwise-result": url += "-unbound-result"; break; } break; } case ErrorCode.CALL_EXCEPTION: case ErrorCode.INSUFFICIENT_FUNDS: case ErrorCode.MISSING_NEW: case ErrorCode.NONCE_EXPIRED: case ErrorCode.REPLACEMENT_UNDERPRICED: case ErrorCode.TRANSACTION_REPLACED: case ErrorCode.UNPREDICTABLE_GAS_LIMIT: url = code; break; } if (url) { message += " [ See: https://links.ethers.org/v5-errors-" + url + " ]"; } if (messageDetails.length) { message += " (" + messageDetails.join(", ") + ")"; } const error = new Error(message); error.reason = reason; error.code = code; Object.keys(params).forEach(function(key) { error[key] = params[key]; }); return error; } throwError(message, code, params) { throw this.makeError(message, code, params); } throwArgumentError(message, name, value) { return this.throwError(message, Logger.errors.INVALID_ARGUMENT, { argument: name, value }); } assert(condition, message, code, params) { if (!!condition) { return; } this.throwError(message, code, params); } assertArgument(condition, message, name, value) { if (!!condition) { return; } this.throwArgumentError(message, name, value); } checkNormalize(message) { if (_normalizeError) { this.throwError("platform missing String.prototype.normalize", Logger.errors.UNSUPPORTED_OPERATION, { operation: "String.prototype.normalize", form: _normalizeError }); } } checkSafeUint53(value, message) { if (typeof value !== "number") { return; } if (message == null) { message = "value not safe"; } if (value < 0 || value >= 9007199254740991) { this.throwError(message, Logger.errors.NUMERIC_FAULT, { operation: "checkSafeInteger", fault: "out-of-safe-range", value }); } if (value % 1) { this.throwError(message, Logger.errors.NUMERIC_FAULT, { operation: "checkSafeInteger", fault: "non-integer", value }); } } checkArgumentCount(count, expectedCount, message) { if (message) { message = ": " + message; } else { message = ""; } if (count < expectedCount) { this.throwError("missing argument" + message, Logger.errors.MISSING_ARGUMENT, { count, expectedCount }); } if (count > expectedCount) { this.throwError("too many arguments" + message, Logger.errors.UNEXPECTED_ARGUMENT, { count, expectedCount }); } } checkNew(target, kind) { if (target === Object || target == null) { this.throwError("missing new", Logger.errors.MISSING_NEW, { name: kind.name }); } } checkAbstract(target, kind) { if (target === kind) { this.throwError("cannot instantiate abstract class " + JSON.stringify(kind.name) + " directly; use a sub-class", Logger.errors.UNSUPPORTED_OPERATION, { name: target.name, operation: "new" }); } else if (target === Object || target == null) { this.throwError("missing new", Logger.errors.MISSING_NEW, { name: kind.name }); } } static globalLogger() { if (!_globalLogger) { _globalLogger = new Logger(version$1); } return _globalLogger; } static setCensorship(censorship, permanent) { if (!censorship && permanent) { this.globalLogger().throwError("cannot permanently disable censorship", Logger.errors.UNSUPPORTED_OPERATION, { operation: "setCensorship" }); } if (_permanentCensorErrors) { if (!censorship) { return; } this.globalLogger().throwError("error censorship permanent", Logger.errors.UNSUPPORTED_OPERATION, { operation: "setCensorship" }); } _censorErrors = !!censorship; _permanentCensorErrors = !!permanent; } static setLogLevel(logLevel) { const level = LogLevels[logLevel.toLowerCase()]; if (level == null) { Logger.globalLogger().warn("invalid log level - " + logLevel); return; } _logLevel = level; } static from(version2) { return new Logger(version2); } } Logger.errors = ErrorCode; Logger.levels = LogLevel; const version = "properties/5.7.0"; var __awaiter = globalThis && globalThis.__awaiter || function(thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function(resolve) { resolve(value); }); } return new (P || (P = Promise))(function(resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; new Logger(version); function resolveProperties(object) { return __awaiter(this, void 0, void 0, function* () { const promises = Object.keys(object).map((key) => { const value = object[key]; return Promise.resolve(value).then((v) => ({ key, value: v })); }); const results = yield Promise.all(promises); return results.reduce((accum, result) => { accum[result.key] = result.value; return accum; }, {}); }); } async function getPaymasterAndData(chainId, userOp) { const endpoint = "paymaster"; const request = { chainId, sender: userOp.sender, nonce: userOp.nonce.toString(), initCode: userOp.initCode, callData: userOp.callData, callGasLimit: userOp.callGasLimit.toString(), verificationGasLimit: userOp.verificationGasLimit.toString(), preVerificationGas: userOp.preVerificationGas.toString(), maxFeePerGas: userOp.maxFeePerGas.toString(), maxPriorityFeePerGas: userOp.maxPriorityFeePerGas.toString(), paymasterAndData: userOp.paymasterAndData, signature: userOp.signature }; const url = `${CONFIG.WIDO_API_URL}/${endpoint}`; const res = await fetch(url, { method: "POST", mode: "cors", headers: { Accept: "*/*", "Content-Type": "application/json" }, body: JSON.stringify(request) }); if (!res.ok) { throw WidoError.from_api_response(await res.json()); } const { paymasterAndData } = await res.json(); return { paymasterAndData }; } class BiconomyPaymaster { constructor(chainId) { __publicField(this, "chainId"); this.chainId = chainId; } getDummyPaymasterAndData(_userOp) { return Promise.resolve( "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" ); } async getPaymasterAndData(userOp) { userOp = await resolveProperties(userOp); userOp.nonce = Number(userOp.nonce); userOp.callGasLimit = Number(userOp.callGasLimit); userOp.verificationGasLimit = Number(userOp.verificationGasLimit); userOp.maxFeePerGas = Number(userOp.maxFeePerGas); userOp.maxPriorityFeePerGas = Number(userOp.maxPriorityFeePerGas); userOp.preVerificationGas = Number(userOp.preVerificationGas); userOp.signature = "0x"; userOp.paymasterAndData = "0x"; const paymasterResponse = await getPaymasterAndData( this.chainId, userOp ); return { paymasterAndData: paymasterResponse.paymasterAndData }; } } const MAX_UINT256 = "115792089237316195423570985008687907853269984665640564039457584007913129639935"; const chainIdMap = { other: 1, mainnet: 1, goerli: 5, fantom: 250, arbitrum: 42161, avalanche: 43114, moonriver: 1285, polygon: 137, celo: 42220, phuture: 1338, optimism: 10, binance: 56, aurora: 1313161554, base: 8453 }; function getChainId(chainName) { if (!chainIdMap[chainName]) { throw new Error(`InputError: chain with name ${chainName} not found.`); } return chainIdMap[chainName]; } const chainNameMap = { 1: "mainnet", 5: "goerli", 250: "fantom", 43114: "avalanche", 42161: "arbitrum", 1285: "moonriver", 137: "polygon", 42220: "celo", 1338: "phuture", 10: "optimism", 56: "binance", 1313161554: "aurora", 8453: "base" }; function getChainName(chainId) { if (!chainNameMap[chainId]) { throw new Error(`InputError: chain with id ${chainId} not found.`); } return chainNameMap[chainId]; } var GaslessType = /* @__PURE__ */ ((GaslessType2) => { GaslessType2["ERC4337"] = "erc4337"; GaslessType2["EOA"] = "eoa"; return GaslessType2; })(GaslessType || {}); var Providers = /* @__PURE__ */ ((Providers2) => { Providers2["LiFi"] = "LiFi"; Providers2["ZeroEx"] = "ZeroEx"; Providers2["OpenOcean"] = "OpenOcean"; return Providers2; })(Providers || {}); export { BiconomyPaymaster, CONFIG, GaslessType, MAX_UINT256, Providers, ZERO_ADDRESS, approve, getBalances, getChainId, getChainName, getStatus, getSupportedTokens, getTokenAllowance, getWidoContractAddress, getWidoSpender, quote, useLocalApi, useProdApi }; //# sourceMappingURL=wido.mjs.map