UNPKG

@flaunch/sdk

Version:

Flaunch SDK to easily interact with the Flaunch protocol

289 lines (281 loc) 10.5 kB
import { s as slice, t as toFunctionSelector, f as formatAbiItem, A as AbiFunctionSignatureNotFoundError, d as decodeAbiParameters, g as getAbiItem, a as AbiErrorNotFoundError, b as AbiErrorInputsNotFoundError, e as encodeAbiParameters, c as concatHex, h as AbiFunctionNotFoundError, i as AbiFunctionOutputsNotFoundError, I as InvalidArrayError, B as BaseError, j as getUrl, k as stringify, l as batchGatewayAbi, m as solidityError, n as decodeErrorResult, o as isAddressEqual, p as call, q as concat, r as getAbortError, u as isAbortError, H as HttpRequestError, v as isHex } from './addresses-b6f6aad0.js'; import 'viem'; function decodeFunctionData(parameters) { const { abi, data } = parameters; const signature = slice(data, 0, 4); const description = abi.find((x) => x.type === 'function' && signature === toFunctionSelector(formatAbiItem(x))); if (!description) throw new AbiFunctionSignatureNotFoundError(signature, { docsPath: '/docs/contract/decodeFunctionData', }); return { functionName: description.name, args: ('inputs' in description && description.inputs && description.inputs.length > 0 ? decodeAbiParameters(description.inputs, slice(data, 4)) : undefined), }; } const docsPath$1 = '/docs/contract/encodeErrorResult'; function encodeErrorResult(parameters) { const { abi, errorName, args } = parameters; let abiItem = abi[0]; if (errorName) { const item = getAbiItem({ abi, args, name: errorName }); if (!item) throw new AbiErrorNotFoundError(errorName, { docsPath: docsPath$1 }); abiItem = item; } if (abiItem.type !== 'error') throw new AbiErrorNotFoundError(undefined, { docsPath: docsPath$1 }); const definition = formatAbiItem(abiItem); const signature = toFunctionSelector(definition); let data = '0x'; if (args && args.length > 0) { if (!abiItem.inputs) throw new AbiErrorInputsNotFoundError(abiItem.name, { docsPath: docsPath$1 }); data = encodeAbiParameters(abiItem.inputs, args); } return concatHex([signature, data]); } const docsPath = '/docs/contract/encodeFunctionResult'; function encodeFunctionResult(parameters) { const { abi, functionName, result } = parameters; let abiItem = abi[0]; if (functionName) { const item = getAbiItem({ abi, name: functionName }); if (!item) throw new AbiFunctionNotFoundError(functionName, { docsPath }); abiItem = item; } if (abiItem.type !== 'function') throw new AbiFunctionNotFoundError(undefined, { docsPath }); if (!abiItem.outputs) throw new AbiFunctionOutputsNotFoundError(abiItem.name, { docsPath }); const values = (() => { if (abiItem.outputs.length === 0) return []; if (abiItem.outputs.length === 1) return [result]; if (Array.isArray(result)) return result; throw new InvalidArrayError(result); })(); return encodeAbiParameters(abiItem.outputs, values); } class OffchainLookupError extends BaseError { constructor({ callbackSelector, cause, data, extraData, sender, urls, }) { super(cause.shortMessage || 'An error occurred while fetching for an offchain result.', { cause, metaMessages: [ ...(cause.metaMessages || []), cause.metaMessages?.length ? '' : [], 'Offchain Gateway Call:', urls && [ ' Gateway URL(s):', ...urls.map((url) => ` ${getUrl(url)}`), ], ` Sender: ${sender}`, ` Data: ${data}`, ` Callback selector: ${callbackSelector}`, ` Extra data: ${extraData}`, ].flat(), name: 'OffchainLookupError', }); } } class OffchainLookupResponseMalformedError extends BaseError { constructor({ result, url }) { super('Offchain gateway response is malformed. Response data must be a hex value.', { metaMessages: [ `Gateway URL: ${getUrl(url)}`, `Response: ${stringify(result)}`, ], name: 'OffchainLookupResponseMalformedError', }); } } class OffchainLookupSenderMismatchError extends BaseError { constructor({ sender, to }) { super('Reverted sender address does not match target contract address (`to`).', { metaMessages: [ `Contract address: ${to}`, `OffchainLookup sender address: ${sender}`, ], name: 'OffchainLookupSenderMismatchError', }); } } const localBatchGatewayUrl = 'x-batch-gateway:true'; async function localBatchGatewayRequest(parameters) { const { data, ccipRequest } = parameters; const { args: [queries], } = decodeFunctionData({ abi: batchGatewayAbi, data }); const failures = []; const responses = []; await Promise.all(queries.map(async (query, i) => { try { responses[i] = query.urls.includes(localBatchGatewayUrl) ? await localBatchGatewayRequest({ data: query.data, ccipRequest }) : await ccipRequest(query); failures[i] = false; } catch (err) { failures[i] = true; responses[i] = encodeError(err); } })); return encodeFunctionResult({ abi: batchGatewayAbi, functionName: 'query', result: [failures, responses], }); } function encodeError(error) { if (error.name === 'HttpRequestError' && error.status) return encodeErrorResult({ abi: batchGatewayAbi, errorName: 'HttpError', args: [error.status, error.shortMessage], }); return encodeErrorResult({ abi: [solidityError], errorName: 'Error', args: ['shortMessage' in error ? error.shortMessage : error.message], }); } const offchainLookupSignature = '0x556f1830'; const offchainLookupAbiItem = { name: 'OffchainLookup', type: 'error', inputs: [ { name: 'sender', type: 'address', }, { name: 'urls', type: 'string[]', }, { name: 'callData', type: 'bytes', }, { name: 'callbackFunction', type: 'bytes4', }, { name: 'extraData', type: 'bytes', }, ], }; async function offchainLookup(client, { blockNumber, blockTag, data, requestOptions, to, }) { const { args } = decodeErrorResult({ data, abi: [offchainLookupAbiItem], }); const [sender, urls, callData, callbackSelector, extraData] = args; const { ccipRead } = client; const ccipRequest_ = ccipRead && typeof ccipRead?.request === 'function' ? ccipRead.request : ccipRequest; try { if (!isAddressEqual(to, sender)) throw new OffchainLookupSenderMismatchError({ sender, to }); const result = urls.includes(localBatchGatewayUrl) ? await localBatchGatewayRequest({ data: callData, ccipRequest: (parameters) => ccipRequest_({ ...parameters, requestOptions }), }) : await ccipRequest_({ data: callData, requestOptions, sender, urls }); const { data: data_ } = await call(client, { blockNumber, blockTag, data: concat([ callbackSelector, encodeAbiParameters([{ type: 'bytes' }, { type: 'bytes' }], [result, extraData]), ]), requestOptions, to, }); return data_; } catch (err) { if (requestOptions?.signal?.aborted) throw getAbortError(requestOptions.signal); if (isAbortError(err)) throw err; throw new OffchainLookupError({ callbackSelector, cause: err, data, extraData, sender, urls, }); } } async function ccipRequest({ data, requestOptions, sender, urls, }) { let error = new Error('An unknown error occurred.'); for (let i = 0; i < urls.length; i++) { if (requestOptions?.signal?.aborted) throw getAbortError(requestOptions.signal); const url = urls[i]; const method = url.includes('{data}') ? 'GET' : 'POST'; const body = method === 'POST' ? { data, sender } : undefined; const headers = method === 'POST' ? { 'Content-Type': 'application/json' } : {}; try { const response = await fetch(url.replace('{sender}', sender.toLowerCase()).replace('{data}', data), { body: JSON.stringify(body), headers, method, ...(requestOptions?.signal ? { signal: requestOptions.signal } : {}), }); let result; if (response.headers.get('Content-Type')?.startsWith('application/json')) { result = (await response.json()).data; } else { result = (await response.text()); } if (!response.ok) { error = new HttpRequestError({ body, details: result?.error ? stringify(result.error) : response.statusText, headers: response.headers, status: response.status, url, }); continue; } if (!isHex(result)) { error = new OffchainLookupResponseMalformedError({ result, url, }); continue; } return result; } catch (err) { if (requestOptions?.signal?.aborted) throw getAbortError(requestOptions.signal); if (isAbortError(err)) throw err; error = new HttpRequestError({ body, details: err.message, url, }); } } throw error; } export { ccipRequest, offchainLookup, offchainLookupAbiItem, offchainLookupSignature }; //# sourceMappingURL=ccip-3278052c.js.map