@blazephoenix/sdk 1.0.0 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -2
- package/dist/index.cjs +280 -258
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +281 -259
- package/dist/index.js.map +1 -1
- package/llms.txt +49 -0
- package/package.json +6 -3
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { custom, fallback, createPublicClient, decodeErrorResult, encodeFunctionData, decodeFunctionData, getAddress, decodeFunctionResult, parseEventLogs, webSocket, http } from 'viem';
|
|
2
2
|
|
|
3
3
|
// src/client.ts
|
|
4
4
|
|
|
@@ -4714,12 +4714,278 @@ function phoenixCheck(pv, tokenIn, tokenOut) {
|
|
|
4714
4714
|
disclaimer: 'Deterministic checks derived from on-chain state, not financial advice. "blocked" is a real answer \u2014 we fail closed rather than guess.'
|
|
4715
4715
|
};
|
|
4716
4716
|
}
|
|
4717
|
+
|
|
4718
|
+
// src/constants.ts
|
|
4719
|
+
var API_BASE = "https://blazephoenix.xyz";
|
|
4720
|
+
var DEPLOYMENTS_URL = `${API_BASE}/api/deployments`;
|
|
4721
|
+
var SUPPORTED_CHAIN_IDS = [8453, 1, 10, 42161, 4663];
|
|
4722
|
+
var CHAINS = {
|
|
4723
|
+
1: {
|
|
4724
|
+
chainId: 1,
|
|
4725
|
+
name: "Ethereum",
|
|
4726
|
+
key: "ETHEREUM",
|
|
4727
|
+
explorer: "https://etherscan.io",
|
|
4728
|
+
weth: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
|
|
4729
|
+
usdc: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
|
|
4730
|
+
blockTime: 12
|
|
4731
|
+
},
|
|
4732
|
+
8453: {
|
|
4733
|
+
chainId: 8453,
|
|
4734
|
+
name: "Base",
|
|
4735
|
+
key: "BASE",
|
|
4736
|
+
explorer: "https://basescan.org",
|
|
4737
|
+
weth: "0x4200000000000000000000000000000000000006",
|
|
4738
|
+
usdc: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
|
|
4739
|
+
bzpx: "0x23113e72165a034265Ab8Bf2277CCB7a85Cb7483",
|
|
4740
|
+
staking: "0x3f60C7aa0c36a78D200405feBE143d2Cf3fA0c77",
|
|
4741
|
+
blockTime: 2
|
|
4742
|
+
},
|
|
4743
|
+
10: {
|
|
4744
|
+
chainId: 10,
|
|
4745
|
+
name: "Optimism",
|
|
4746
|
+
key: "OPTIMISM",
|
|
4747
|
+
explorer: "https://optimistic.etherscan.io",
|
|
4748
|
+
weth: "0x4200000000000000000000000000000000000006",
|
|
4749
|
+
usdc: "0x0b2C639c533813f4Aa9D7837CAf62653d097Ff85",
|
|
4750
|
+
blockTime: 2
|
|
4751
|
+
},
|
|
4752
|
+
42161: {
|
|
4753
|
+
chainId: 42161,
|
|
4754
|
+
name: "Arbitrum",
|
|
4755
|
+
key: "ARBITRUM",
|
|
4756
|
+
explorer: "https://arbiscan.io",
|
|
4757
|
+
weth: "0x82aF49447D8a07e3bd95BD0d56f35241523fBab1",
|
|
4758
|
+
usdc: "0xaf88d065e77c8cC2239327C5EDb3A432268e5831",
|
|
4759
|
+
blockTime: 0.25
|
|
4760
|
+
},
|
|
4761
|
+
// Robinhood Chain — the dollar asset is USDG, not USDC; the `usdc` field
|
|
4762
|
+
// carries the chain's canonical dollar token. Explorer is Blockscout.
|
|
4763
|
+
4663: {
|
|
4764
|
+
chainId: 4663,
|
|
4765
|
+
name: "Robinhood",
|
|
4766
|
+
key: "ROBINHOOD",
|
|
4767
|
+
explorer: "https://robinhoodchain.blockscout.com",
|
|
4768
|
+
weth: "0x0Bd7D308f8E1639FAb988df18A8011f41EAcAD73",
|
|
4769
|
+
usdc: "0x5fc5360D0400a0Fd4f2af552ADD042D716F1d168",
|
|
4770
|
+
blockTime: 2
|
|
4771
|
+
}
|
|
4772
|
+
};
|
|
4773
|
+
var ALIASES = {
|
|
4774
|
+
"1": 1,
|
|
4775
|
+
eth: 1,
|
|
4776
|
+
ethereum: 1,
|
|
4777
|
+
mainnet: 1,
|
|
4778
|
+
"8453": 8453,
|
|
4779
|
+
base: 8453,
|
|
4780
|
+
"10": 10,
|
|
4781
|
+
op: 10,
|
|
4782
|
+
optimism: 10,
|
|
4783
|
+
"42161": 42161,
|
|
4784
|
+
arb: 42161,
|
|
4785
|
+
arbitrum: 42161,
|
|
4786
|
+
"arbitrum-one": 42161,
|
|
4787
|
+
"4663": 4663,
|
|
4788
|
+
rh: 4663,
|
|
4789
|
+
robinhood: 4663,
|
|
4790
|
+
"robinhood-chain": 4663
|
|
4791
|
+
};
|
|
4792
|
+
function resolveChain(chain) {
|
|
4793
|
+
const id = ALIASES[String(chain).trim().toLowerCase()];
|
|
4794
|
+
if (!id) {
|
|
4795
|
+
throw new Error(
|
|
4796
|
+
`Unsupported chain "${chain}" \u2014 use 8453/base, 1/eth, 10/optimism, 42161/arbitrum or 4663/robinhood`
|
|
4797
|
+
);
|
|
4798
|
+
}
|
|
4799
|
+
return id;
|
|
4800
|
+
}
|
|
4801
|
+
function tryResolveChain(chain) {
|
|
4802
|
+
return ALIASES[String(chain).trim().toLowerCase()];
|
|
4803
|
+
}
|
|
4804
|
+
var ZERO_ADDRESS = "0x0000000000000000000000000000000000000000";
|
|
4805
|
+
var NATIVE_TOKEN = "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE";
|
|
4806
|
+
var PERMIT2 = "0x000000000022D473030F116dDEE9F6B43aC78BA3";
|
|
4807
|
+
var FEE_BPS = 28;
|
|
4808
|
+
var SWAP_TOPIC0 = "0xd6d34547c69c5ee3d2667625c188acf1006abb93e0ee7cf03925c67cf7760413";
|
|
4809
|
+
var SURPLUS_TOPIC0 = "0x1a3afef0f067eb51a6bfec6ab3625a4408dd8c3571b72836483e68feb70d1026";
|
|
4810
|
+
var EXECUTION_PROOF_TOPIC0 = "0xb5a62bcb8753e37706da20862f2a32a16831ef0144567eb15b1da49547e9f84c";
|
|
4811
|
+
var FEE_TOPIC0 = "0x18fa25e22e0f1f39ef2130081363ba86a1259e598e669558683dabfc15bfe731";
|
|
4812
|
+
|
|
4813
|
+
// src/rpc.ts
|
|
4814
|
+
var isTransport = (v) => typeof v === "function";
|
|
4815
|
+
var isEip1193 = (v) => !!v && typeof v === "object" && typeof v.request === "function";
|
|
4816
|
+
var isSource = (v) => typeof v === "string" || Array.isArray(v) || isTransport(v) || isEip1193(v);
|
|
4817
|
+
function isAllowedRpcUrl(url) {
|
|
4818
|
+
let u;
|
|
4819
|
+
try {
|
|
4820
|
+
u = new URL(url.trim());
|
|
4821
|
+
} catch {
|
|
4822
|
+
return false;
|
|
4823
|
+
}
|
|
4824
|
+
if (u.protocol === "https:" || u.protocol === "wss:") return true;
|
|
4825
|
+
if (u.protocol === "http:" || u.protocol === "ws:") {
|
|
4826
|
+
return u.hostname === "localhost" || u.hostname === "127.0.0.1" || u.hostname === "[::1]";
|
|
4827
|
+
}
|
|
4828
|
+
return false;
|
|
4829
|
+
}
|
|
4830
|
+
function urlTransport(url, o) {
|
|
4831
|
+
if (!isAllowedRpcUrl(url)) {
|
|
4832
|
+
throw new BlazeError("bad_request", `refusing RPC URL "${redact(url)}": use https:// or wss:// (http/ws only for localhost)`);
|
|
4833
|
+
}
|
|
4834
|
+
const u = url.trim();
|
|
4835
|
+
return u.startsWith("ws") ? webSocket(u, { timeout: o.timeoutMs, retryCount: o.retries }) : http(u, { timeout: o.timeoutMs, retryCount: o.retries, batch: o.batch });
|
|
4836
|
+
}
|
|
4837
|
+
function redact(url) {
|
|
4838
|
+
try {
|
|
4839
|
+
const u = new URL(url);
|
|
4840
|
+
const path = u.pathname.length > 1 ? "/\u2026" : "";
|
|
4841
|
+
return `${u.protocol}//${u.host}${path}`;
|
|
4842
|
+
} catch {
|
|
4843
|
+
return "<invalid url>";
|
|
4844
|
+
}
|
|
4845
|
+
}
|
|
4846
|
+
function scrubUrls(text) {
|
|
4847
|
+
return text.replace(/\b(?:https?|wss?):\/\/[^\s"'<>]+/gi, (m) => redact(m));
|
|
4848
|
+
}
|
|
4849
|
+
function transportFrom(src, opts = {}) {
|
|
4850
|
+
const o = {
|
|
4851
|
+
timeoutMs: opts.timeoutMs ?? 1e4,
|
|
4852
|
+
retries: opts.retries ?? 2,
|
|
4853
|
+
batch: opts.batch ?? false
|
|
4854
|
+
};
|
|
4855
|
+
if (isTransport(src)) return src;
|
|
4856
|
+
if (isEip1193(src)) return custom(src, { retryCount: o.retries });
|
|
4857
|
+
if (typeof src === "string") return urlTransport(src, o);
|
|
4858
|
+
if (Array.isArray(src)) {
|
|
4859
|
+
const list = src.map((u) => u.trim()).filter(Boolean);
|
|
4860
|
+
if (list.length === 0) throw new BlazeError("rpc_required", "empty RPC list");
|
|
4861
|
+
if (list.length === 1) return urlTransport(list[0], o);
|
|
4862
|
+
return fallback(list.map((u) => urlTransport(u, { ...o, retries: 0 })), { retryCount: o.retries });
|
|
4863
|
+
}
|
|
4864
|
+
throw new BlazeError("bad_request", "unrecognised rpc value");
|
|
4865
|
+
}
|
|
4866
|
+
var RPC_HELP = "BlazePhoenix SDK 1.x runs 100% on YOUR RPC \u2014 it ships no endpoints and never reads through our servers. Pass `rpc` (a URL, a list of URLs, a wallet provider or a viem transport), e.g. new BlazePhoenix({ rpc: { base: process.env.BASE_RPC_URL } }). Any provider's free tier is enough.";
|
|
4867
|
+
var RpcRouter = class {
|
|
4868
|
+
perChain = /* @__PURE__ */ new Map();
|
|
4869
|
+
single;
|
|
4870
|
+
opts;
|
|
4871
|
+
constructor(config, opts = {}) {
|
|
4872
|
+
this.opts = opts;
|
|
4873
|
+
if (config === void 0 || config === null || config === "") return;
|
|
4874
|
+
if (isSource(config)) {
|
|
4875
|
+
this.single = { source: config };
|
|
4876
|
+
return;
|
|
4877
|
+
}
|
|
4878
|
+
if (typeof config !== "object") throw new BlazeError("bad_request", "rpc must be a URL, a list, a provider, a transport or a per-chain map");
|
|
4879
|
+
for (const [k, v] of Object.entries(config)) {
|
|
4880
|
+
if (v === void 0 || v === null || v === "") continue;
|
|
4881
|
+
const id = tryResolveChain(k);
|
|
4882
|
+
if (!id) throw new BlazeError("bad_request", `rpc map: unknown chain "${k}"`);
|
|
4883
|
+
if (!isSource(v)) throw new BlazeError("bad_request", `rpc map: bad value for chain "${k}"`);
|
|
4884
|
+
this.perChain.set(id, { source: v, chainId: id });
|
|
4885
|
+
}
|
|
4886
|
+
}
|
|
4887
|
+
/** Chains with an explicitly configured RPC (a single source reports none). */
|
|
4888
|
+
configuredChains() {
|
|
4889
|
+
return SUPPORTED_CHAIN_IDS.filter((id) => this.perChain.has(id));
|
|
4890
|
+
}
|
|
4891
|
+
hasAny() {
|
|
4892
|
+
return !!this.single || this.perChain.size > 0;
|
|
4893
|
+
}
|
|
4894
|
+
/** The chain to use when a request names none: the only configured one. */
|
|
4895
|
+
async defaultChain() {
|
|
4896
|
+
if (this.perChain.size === 1) return [...this.perChain.keys()][0];
|
|
4897
|
+
if (this.single && this.perChain.size === 0) {
|
|
4898
|
+
const id = await this.verify(this.single);
|
|
4899
|
+
const c = tryResolveChain(id);
|
|
4900
|
+
if (!c) throw new BlazeError("rpc_chain_mismatch", `your RPC serves chain ${id}, which BlazePhoenix is not deployed on`);
|
|
4901
|
+
return c;
|
|
4902
|
+
}
|
|
4903
|
+
throw new BlazeError("bad_request", "this request needs `chain` (several RPCs are configured)");
|
|
4904
|
+
}
|
|
4905
|
+
slotFor(chainId) {
|
|
4906
|
+
const s = this.perChain.get(chainId) ?? this.single;
|
|
4907
|
+
if (!s) {
|
|
4908
|
+
throw new BlazeError(
|
|
4909
|
+
"rpc_required",
|
|
4910
|
+
`no RPC configured for ${CHAINS[chainId].name} (${chainId}). ${RPC_HELP}`,
|
|
4911
|
+
{ details: { chainId } }
|
|
4912
|
+
);
|
|
4913
|
+
}
|
|
4914
|
+
return s;
|
|
4915
|
+
}
|
|
4916
|
+
clientOf(s) {
|
|
4917
|
+
if (!s.client) {
|
|
4918
|
+
s.client = createPublicClient({ transport: transportFrom(s.source, this.opts) });
|
|
4919
|
+
}
|
|
4920
|
+
return s.client;
|
|
4921
|
+
}
|
|
4922
|
+
verify(s) {
|
|
4923
|
+
if (!s.verified) {
|
|
4924
|
+
const c = this.clientOf(s);
|
|
4925
|
+
s.verified = c.getChainId().catch((e) => {
|
|
4926
|
+
s.verified = void 0;
|
|
4927
|
+
throw new BlazeError("rpc_error", `your RPC did not answer eth_chainId: ${scrubUrls(String(e?.message ?? e))}`, { cause: e });
|
|
4928
|
+
});
|
|
4929
|
+
}
|
|
4930
|
+
return s.verified;
|
|
4931
|
+
}
|
|
4932
|
+
/** A PublicClient for `chain`, over YOUR node, after checking it really is that chain. */
|
|
4933
|
+
async client(chain) {
|
|
4934
|
+
const chainId = resolveChain(chain);
|
|
4935
|
+
const s = this.slotFor(chainId);
|
|
4936
|
+
const actual = await this.verify(s);
|
|
4937
|
+
if (actual !== chainId) {
|
|
4938
|
+
throw new BlazeError(
|
|
4939
|
+
"rpc_chain_mismatch",
|
|
4940
|
+
`your RPC serves chain ${actual}, not ${CHAINS[chainId].name} (${chainId}) \u2014 configure one per chain: rpc: { base: "\u2026", eth: "\u2026" }`,
|
|
4941
|
+
{ details: { expected: chainId, actual } }
|
|
4942
|
+
);
|
|
4943
|
+
}
|
|
4944
|
+
return this.clientOf(s);
|
|
4945
|
+
}
|
|
4946
|
+
};
|
|
4947
|
+
function rpcFromEnv(env = globalEnv()) {
|
|
4948
|
+
const split = (v) => {
|
|
4949
|
+
const list = v.split(",").map((s) => s.trim()).filter(Boolean);
|
|
4950
|
+
return list.length === 1 ? list[0] : list;
|
|
4951
|
+
};
|
|
4952
|
+
const map = {};
|
|
4953
|
+
for (const id of SUPPORTED_CHAIN_IDS) {
|
|
4954
|
+
const v = env[`BLAZEPHOENIX_RPC_${CHAINS[id].key}`] ?? env[`BLAZEPHOENIX_RPC_${id}`];
|
|
4955
|
+
if (v && v.trim()) map[String(id)] = split(v);
|
|
4956
|
+
}
|
|
4957
|
+
const single = env.BLAZEPHOENIX_RPC_URL;
|
|
4958
|
+
if (Object.keys(map).length > 0) {
|
|
4959
|
+
if (single && single.trim()) {
|
|
4960
|
+
throw new BlazeError(
|
|
4961
|
+
"bad_request",
|
|
4962
|
+
"set either BLAZEPHOENIX_RPC_URL (one node) or the per-chain BLAZEPHOENIX_RPC_<CHAIN> variables, not both"
|
|
4963
|
+
);
|
|
4964
|
+
}
|
|
4965
|
+
return map;
|
|
4966
|
+
}
|
|
4967
|
+
return single && single.trim() ? split(single) : void 0;
|
|
4968
|
+
}
|
|
4969
|
+
function globalEnv() {
|
|
4970
|
+
const p = globalThis.process;
|
|
4971
|
+
return p?.env ?? {};
|
|
4972
|
+
}
|
|
4973
|
+
|
|
4974
|
+
// src/errors.ts
|
|
4975
|
+
function scrubCause(c, depth = 0) {
|
|
4976
|
+
if (c === void 0 || c === null || depth > 8) return void 0;
|
|
4977
|
+
if (!(c instanceof Error)) return scrubUrls(String(c));
|
|
4978
|
+
const inner = scrubCause(c.cause, depth + 1);
|
|
4979
|
+
const out = new Error(scrubUrls(c.message), inner !== void 0 ? { cause: inner } : void 0);
|
|
4980
|
+
out.name = c.name;
|
|
4981
|
+
return out;
|
|
4982
|
+
}
|
|
4717
4983
|
var BlazeError = class extends Error {
|
|
4718
4984
|
code;
|
|
4719
4985
|
details;
|
|
4720
4986
|
revert;
|
|
4721
4987
|
constructor(code, message, opts = {}) {
|
|
4722
|
-
super(message, opts.cause !== void 0 ? { cause: opts.cause } : void 0);
|
|
4988
|
+
super(message, opts.cause !== void 0 ? { cause: scrubCause(opts.cause) } : void 0);
|
|
4723
4989
|
this.name = "BlazeError";
|
|
4724
4990
|
this.code = code;
|
|
4725
4991
|
this.details = opts.details;
|
|
@@ -4882,101 +5148,6 @@ function minOutFor(netOut, slippageBps, floor) {
|
|
|
4882
5148
|
return bySlip > floor ? bySlip : floor;
|
|
4883
5149
|
}
|
|
4884
5150
|
|
|
4885
|
-
// src/constants.ts
|
|
4886
|
-
var API_BASE = "https://blazephoenix.xyz";
|
|
4887
|
-
var DEPLOYMENTS_URL = `${API_BASE}/api/deployments`;
|
|
4888
|
-
var SUPPORTED_CHAIN_IDS = [8453, 1, 10, 42161, 4663];
|
|
4889
|
-
var CHAINS = {
|
|
4890
|
-
1: {
|
|
4891
|
-
chainId: 1,
|
|
4892
|
-
name: "Ethereum",
|
|
4893
|
-
key: "ETHEREUM",
|
|
4894
|
-
explorer: "https://etherscan.io",
|
|
4895
|
-
weth: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
|
|
4896
|
-
usdc: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
|
|
4897
|
-
blockTime: 12
|
|
4898
|
-
},
|
|
4899
|
-
8453: {
|
|
4900
|
-
chainId: 8453,
|
|
4901
|
-
name: "Base",
|
|
4902
|
-
key: "BASE",
|
|
4903
|
-
explorer: "https://basescan.org",
|
|
4904
|
-
weth: "0x4200000000000000000000000000000000000006",
|
|
4905
|
-
usdc: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
|
|
4906
|
-
bzpx: "0x23113e72165a034265Ab8Bf2277CCB7a85Cb7483",
|
|
4907
|
-
staking: "0x3f60C7aa0c36a78D200405feBE143d2Cf3fA0c77",
|
|
4908
|
-
blockTime: 2
|
|
4909
|
-
},
|
|
4910
|
-
10: {
|
|
4911
|
-
chainId: 10,
|
|
4912
|
-
name: "Optimism",
|
|
4913
|
-
key: "OPTIMISM",
|
|
4914
|
-
explorer: "https://optimistic.etherscan.io",
|
|
4915
|
-
weth: "0x4200000000000000000000000000000000000006",
|
|
4916
|
-
usdc: "0x0b2C639c533813f4Aa9D7837CAf62653d097Ff85",
|
|
4917
|
-
blockTime: 2
|
|
4918
|
-
},
|
|
4919
|
-
42161: {
|
|
4920
|
-
chainId: 42161,
|
|
4921
|
-
name: "Arbitrum",
|
|
4922
|
-
key: "ARBITRUM",
|
|
4923
|
-
explorer: "https://arbiscan.io",
|
|
4924
|
-
weth: "0x82aF49447D8a07e3bd95BD0d56f35241523fBab1",
|
|
4925
|
-
usdc: "0xaf88d065e77c8cC2239327C5EDb3A432268e5831",
|
|
4926
|
-
blockTime: 0.25
|
|
4927
|
-
},
|
|
4928
|
-
// Robinhood Chain — the dollar asset is USDG, not USDC; the `usdc` field
|
|
4929
|
-
// carries the chain's canonical dollar token. Explorer is Blockscout.
|
|
4930
|
-
4663: {
|
|
4931
|
-
chainId: 4663,
|
|
4932
|
-
name: "Robinhood",
|
|
4933
|
-
key: "ROBINHOOD",
|
|
4934
|
-
explorer: "https://robinhoodchain.blockscout.com",
|
|
4935
|
-
weth: "0x0Bd7D308f8E1639FAb988df18A8011f41EAcAD73",
|
|
4936
|
-
usdc: "0x5fc5360D0400a0Fd4f2af552ADD042D716F1d168",
|
|
4937
|
-
blockTime: 2
|
|
4938
|
-
}
|
|
4939
|
-
};
|
|
4940
|
-
var ALIASES = {
|
|
4941
|
-
"1": 1,
|
|
4942
|
-
eth: 1,
|
|
4943
|
-
ethereum: 1,
|
|
4944
|
-
mainnet: 1,
|
|
4945
|
-
"8453": 8453,
|
|
4946
|
-
base: 8453,
|
|
4947
|
-
"10": 10,
|
|
4948
|
-
op: 10,
|
|
4949
|
-
optimism: 10,
|
|
4950
|
-
"42161": 42161,
|
|
4951
|
-
arb: 42161,
|
|
4952
|
-
arbitrum: 42161,
|
|
4953
|
-
"arbitrum-one": 42161,
|
|
4954
|
-
"4663": 4663,
|
|
4955
|
-
rh: 4663,
|
|
4956
|
-
robinhood: 4663,
|
|
4957
|
-
"robinhood-chain": 4663
|
|
4958
|
-
};
|
|
4959
|
-
function resolveChain(chain) {
|
|
4960
|
-
const id = ALIASES[String(chain).trim().toLowerCase()];
|
|
4961
|
-
if (!id) {
|
|
4962
|
-
throw new Error(
|
|
4963
|
-
`Unsupported chain "${chain}" \u2014 use 8453/base, 1/eth, 10/optimism, 42161/arbitrum or 4663/robinhood`
|
|
4964
|
-
);
|
|
4965
|
-
}
|
|
4966
|
-
return id;
|
|
4967
|
-
}
|
|
4968
|
-
function tryResolveChain(chain) {
|
|
4969
|
-
return ALIASES[String(chain).trim().toLowerCase()];
|
|
4970
|
-
}
|
|
4971
|
-
var ZERO_ADDRESS = "0x0000000000000000000000000000000000000000";
|
|
4972
|
-
var NATIVE_TOKEN = "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE";
|
|
4973
|
-
var PERMIT2 = "0x000000000022D473030F116dDEE9F6B43aC78BA3";
|
|
4974
|
-
var FEE_BPS = 28;
|
|
4975
|
-
var SWAP_TOPIC0 = "0xd6d34547c69c5ee3d2667625c188acf1006abb93e0ee7cf03925c67cf7760413";
|
|
4976
|
-
var SURPLUS_TOPIC0 = "0x1a3afef0f067eb51a6bfec6ab3625a4408dd8c3571b72836483e68feb70d1026";
|
|
4977
|
-
var EXECUTION_PROOF_TOPIC0 = "0xb5a62bcb8753e37706da20862f2a32a16831ef0144567eb15b1da49547e9f84c";
|
|
4978
|
-
var FEE_TOPIC0 = "0x18fa25e22e0f1f39ef2130081363ba86a1259e598e669558683dabfc15bfe731";
|
|
4979
|
-
|
|
4980
5151
|
// src/deployments.ts
|
|
4981
5152
|
var Z = ZERO_ADDRESS;
|
|
4982
5153
|
var pending = () => ({ core: Z, hub: Z, solver: Z, router: Z, quoter: Z });
|
|
@@ -5469,162 +5640,6 @@ function fromBaseUnits(v, decimals, maxDp) {
|
|
|
5469
5640
|
frac = frac.replace(/0+$/, "");
|
|
5470
5641
|
return `${neg ? "-" : ""}${whole}${frac ? `.${frac}` : ""}`;
|
|
5471
5642
|
}
|
|
5472
|
-
var isTransport = (v) => typeof v === "function";
|
|
5473
|
-
var isEip1193 = (v) => !!v && typeof v === "object" && typeof v.request === "function";
|
|
5474
|
-
var isSource = (v) => typeof v === "string" || Array.isArray(v) || isTransport(v) || isEip1193(v);
|
|
5475
|
-
function isAllowedRpcUrl(url) {
|
|
5476
|
-
let u;
|
|
5477
|
-
try {
|
|
5478
|
-
u = new URL(url.trim());
|
|
5479
|
-
} catch {
|
|
5480
|
-
return false;
|
|
5481
|
-
}
|
|
5482
|
-
if (u.protocol === "https:" || u.protocol === "wss:") return true;
|
|
5483
|
-
if (u.protocol === "http:" || u.protocol === "ws:") {
|
|
5484
|
-
return u.hostname === "localhost" || u.hostname === "127.0.0.1" || u.hostname === "[::1]";
|
|
5485
|
-
}
|
|
5486
|
-
return false;
|
|
5487
|
-
}
|
|
5488
|
-
function urlTransport(url, o) {
|
|
5489
|
-
if (!isAllowedRpcUrl(url)) {
|
|
5490
|
-
throw new BlazeError("bad_request", `refusing RPC URL "${redact(url)}": use https:// or wss:// (http/ws only for localhost)`);
|
|
5491
|
-
}
|
|
5492
|
-
const u = url.trim();
|
|
5493
|
-
return u.startsWith("ws") ? webSocket(u, { timeout: o.timeoutMs, retryCount: o.retries }) : http(u, { timeout: o.timeoutMs, retryCount: o.retries, batch: o.batch });
|
|
5494
|
-
}
|
|
5495
|
-
function redact(url) {
|
|
5496
|
-
try {
|
|
5497
|
-
const u = new URL(url);
|
|
5498
|
-
const path = u.pathname.length > 1 ? "/\u2026" : "";
|
|
5499
|
-
return `${u.protocol}//${u.host}${path}`;
|
|
5500
|
-
} catch {
|
|
5501
|
-
return "<invalid url>";
|
|
5502
|
-
}
|
|
5503
|
-
}
|
|
5504
|
-
function transportFrom(src, opts = {}) {
|
|
5505
|
-
const o = {
|
|
5506
|
-
timeoutMs: opts.timeoutMs ?? 1e4,
|
|
5507
|
-
retries: opts.retries ?? 2,
|
|
5508
|
-
batch: opts.batch ?? false
|
|
5509
|
-
};
|
|
5510
|
-
if (isTransport(src)) return src;
|
|
5511
|
-
if (isEip1193(src)) return custom(src, { retryCount: o.retries });
|
|
5512
|
-
if (typeof src === "string") return urlTransport(src, o);
|
|
5513
|
-
if (Array.isArray(src)) {
|
|
5514
|
-
const list = src.map((u) => u.trim()).filter(Boolean);
|
|
5515
|
-
if (list.length === 0) throw new BlazeError("rpc_required", "empty RPC list");
|
|
5516
|
-
if (list.length === 1) return urlTransport(list[0], o);
|
|
5517
|
-
return fallback(list.map((u) => urlTransport(u, { ...o, retries: 0 })), { retryCount: o.retries });
|
|
5518
|
-
}
|
|
5519
|
-
throw new BlazeError("bad_request", "unrecognised rpc value");
|
|
5520
|
-
}
|
|
5521
|
-
var RPC_HELP = "BlazePhoenix SDK 1.x runs 100% on YOUR RPC \u2014 it ships no endpoints and never reads through our servers. Pass `rpc` (a URL, a list of URLs, a wallet provider or a viem transport), e.g. new BlazePhoenix({ rpc: { base: process.env.BASE_RPC_URL } }). Any provider's free tier is enough.";
|
|
5522
|
-
var RpcRouter = class {
|
|
5523
|
-
perChain = /* @__PURE__ */ new Map();
|
|
5524
|
-
single;
|
|
5525
|
-
opts;
|
|
5526
|
-
constructor(config, opts = {}) {
|
|
5527
|
-
this.opts = opts;
|
|
5528
|
-
if (config === void 0 || config === null || config === "") return;
|
|
5529
|
-
if (isSource(config)) {
|
|
5530
|
-
this.single = { source: config };
|
|
5531
|
-
return;
|
|
5532
|
-
}
|
|
5533
|
-
if (typeof config !== "object") throw new BlazeError("bad_request", "rpc must be a URL, a list, a provider, a transport or a per-chain map");
|
|
5534
|
-
for (const [k, v] of Object.entries(config)) {
|
|
5535
|
-
if (v === void 0 || v === null || v === "") continue;
|
|
5536
|
-
const id = tryResolveChain(k);
|
|
5537
|
-
if (!id) throw new BlazeError("bad_request", `rpc map: unknown chain "${k}"`);
|
|
5538
|
-
if (!isSource(v)) throw new BlazeError("bad_request", `rpc map: bad value for chain "${k}"`);
|
|
5539
|
-
this.perChain.set(id, { source: v, chainId: id });
|
|
5540
|
-
}
|
|
5541
|
-
}
|
|
5542
|
-
/** Chains with an explicitly configured RPC (a single source reports none). */
|
|
5543
|
-
configuredChains() {
|
|
5544
|
-
return SUPPORTED_CHAIN_IDS.filter((id) => this.perChain.has(id));
|
|
5545
|
-
}
|
|
5546
|
-
hasAny() {
|
|
5547
|
-
return !!this.single || this.perChain.size > 0;
|
|
5548
|
-
}
|
|
5549
|
-
/** The chain to use when a request names none: the only configured one. */
|
|
5550
|
-
async defaultChain() {
|
|
5551
|
-
if (this.perChain.size === 1) return [...this.perChain.keys()][0];
|
|
5552
|
-
if (this.single && this.perChain.size === 0) {
|
|
5553
|
-
const id = await this.verify(this.single);
|
|
5554
|
-
const c = tryResolveChain(id);
|
|
5555
|
-
if (!c) throw new BlazeError("rpc_chain_mismatch", `your RPC serves chain ${id}, which BlazePhoenix is not deployed on`);
|
|
5556
|
-
return c;
|
|
5557
|
-
}
|
|
5558
|
-
throw new BlazeError("bad_request", "this request needs `chain` (several RPCs are configured)");
|
|
5559
|
-
}
|
|
5560
|
-
slotFor(chainId) {
|
|
5561
|
-
const s = this.perChain.get(chainId) ?? this.single;
|
|
5562
|
-
if (!s) {
|
|
5563
|
-
throw new BlazeError(
|
|
5564
|
-
"rpc_required",
|
|
5565
|
-
`no RPC configured for ${CHAINS[chainId].name} (${chainId}). ${RPC_HELP}`,
|
|
5566
|
-
{ details: { chainId } }
|
|
5567
|
-
);
|
|
5568
|
-
}
|
|
5569
|
-
return s;
|
|
5570
|
-
}
|
|
5571
|
-
clientOf(s) {
|
|
5572
|
-
if (!s.client) {
|
|
5573
|
-
s.client = createPublicClient({ transport: transportFrom(s.source, this.opts) });
|
|
5574
|
-
}
|
|
5575
|
-
return s.client;
|
|
5576
|
-
}
|
|
5577
|
-
verify(s) {
|
|
5578
|
-
if (!s.verified) {
|
|
5579
|
-
const c = this.clientOf(s);
|
|
5580
|
-
s.verified = c.getChainId().catch((e) => {
|
|
5581
|
-
s.verified = void 0;
|
|
5582
|
-
throw new BlazeError("rpc_error", `your RPC did not answer eth_chainId: ${e?.message ?? e}`, { cause: e });
|
|
5583
|
-
});
|
|
5584
|
-
}
|
|
5585
|
-
return s.verified;
|
|
5586
|
-
}
|
|
5587
|
-
/** A PublicClient for `chain`, over YOUR node, after checking it really is that chain. */
|
|
5588
|
-
async client(chain) {
|
|
5589
|
-
const chainId = resolveChain(chain);
|
|
5590
|
-
const s = this.slotFor(chainId);
|
|
5591
|
-
const actual = await this.verify(s);
|
|
5592
|
-
if (actual !== chainId) {
|
|
5593
|
-
throw new BlazeError(
|
|
5594
|
-
"rpc_chain_mismatch",
|
|
5595
|
-
`your RPC serves chain ${actual}, not ${CHAINS[chainId].name} (${chainId}) \u2014 configure one per chain: rpc: { base: "\u2026", eth: "\u2026" }`,
|
|
5596
|
-
{ details: { expected: chainId, actual } }
|
|
5597
|
-
);
|
|
5598
|
-
}
|
|
5599
|
-
return this.clientOf(s);
|
|
5600
|
-
}
|
|
5601
|
-
};
|
|
5602
|
-
function rpcFromEnv(env = globalEnv()) {
|
|
5603
|
-
const split = (v) => {
|
|
5604
|
-
const list = v.split(",").map((s) => s.trim()).filter(Boolean);
|
|
5605
|
-
return list.length === 1 ? list[0] : list;
|
|
5606
|
-
};
|
|
5607
|
-
const map = {};
|
|
5608
|
-
for (const id of SUPPORTED_CHAIN_IDS) {
|
|
5609
|
-
const v = env[`BLAZEPHOENIX_RPC_${CHAINS[id].key}`] ?? env[`BLAZEPHOENIX_RPC_${id}`];
|
|
5610
|
-
if (v && v.trim()) map[String(id)] = split(v);
|
|
5611
|
-
}
|
|
5612
|
-
const single = env.BLAZEPHOENIX_RPC_URL;
|
|
5613
|
-
if (Object.keys(map).length > 0) {
|
|
5614
|
-
if (single && single.trim()) {
|
|
5615
|
-
throw new BlazeError(
|
|
5616
|
-
"bad_request",
|
|
5617
|
-
"set either BLAZEPHOENIX_RPC_URL (one node) or the per-chain BLAZEPHOENIX_RPC_<CHAIN> variables, not both"
|
|
5618
|
-
);
|
|
5619
|
-
}
|
|
5620
|
-
return map;
|
|
5621
|
-
}
|
|
5622
|
-
return single && single.trim() ? split(single) : void 0;
|
|
5623
|
-
}
|
|
5624
|
-
function globalEnv() {
|
|
5625
|
-
const p = globalThis.process;
|
|
5626
|
-
return p?.env ?? {};
|
|
5627
|
-
}
|
|
5628
5643
|
|
|
5629
5644
|
// src/client.ts
|
|
5630
5645
|
var HEX_ADDR2 = /^0x[0-9a-fA-F]{40}$/;
|
|
@@ -5700,6 +5715,8 @@ var BlazePhoenix = class {
|
|
|
5700
5715
|
checks.push({ name: `code:${k}`, ok: !!code && code !== "0x", detail: code && code !== "0x" ? `${(code.length - 2) / 2} bytes` : "no code at address" });
|
|
5701
5716
|
});
|
|
5702
5717
|
if (featuresOf(dep.version).introspection) {
|
|
5718
|
+
if (isZero(c.hub)) checks.push({ name: "hub", ok: false, detail: "zero address" });
|
|
5719
|
+
if (isZero(c.solver)) checks.push({ name: "solver", ok: false, detail: "zero address" });
|
|
5703
5720
|
const eq = (a, b) => a.toLowerCase() === b.toLowerCase();
|
|
5704
5721
|
const read = async (fn) => {
|
|
5705
5722
|
try {
|
|
@@ -5910,7 +5927,7 @@ var BlazePhoenix = class {
|
|
|
5910
5927
|
async quoteBatch(reqs) {
|
|
5911
5928
|
const fail = (e) => ({
|
|
5912
5929
|
ok: false,
|
|
5913
|
-
error: { code: e instanceof BlazeError ? e.code : "error", message: e?.message ?? String(e) }
|
|
5930
|
+
error: { code: e instanceof BlazeError ? e.code : "error", message: scrubUrls(e?.message ?? String(e)) }
|
|
5914
5931
|
});
|
|
5915
5932
|
const out = new Array(reqs.length);
|
|
5916
5933
|
const groups = /* @__PURE__ */ new Map();
|
|
@@ -6201,11 +6218,16 @@ var BlazePhoenix = class {
|
|
|
6201
6218
|
const staking = CHAINS[chainId].staking;
|
|
6202
6219
|
if (!staking) throw new BlazeError("not_deployed", `no BlazePhoenix staking engine on ${CHAINS[chainId].name}`);
|
|
6203
6220
|
const client = await this.rpc.client(chainId);
|
|
6204
|
-
|
|
6205
|
-
|
|
6206
|
-
client.
|
|
6207
|
-
|
|
6208
|
-
|
|
6221
|
+
let blockNumber, r, isSolvent;
|
|
6222
|
+
try {
|
|
6223
|
+
blockNumber = await client.getBlockNumber();
|
|
6224
|
+
[r, isSolvent] = await Promise.all([
|
|
6225
|
+
client.readContract({ address: staking, abi: STAKING_SOLVENCY_ABI, functionName: "solvency", blockNumber }),
|
|
6226
|
+
client.readContract({ address: staking, abi: STAKING_SOLVENCY_ABI, functionName: "isSolvent", blockNumber })
|
|
6227
|
+
]);
|
|
6228
|
+
} catch (e) {
|
|
6229
|
+
throw new BlazeError("rpc_error", `solvency read failed on your RPC: ${scrubUrls(String(e?.message ?? e))}`, { cause: e });
|
|
6230
|
+
}
|
|
6209
6231
|
const s = r;
|
|
6210
6232
|
return {
|
|
6211
6233
|
chainId,
|