UNPKG

@reservoir0x/reservoir-kit-client

Version:

ReservoirKit is the official frontend kit to get you started building dApps with the ReservoirProtocol.

568 lines (505 loc) 27.1 kB
import {arrayify as $iGiPT$arrayify} from "ethers/lib/utils"; import $iGiPT$axios from "axios"; function $parcel$export(e, n, v, s) { Object.defineProperty(e, n, {get: v, set: s, enumerable: true, configurable: true}); } function $parcel$exportWildcard(dest, source) { Object.keys(source).forEach(function(key) { if (key === 'default' || key === '__esModule' || dest.hasOwnProperty(key)) { return; } Object.defineProperty(dest, key, { enumerable: true, get: function get() { return source[key]; } }); }); return dest; } var $8dc4e9b911526003$exports = {}; $parcel$export($8dc4e9b911526003$exports, "ReservoirClient", () => $8dc4e9b911526003$export$d0c36b5db6a81704); $parcel$export($8dc4e9b911526003$exports, "getClient", () => $8dc4e9b911526003$export$6bb76d6eba7e258c); $parcel$export($8dc4e9b911526003$exports, "createClient", () => $8dc4e9b911526003$export$5d730b7aed1a3eb0); var $d79888aa62b18edb$exports = {}; $parcel$export($d79888aa62b18edb$exports, "executeSteps", () => $cbe142d0473ea2cf$export$21ece85d7636deb); $parcel$export($d79888aa62b18edb$exports, "setParams", () => $a72505a16e120031$export$dc1827290674c112); $parcel$export($d79888aa62b18edb$exports, "pollUntilOk", () => $fd2817e1b4d271f0$export$d2c70568ef790b87); $parcel$export($d79888aa62b18edb$exports, "pollUntilHasData", () => $fd2817e1b4d271f0$export$f014594cc879f602); $parcel$export($d79888aa62b18edb$exports, "isOpenSeaBanned", () => $c0bb623c6f3fd12b$export$feaa73ad8ed3f2b9); async function $fd2817e1b4d271f0$export$f014594cc879f602(request, dataParser) { async function getData() { let res = await (0, $iGiPT$axios).request(request); return res.data; } const json = await getData(); // Check if the data exists const dataExists = dataParser(json); if (dataExists) return json; // The response is still unchanged. Check again in five seconds await new Promise((resolve)=>setTimeout(resolve, 5000)); await $fd2817e1b4d271f0$export$f014594cc879f602(request, dataParser); } async function $fd2817e1b4d271f0$export$d2c70568ef790b87(request, validate) { const res1 = await (0, $iGiPT$axios).request(request); if (!validate) validate = (res)=>res.status === 200; // Check that the response from an endpoint updated if (validate(res1)) return true; else { // The response is still unchanged. Check again in five seconds await new Promise((resolve)=>setTimeout(resolve, 5000)); await $fd2817e1b4d271f0$export$d2c70568ef790b87(request, validate); } } function $a72505a16e120031$export$dc1827290674c112(url, query) { Object.keys(query).map((key)=>{ var _a; let value = query[key]; if (value !== undefined) { if (Array.isArray(value)) value.forEach((item)=>{ url.searchParams.append(key, item); }); else url.searchParams.append(key, (_a = query[key]) === null || _a === void 0 ? void 0 : _a.toString()); } return url; }); } var $4d953031265289eb$exports = {}; $4d953031265289eb$exports = JSON.parse('{"name":"@reservoir0x/reservoir-kit-client","version":"0.2.5","description":"ReservoirKit is the official frontend kit to get you started building dApps with the ReservoirProtocol.","source":"src/index.ts","main":"dist/index.js","module":"dist/index.module.js","types":"dist/index.d.ts","author":"Reservoir Protocol","license":"MIT","files":["dist"],"scripts":{"clean":"rm -rf dist","version":"yarn version","version:package":"sh ../../scripts/package-version.sh","version:update":"yarn version ${0}; PACKAGE_VERSION=$(yarn version:package); git add -A; git commit -m \\"\uD83C\uDF89 Release client package v$PACKAGE_VERSION\\"; git push","syncApi":"npx openapi-typescript https://api.reservoir.tools/swagger.json --output ./src/types/api.ts","changelog":"node ../../scripts/generate-changelog.js package=client"},"repository":{"type":"git","url":"https://github.com/reservoirprotocol/reservoir-kit"},"sideEffects":false,"keywords":["nft","reservoir","reservoirkit","protocol","sdk"],"peerDependencies":{"ethers":"^5.6.1"},"dependencies":{"axios":"^0.27.2"},"publishConfig":{"access":"public"},"devDependencies":{"openapi-typescript":"^5.4.1"}}'); async function $cbe142d0473ea2cf$export$21ece85d7636deb(request, signer, setState, newJson, expectedPrice) { var _a1, _b1, _c; try { let json1 = newJson; if (!request.headers) request.headers = {}; const client = (0, $8dc4e9b911526003$export$6bb76d6eba7e258c)(); if (client === null || client === void 0 ? void 0 : client.apiKey) request.headers["x-api-key"] = client.apiKey; if (client === null || client === void 0 ? void 0 : client.uiVersion) request.headers["x-rkui-version"] = client.uiVersion; request.headers["x-rkc-version"] = (0, $4d953031265289eb$exports.version); if (!json1) { const res = await (0, $iGiPT$axios).request(request); json1 = res.data; if (res.status !== 200) throw json1; } // Handle errors if (json1.error || !json1.steps) throw json1; const isBuy = (_a1 = request.url) === null || _a1 === void 0 ? void 0 : _a1.includes("/execute/buy"); const isSell = (_b1 = request.url) === null || _b1 === void 0 ? void 0 : _b1.includes("/execute/sell"); // Handle price changes to protect users from paying more // than expected when buying and selling for less than expected if (json1.path && expectedPrice) { const quote = json1.path.reduce((total, path)=>{ total += path.quote || 0; return total; }, 0); // Check if the user is selling let error = null; if (isSell && quote - expectedPrice < -0.00001) error = { type: "price mismatch", message: `The quoted price of ${quote} is less than the expected price of ${expectedPrice}` }; // Check if the user is buying if (isBuy && quote - expectedPrice > 0.00001) error = { type: "price mismatch", message: `The quoted price of ${quote} is greater than the expected price of ${expectedPrice}` }; if (error) { json1.steps[0].error = error.message; json1.steps[0].errorData = json1.path; setState([ ...json1 === null || json1 === void 0 ? void 0 : json1.steps ]); throw error; } } // Update state on first call or recursion setState([ ...json1 === null || json1 === void 0 ? void 0 : json1.steps ]); let incompleteStepIndex = -1; let incompleteStepItemIndex = -1; json1.steps.find((step, i)=>{ if (!step.items) return false; incompleteStepItemIndex = step.items.findIndex((item)=>item.status == "incomplete"); if (incompleteStepItemIndex !== -1) { incompleteStepIndex = i; return true; } }); // There are no more incomplete steps if (incompleteStepIndex === -1) return; const step1 = json1.steps[incompleteStepIndex]; const stepItems = json1.steps[incompleteStepIndex].items; if (!stepItems) return; let { kind: kind } = step1; let stepItem = stepItems[incompleteStepItemIndex]; // If step item is missing data, poll until it is ready if (!stepItem.data) { json1 = await (0, $fd2817e1b4d271f0$export$f014594cc879f602)(request, (json)=>{ var _a, _b; const data = json; return ((_b = (_a = data === null || data === void 0 ? void 0 : data.steps) === null || _a === void 0 ? void 0 : _a[incompleteStepIndex].items) === null || _b === void 0 ? void 0 : _b[incompleteStepItemIndex].data) ? true : false; }); if (!json1.steps || !json1.steps[incompleteStepIndex].items) throw json1; const items = json1.steps[incompleteStepIndex].items; if (!items || !items[incompleteStepItemIndex] || !items[incompleteStepItemIndex].data) throw json1; stepItem = items[incompleteStepItemIndex]; } const stepData = stepItem.data; // Handle each step based on it's kind switch(kind){ // Make an on-chain transaction case "transaction": { const tx = await signer.sendTransaction(stepData); if ((_c = json1.steps[incompleteStepIndex].items) === null || _c === void 0 ? void 0 : _c[incompleteStepItemIndex]) stepItem.txHash = tx.hash; setState([ ...json1 === null || json1 === void 0 ? void 0 : json1.steps ]); await tx.wait(); //Implicitly poll the confirmation url to confirm the transaction went through const confirmationUrl = new URL(`${client.apiBase}/transactions/${tx.hash}/synced/v1`); const headers = { "x-rkc-version": (0, $4d953031265289eb$exports.version) }; if (client === null || client === void 0 ? void 0 : client.apiKey) headers["x-api-key"] = client.apiKey; if (client === null || client === void 0 ? void 0 : client.uiVersion) request.headers["x-rkui-version"] = client.uiVersion; await (0, $fd2817e1b4d271f0$export$d2c70568ef790b87)({ url: confirmationUrl.href, method: "get", headers: headers }, (res)=>res && res.data.synced); if (json1.steps.slice(incompleteStepIndex + 1).findIndex((step)=>step.kind === "transaction") === -1) //Confirm that on-chain tx has been picked up by the indexer for the last transaction { if (stepItem.txHash && (isSell || isBuy)) { const indexerConfirmationUrl = new URL(`${client.apiBase}/sales/v3`); const queryParams = { txHash: stepItem.txHash }; (0, $a72505a16e120031$export$dc1827290674c112)(indexerConfirmationUrl, queryParams); await (0, $fd2817e1b4d271f0$export$d2c70568ef790b87)({ url: indexerConfirmationUrl.href, method: "get", headers: headers }, (res)=>{ if (res.status === 200) { const data = res.data; return data.sales && data.sales.length > 0 ? true : false; } return false; }); } } break; } // Sign a message case "signature": { let signature; const signData = stepData["sign"]; const postData = stepData["post"]; if (signData) { // Request user signature if (signData.signatureKind === "eip191") { if (signData.message.match(/0x[0-9a-fA-F]{64}/)) // If the message represents a hash, we need to convert it to raw bytes first signature = await signer.signMessage((0, $iGiPT$arrayify)(signData.message)); else signature = await signer.signMessage(signData.message); } else if (signData.signatureKind === "eip712") signature = await signer._signTypedData(signData.domain, signData.types, signData.value); if (signature) request.params = { ...request.params, signature: signature }; } if (postData) { const postOrderUrl = new URL(`${client.apiBase}${postData.endpoint}`); try { const getData = async function() { const headers = { "Content-Type": "application/json", "x-rkc-version": (0, $4d953031265289eb$exports.version) }; if (client === null || client === void 0 ? void 0 : client.apiKey) headers["x-api-key"] = client.apiKey; let response = await (0, $iGiPT$axios).post(postOrderUrl.href, JSON.stringify(postData.body), { method: postData.method, headers: headers, params: request.params }); return response; }; const res = await getData(); if (res.status > 299 || res.status < 200) throw res.data; stepItem.orderId = res.data.orderId; setState([ ...json1 === null || json1 === void 0 ? void 0 : json1.steps ]); } catch (err) { json1.steps[incompleteStepIndex].error = "Your order could not be posted."; setState([ ...json1 === null || json1 === void 0 ? void 0 : json1.steps ]); throw err; } } break; } default: break; } delete step1.message; stepItem.status = "complete"; // Recursively call executeSteps() await $cbe142d0473ea2cf$export$21ece85d7636deb(request, signer, setState, json1); } catch (err) { const error = new Error(err === null || err === void 0 ? void 0 : err.message); console.error(error); throw err; } } async function $c0bb623c6f3fd12b$export$feaa73ad8ed3f2b9(contract, tokenId) { const base = "https://api.opensea.io"; const url = new URL(`/api/v1/asset/${contract}/${tokenId}`, base); const res = await (0, $iGiPT$axios).get(url.href); const json = res.data; const client = (0, $8dc4e9b911526003$export$6bb76d6eba7e258c)(); const apiBase = client === null || client === void 0 ? void 0 : client.apiBase; if (res.status === 200 && apiBase) { const apiKey = client === null || client === void 0 ? void 0 : client.apiKey; const headers = { "Content-Type": "application/json", "x-rkc-version": (0, $4d953031265289eb$exports.version) }; const body = { token: `${contract}:${tokenId}`, flag: !(json === null || json === void 0 ? void 0 : json.supports_wyvern) ? 1 : 0 }; if (apiKey) headers["x-api-key"] = apiKey; if (client === null || client === void 0 ? void 0 : client.uiVersion) headers["x-rkui-version"] = client.uiVersion; (0, $iGiPT$axios).post(`${apiBase}/tokens/flag/v1`, JSON.stringify(body), { headers: headers }).catch(()=>{}); } return !(json === null || json === void 0 ? void 0 : json.supports_wyvern); } async function $1c822481ba778cd8$export$ed27da83bcbea2e5(data) { const { token: token , expectedPrice: expectedPrice , signer: signer , onProgress: onProgress } = data; const taker = await signer.getAddress(); const client = (0, $8dc4e9b911526003$export$6bb76d6eba7e258c)(); const options = data.options || {}; if (!client.apiBase) throw new ReferenceError("ReservoirClient missing configuration"); try { const params = { taker: taker, token: `${token.contract}:${token.tokenId}`, source: client.source || "", ...options }; if (client.normalizeRoyalties !== undefined && params.normalizeRoyalties === undefined) params.normalizeRoyalties = client.normalizeRoyalties; await (0, $cbe142d0473ea2cf$export$21ece85d7636deb)({ url: `${client.apiBase}/execute/sell/v6`, method: "post", data: params }, signer, onProgress, undefined, expectedPrice); return true; } catch (err) { console.error(err); throw err; } } async function $5d30f75fa97319de$export$5e1997c166a16792(data1) { const { tokens: tokens , orderIds: orderIds , rawOrders: rawOrders , expectedPrice: expectedPrice , signer: signer , onProgress: onProgress } = data1; const taker = await signer.getAddress(); const client = (0, $8dc4e9b911526003$export$6bb76d6eba7e258c)(); const options = data1.options || {}; if (!client.apiBase) throw new ReferenceError("ReservoirClient missing configuration"); if ((!tokens || !tokens.length) && (!data1.orderIds || !data1.orderIds.length) && !data1.rawOrders) { console.debug(data1); throw new ReferenceError("ReservoirClient missing data: At least one of the following is required, tokens, orderIds or rawOrders"); } if (tokens && (orderIds || rawOrders) || orderIds && (tokens || rawOrders) || rawOrders && (orderIds || tokens)) { console.debug(data1); throw new ReferenceError("ReservoirClient conflicting data: tokens, orderIds and rawOrders are mutually exclusive"); } try { const params = { taker: taker, source: client.source || "", ...options }; if (tokens) params.tokens = tokens === null || tokens === void 0 ? void 0 : tokens.map((token)=>`${token.contract}:${token.tokenId}`); else if (orderIds) params.orderIds = orderIds; else if (rawOrders) params.rawOrders = rawOrders; if (client.normalizeRoyalties !== undefined && params.normalizeRoyalties === undefined) params.normalizeRoyalties = client.normalizeRoyalties; await (0, $cbe142d0473ea2cf$export$21ece85d7636deb)({ url: `${client.apiBase}/execute/buy/v6`, method: "post", data: params }, signer, onProgress, undefined, expectedPrice); return true; } catch (err) { if (tokens) { const headers = { "Content-Type": "application/json", "x-rkc-version": (0, $4d953031265289eb$exports.version) }; if (client === null || client === void 0 ? void 0 : client.apiKey) headers["x-api-key"] = client.apiKey; tokens.forEach((token)=>{ const data = { router: "v6", token: `${token.contract}:${token.tokenId}` }; (0, $iGiPT$axios).post(`${client.apiBase}/tokens/simulate-floor/v1`, JSON.stringify(data), { method: "POST", headers: headers }); }); } throw err; } } async function $b43bb2acb7afe5dd$export$1d5423ff89b08a3c(data) { const { id: id , signer: signer , onProgress: onProgress } = data; const client = (0, $8dc4e9b911526003$export$6bb76d6eba7e258c)(); const options = data.options || {}; if (!client.apiBase) throw new ReferenceError("ReservoirClient missing configuration"); try { const params = { id: id, ...options }; await (0, $cbe142d0473ea2cf$export$21ece85d7636deb)({ url: `${client.apiBase}/execute/cancel/v2`, params: params }, signer, onProgress); return true; } catch (err) { console.error(err); throw err; } } async function $09ed80e8104b77d0$export$c5dd9dc6df16df31(data) { const { listings: listings , signer: signer , onProgress: onProgress = ()=>{} , precheck: precheck } = data; const client = (0, $8dc4e9b911526003$export$6bb76d6eba7e258c)(); const maker = await signer.getAddress(); if (!client.apiBase) throw new ReferenceError("ReservoirClient missing configuration"); try { const data = { maker: maker, source: client.source || "" }; listings.forEach((listing)=>{ if (listing.orderbook === "reservoir" && client.marketplaceFee && client.marketplaceFeeRecipient && !("fees" in listing)) listing.fees = [ `${client.marketplaceFeeRecipient}:${client.marketplaceFee}`, ]; if (!("automatedRoyalties" in listing) && "automatedRoyalties" in client) listing.automatedRoyalties = client.automatedRoyalties; }); data.params = listings; const request = { url: `${client.apiBase}/execute/list/v4`, method: "post", data: data, headers: { "x-rkc-version": (0, $4d953031265289eb$exports.version) } }; if (precheck) { if ((client === null || client === void 0 ? void 0 : client.apiKey) && request.headers) request.headers["x-api-key"] = client.apiKey; if ((client === null || client === void 0 ? void 0 : client.uiVersion) && request.headers) request.headers["x-rkui-version"] = client.uiVersion; const res = await (0, $iGiPT$axios).request(request); if (res.status !== 200) throw res.data; const data = res.data; onProgress(data["steps"]); return data["steps"]; } else await (0, $cbe142d0473ea2cf$export$21ece85d7636deb)(request, signer, onProgress); return true; } catch (err) { console.error(err); throw err; } } async function $d90513673fc1026d$export$6d65a5902ff15306({ bids: bids , signer: signer , onProgress: onProgress }) { const client = (0, $8dc4e9b911526003$export$6bb76d6eba7e258c)(); const maker = await signer.getAddress(); if (!client.apiBase) throw new ReferenceError("ReservoirClient missing configuration"); try { const data = { maker: maker, source: client.source || "" }; bids.forEach((bid)=>{ if (!bid.token && !bid.collection && !bid.tokenSetId && (!bid.attributeKey || !bid.attributeValue)) throw { message: "Some bid data is missing", data: bid }; if (bid.orderbook === "reservoir" && client.marketplaceFee && client.marketplaceFeeRecipient && !("fees" in bid)) bid.fees = [ `${client.marketplaceFeeRecipient}:${client.marketplaceFee}`, ]; if (!("automatedRoyalties" in bid) && "automatedRoyalties" in client) bid.automatedRoyalties = client.automatedRoyalties; }); data.params = bids; await (0, $cbe142d0473ea2cf$export$21ece85d7636deb)({ url: `${client.apiBase}/execute/bid/v4`, method: "post", data: data }, signer, onProgress); return true; } catch (err) { console.error(err); throw err; } } const $2a1b39e78488cdef$var$actions = { acceptOffer: $1c822481ba778cd8$export$ed27da83bcbea2e5, buyToken: $5d30f75fa97319de$export$5e1997c166a16792, cancelOrder: $b43bb2acb7afe5dd$export$1d5423ff89b08a3c, listToken: $09ed80e8104b77d0$export$c5dd9dc6df16df31, placeBid: $d90513673fc1026d$export$6d65a5902ff15306 }; var $2a1b39e78488cdef$export$2e2bcd8739ae039 = $2a1b39e78488cdef$var$actions; let $8dc4e9b911526003$var$_client; class $8dc4e9b911526003$export$d0c36b5db6a81704 { constructor(options){ this.utils = { ...$d79888aa62b18edb$exports }; this.actions = (0, $2a1b39e78488cdef$export$2e2bcd8739ae039); this.version = (0, $4d953031265289eb$exports.version); this.apiKey = options.apiKey; this.uiVersion = options.uiVersion; this.apiBase = options.apiBase; this.automatedRoyalties = options.automatedRoyalties; this.marketplaceFee = options.marketplaceFee; this.marketplaceFeeRecipient = options.marketplaceFeeRecipient; this.normalizeRoyalties = options.normalizeRoyalties; if (!options.source) { if (typeof window !== "undefined") { let host = location.hostname; if (host.indexOf("www.") === 0) host = host.replace("www.", ""); this.source = host; console.warn("ReservoirKit automatically generated a source based on the url, we recommend providing a source when initializing ReservoirKit. Refer to our docs for steps on how to do this: http://docs.reservoir.tools"); } } else this.source = options.source; } configure(options) { this.source = options.source ? options.source : this.source; this.apiKey = options.apiKey ? options.apiKey : this.apiKey; this.uiVersion = options.uiVersion ? options.uiVersion : this.uiVersion; this.apiBase = options.apiBase ? options.apiBase : this.apiBase; this.marketplaceFee = options.marketplaceFee ? options.marketplaceFee : this.marketplaceFee; this.marketplaceFeeRecipient = options.marketplaceFeeRecipient ? options.marketplaceFeeRecipient : this.marketplaceFeeRecipient; this.automatedRoyalties = options.automatedRoyalties; this.normalizeRoyalties = options.normalizeRoyalties !== undefined ? options.normalizeRoyalties : this.normalizeRoyalties; } } function $8dc4e9b911526003$export$6bb76d6eba7e258c() { //throw an error return $8dc4e9b911526003$var$_client; } function $8dc4e9b911526003$export$5d730b7aed1a3eb0(options) { if (!$8dc4e9b911526003$var$_client) $8dc4e9b911526003$var$_client = new $8dc4e9b911526003$export$d0c36b5db6a81704(options); else $8dc4e9b911526003$var$_client.configure(options); return $8dc4e9b911526003$var$_client; } var $34b316458c7ab1b1$exports = {}; var $dd1cf571a8b47d15$exports = {}; $parcel$exportWildcard($34b316458c7ab1b1$exports, $dd1cf571a8b47d15$exports); export {$8dc4e9b911526003$export$d0c36b5db6a81704 as ReservoirClient, $8dc4e9b911526003$export$6bb76d6eba7e258c as getClient, $8dc4e9b911526003$export$5d730b7aed1a3eb0 as createClient, $cbe142d0473ea2cf$export$21ece85d7636deb as executeSteps, $a72505a16e120031$export$dc1827290674c112 as setParams, $fd2817e1b4d271f0$export$d2c70568ef790b87 as pollUntilOk, $fd2817e1b4d271f0$export$f014594cc879f602 as pollUntilHasData, $c0bb623c6f3fd12b$export$feaa73ad8ed3f2b9 as isOpenSeaBanned}; //# sourceMappingURL=index.module.js.map