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
JavaScript
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