@symmio/trading-core 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.
|
@@ -45,16 +45,23 @@ export interface CreateConfigParameters {
|
|
|
45
45
|
* SDK's built-in defaults. Each entry may override that chain's `addresses`,
|
|
46
46
|
* `subgraphs`, `solver`, `priceService`, `notifications`, and `muon` endpoints.
|
|
47
47
|
*
|
|
48
|
-
* **Required.** Every supported chain must supply
|
|
48
|
+
* **Required.** Every supported chain must supply an
|
|
49
49
|
* `addresses.affiliatesAddress` — your frontend's on-chain **affiliate**
|
|
50
50
|
* (your identity in SYMMIO on that chain), attached to every quote
|
|
51
51
|
* (`sendQuoteWithAffiliateAndData`) so the protocol knows who sourced the trade
|
|
52
52
|
* and routes your share of the trading fee to you. Affiliate addresses are per
|
|
53
53
|
* chain: a registration on one chain is not valid on another. `createConfig`
|
|
54
|
-
* throws `AFFILIATE_ADDRESS_REQUIRED` for any supported chain missing it, so
|
|
55
|
-
* trade can never silently fall back to the built-in default affiliate and lose
|
|
54
|
+
* throws `AFFILIATE_ADDRESS_REQUIRED` for any supported chain **missing** it, so
|
|
55
|
+
* a trade can never silently fall back to the built-in default affiliate and lose
|
|
56
56
|
* attribution.
|
|
57
57
|
*
|
|
58
|
+
* The zero address is accepted here (the SDK only checks presence) — treat it
|
|
59
|
+
* as a **testing placeholder**. On-chain it is a **no-affiliate sentinel**: the
|
|
60
|
+
* trade still opens, you just receive **no share of the trading fee** (nothing
|
|
61
|
+
* is attributed to you). What reverts on-chain is a **non-zero _unregistered_**
|
|
62
|
+
* affiliate — that fails with `PartyAFacet: Invalid affiliate` at trade time. Use
|
|
63
|
+
* a **registered** affiliate to earn your fee share.
|
|
64
|
+
*
|
|
58
65
|
* @example
|
|
59
66
|
* ```ts
|
|
60
67
|
* symmioConfig: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"create-config.d.ts","sourceRoot":"","sources":["../../../src/core/config/create-config.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"create-config.d.ts","sourceRoot":"","sources":["../../../src/core/config/create-config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,MAAM,CAAC;AAEvD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,+BAA+B,CAAC;AACjE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,8BAA8B,CAAC;AACzE,OAAO,EAAuB,KAAK,iBAAiB,EAAE,KAAK,uBAAuB,EAAE,MAAM,WAAW,CAAC;AAGtG,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAElD;;;;;;;;;;GAUG;AACH,MAAM,MAAM,sBAAsB,GAAG,IAAI,CAAC,WAAW,CAAC,iBAAiB,CAAC,EAAE,WAAW,CAAC,GAAG;IACvF,SAAS,EAAE,WAAW,CAAC,uBAAuB,CAAC,GAAG,IAAI,CAAC,uBAAuB,EAAE,mBAAmB,CAAC,CAAC;CACtG,CAAC;AAEF,YAAY,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAElD,gFAAgF;AAChF,MAAM,MAAM,WAAW,GAAG,CAAC,UAAU,CAAC,EAAE;IAAE,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,KAAK,YAAY,CAAC;AAE9E;;;;;;;;;GASG;AACH,MAAM,MAAM,iBAAiB,GAAG,CAAC,UAAU,EAAE;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,OAAO,CAAA;CAAE,KAAK,OAAO,CAAC,kBAAkB,CAAC,CAAC;AAEjH;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA+BG;IACH,YAAY,EAAE,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,sBAAsB,CAAC,CAAC,CAAC;IAC9D;;;;OAIG;IACH,SAAS,EAAE,WAAW,CAAC;IACvB;;;;;;;OAOG;IACH,eAAe,CAAC,EAAE,iBAAiB,CAAC;IACpC;;;OAGG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB;;;;;OAKG;IACH,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B;;;;;OAKG;IACH,oBAAoB,CAAC,EAAE,oBAAoB,CAAC;CAC7C;AAED;;;GAGG;AACH,MAAM,WAAW,MAAM;IACrB,2EAA2E;IAC3E,QAAQ,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC;IACnC,0DAA0D;IAC1D,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC;;;;OAIG;IACH,QAAQ,CAAC,mBAAmB,EAAE,OAAO,CAAC;IACtC;;;OAGG;IACH,cAAc,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,iBAAiB,CAAC;IACpD;;;;;;;;;;OAUG;IACH,iBAAiB,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC5C,4DAA4D;IAC5D,SAAS,CAAC,UAAU,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,YAAY,CAAC;IAC3D;;;;;;;;OAQG;IACH,eAAe,CAAC,UAAU,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAAC;IAChG;;;;;;;OAOG;IACH,uBAAuB,IAAI,oBAAoB,CAAC;CACjD;AAED;;;GAGG;AACH,MAAM,WAAW,eAAe;IAC9B,uDAAuD;IACvD,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,YAAY,CAAC,UAAU,EAAE,sBAAsB,GAAG,MAAM,CAqFvE"}
|
|
@@ -2,50 +2,46 @@ import { SymmError as e } from "../../shared/errors/symm-error.js";
|
|
|
2
2
|
import { listSupportedChains as t } from "../chains/actions/list-supported-chains.js";
|
|
3
3
|
import { hashChainConfig as n } from "./config-key.js";
|
|
4
4
|
import { buildChainConfigs as r } from "./merge-chain-config.js";
|
|
5
|
-
import { zeroAddress as i } from "viem";
|
|
6
5
|
//#region src/core/config/create-config.ts
|
|
7
|
-
function
|
|
8
|
-
let { getClient:
|
|
9
|
-
for (let n of t()) {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
}
|
|
13
|
-
let
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
for (let e of p) h[e] = n(f[e]);
|
|
17
|
-
function g(t) {
|
|
18
|
-
let n = t ?? m, r = f[n];
|
|
6
|
+
function i(i) {
|
|
7
|
+
let { getClient: a, getWalletClient: o, symmioConfig: s, defaultChainId: c, simulateBeforeWrite: l = !0, webSocketConstructor: u } = i;
|
|
8
|
+
for (let n of t()) if (!s?.[n]?.addresses?.affiliatesAddress) throw new e("config", "AFFILIATE_ADDRESS_REQUIRED", `createConfig: \`symmioConfig[${n}].addresses.affiliatesAddress\` is required. Affiliate addresses are per chain — set a *registered* affiliate for every supported chain to earn your fee share. The zero address is accepted as a no-affiliate sentinel (trades open, but no fee is attributed); a non-zero unregistered address reverts on-chain at trade time with "PartyAFacet: Invalid affiliate".`);
|
|
9
|
+
let d = r(s), f = Object.keys(d).map(Number);
|
|
10
|
+
if (f.length === 0) throw new e("config", "NO_CHAINS_CONFIGURED", "createConfig: no supported chains are configured.");
|
|
11
|
+
let p = c ?? f[0], m = {};
|
|
12
|
+
for (let e of f) m[e] = n(d[e]);
|
|
13
|
+
function h(t) {
|
|
14
|
+
let n = t ?? p, r = d[n];
|
|
19
15
|
if (!r) throw new e("config", "UNSUPPORTED_CHAIN", `Unsupported chain id: ${n}.`);
|
|
20
16
|
return r;
|
|
21
17
|
}
|
|
22
|
-
function
|
|
23
|
-
return
|
|
18
|
+
function g(e) {
|
|
19
|
+
return m[e ?? p] ?? "unsupported";
|
|
24
20
|
}
|
|
25
21
|
return {
|
|
26
|
-
chains:
|
|
27
|
-
simulateBeforeWrite:
|
|
28
|
-
defaultChainId:
|
|
29
|
-
getChainConfig:
|
|
30
|
-
getChainConfigKey:
|
|
22
|
+
chains: f,
|
|
23
|
+
simulateBeforeWrite: l,
|
|
24
|
+
defaultChainId: p,
|
|
25
|
+
getChainConfig: h,
|
|
26
|
+
getChainConfigKey: g,
|
|
31
27
|
getClient(e) {
|
|
32
|
-
return
|
|
28
|
+
return a({ chainId: e?.chainId ?? p });
|
|
33
29
|
},
|
|
34
30
|
async getWalletClient(t) {
|
|
35
|
-
if (!
|
|
36
|
-
return
|
|
37
|
-
chainId: t?.chainId ??
|
|
31
|
+
if (!o) throw new e("config", "NO_WALLET_CLIENT", "createConfig: no `getWalletClient` resolver was provided; write/sign actions are unavailable.");
|
|
32
|
+
return o({
|
|
33
|
+
chainId: t?.chainId ?? p,
|
|
38
34
|
from: t?.from
|
|
39
35
|
});
|
|
40
36
|
},
|
|
41
37
|
getWebSocketConstructor() {
|
|
42
|
-
let t =
|
|
38
|
+
let t = u ?? globalThis.WebSocket;
|
|
43
39
|
if (!t) throw new e("config", "NO_WEBSOCKET", "No WebSocket implementation available. Pass `webSocketConstructor` to createConfig (e.g. the `ws` package in Node).");
|
|
44
40
|
return t;
|
|
45
41
|
}
|
|
46
42
|
};
|
|
47
43
|
}
|
|
48
44
|
//#endregion
|
|
49
|
-
export {
|
|
45
|
+
export { i as createConfig };
|
|
50
46
|
|
|
51
47
|
//# sourceMappingURL=create-config.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"create-config.js","names":[],"sources":["../../../src/core/config/create-config.ts"],"sourcesContent":["import { zeroAddress, type Address, type PublicClient } from \"viem\";\nimport { SymmError } from \"../../shared/errors/symm-error\";\nimport type { DeepPartial } from \"../../shared/types/properties\";\nimport type { WebSocketConstructor } from \"../../shared/types/websocket\";\nimport { listSupportedChains, type SymmioChainConfig, type SymmioContractAddresses } from \"../chains\";\nimport { hashChainConfig } from \"./config-key\";\nimport { buildChainConfigs } from \"./merge-chain-config\";\nimport type { SymmioWalletClient } from \"./types\";\n\n/**\n * Per-chain SYMMIO configuration input for {@link createConfig}, deep-merged onto\n * that chain's built-in defaults.\n *\n * Every field is optional to override **except** `addresses.affiliatesAddress` —\n * your frontend's on-chain affiliate for that chain (your identity in SYMMIO),\n * attached to every quote so the protocol attributes the trade to you and routes\n * your fee share. It is mandatory in the type because affiliate addresses are per\n * chain (a registration on one chain is not valid on another) and a missing one\n * would silently fall back to the built-in default affiliate, losing attribution.\n */\nexport type SymmioChainConfigInput = Omit<DeepPartial<SymmioChainConfig>, \"addresses\"> & {\n addresses: DeepPartial<SymmioContractAddresses> & Pick<SymmioContractAddresses, \"affiliatesAddress\">;\n};\n\nexport type { SymmioWalletClient } from \"./types\";\n\n/** Resolve a viem `PublicClient` for reads, optionally for a specific chain. */\nexport type GetClientFn = (parameters?: { chainId?: number }) => PublicClient;\n\n/**\n * Returns the wallet client the SDK should sign/write with.\n *\n * The SDK does not pick between multiple wallets. The consumer's resolver\n * receives the optional `from` (passed by the action) and is responsible for\n * returning the right wallet client — e.g. session-key when `from` matches the\n * session key, wagmi-connected wallet otherwise. The resolver is called fresh\n * per action so account switches in the connected wallet propagate without\n * recreating the config.\n */\nexport type GetWalletClientFn = (parameters: { chainId: number; from?: Address }) => Promise<SymmioWalletClient>;\n\n/**\n * Parameters for {@link createConfig}.\n */\nexport interface CreateConfigParameters {\n /**\n * Per-chain SYMMIO configuration, keyed by chain id — deep-merged onto the\n * SDK's built-in defaults. Each entry may override that chain's `addresses`,\n * `subgraphs`, `solver`, `priceService`, `notifications`, and `muon` endpoints.\n *\n * **Required.** Every supported chain must supply a non-zero\n * `addresses.affiliatesAddress` — your frontend's on-chain **affiliate**\n * (your identity in SYMMIO on that chain), attached to every quote\n * (`sendQuoteWithAffiliateAndData`) so the protocol knows who sourced the trade\n * and routes your share of the trading fee to you. Affiliate addresses are per\n * chain: a registration on one chain is not valid on another. `createConfig`\n * throws `AFFILIATE_ADDRESS_REQUIRED` for any supported chain missing it, so a\n * trade can never silently fall back to the built-in default affiliate and lose\n * attribution.\n *\n * @example\n * ```ts\n * symmioConfig: {\n * [SymmioSupportedChainId.HYPER_EVM]: {\n * addresses: { affiliatesAddress: \"0xYourHyperEvmAffiliate…\" },\n * // optional: subgraphs, solver, priceService, notifications, muon\n * },\n * }\n * ```\n */\n symmioConfig: Partial<Record<number, SymmioChainConfigInput>>;\n /**\n * Returns the viem `PublicClient` used for read actions. Framework layers\n * inject this — e.g. `@symmio/trading-react` bridges it to wagmi's\n * `getPublicClient`. In a plain Node script, return your own viem client.\n */\n getClient: GetClientFn;\n /**\n * Returns the bound viem `WalletClient` to sign/write with. Receives the\n * optional `from` from the action — when the consumer has multiple potential\n * signers (e.g. session-key + connected wallet), this resolver picks. The\n * SDK does no address matching itself; passing `from` is just a hint.\n *\n * Optional — read-only configs may omit it; write/sign actions then throw.\n */\n getWalletClient?: GetWalletClientFn;\n /**\n * Chain used when an action or query omits `chainId`. Defaults to the first\n * built-in supported chain.\n */\n defaultChainId?: number;\n /**\n * Dry-run every write with `simulateContract` before sending it, aborting (and\n * throwing the decoded revert) if the transaction would fail. Defaults to\n * `true`. Override for a single call with the write's `simulateBeforeWrite`\n * option; set `false` here to disable the pre-flight for all writes.\n */\n simulateBeforeWrite?: boolean;\n /**\n * WebSocket implementation used by streaming actions (e.g. `watchNotifications`).\n * Defaults to `globalThis.WebSocket` — set in browsers and Node 22+. Pass an\n * implementation explicitly to run streams in environments without a global\n * (e.g. the `ws` package in older Node, or a mock in tests).\n */\n webSocketConstructor?: WebSocketConstructor;\n}\n\n/**\n * The immutable SDK config every action and query factory receives as its first\n * argument. Holds the per-chain registry and the viem-client resolvers.\n */\nexport interface Config {\n /** Chain ids the config knows about (built-in defaults plus overrides). */\n readonly chains: readonly number[];\n /** Chain used when an action or query omits `chainId`. */\n readonly defaultChainId: number;\n /**\n * Default for the pre-send dry-run on writes. When `true` (the default), a\n * write runs `simulateContract` and aborts if it would revert, unless the call\n * passes `simulateBeforeWrite: false`.\n */\n readonly simulateBeforeWrite: boolean;\n /**\n * Resolve the fully-merged config for a chain.\n * @throws {SymmError} when the chain is not supported.\n */\n getChainConfig(chainId?: number): SymmioChainConfig;\n /**\n * Stable fingerprint of a chain's fully-resolved config (addresses, solver,\n * subgraphs). Identical for identical config across reloads and SSR; changes\n * iff that chain's resolved config changes.\n *\n * The query option factories fold this into every query key, so a runtime\n * override produces a fresh key — TanStack refetches with the new config\n * instead of serving stale cache. Returns a stable sentinel for chains the\n * config does not know about (it never throws, so it is safe to call while\n * building query options for an unsupported chain).\n */\n getChainConfigKey(chainId?: number): string;\n /** Resolve the viem `PublicClient` for reads on a chain. */\n getClient(parameters?: { chainId?: number }): PublicClient;\n /**\n * Resolve the wallet client for writes / off-chain signs.\n *\n * Forwards `chainId` (defaulting to `defaultChainId`) and the optional\n * `from` to the consumer's `getWalletClient` resolver. The resolver decides\n * which wallet to return; the SDK does not perform address matching.\n *\n * @throws {SymmError} when the config was created without `getWalletClient`.\n */\n getWalletClient(parameters?: { chainId?: number; from?: Address }): Promise<SymmioWalletClient>;\n /**\n * Resolve the WebSocket implementation streaming actions open connections\n * with. Returns the injected `webSocketConstructor`, falling back to\n * `globalThis.WebSocket`.\n *\n * @throws {SymmError} when neither an injected constructor nor a global\n * `WebSocket` is available.\n */\n getWebSocketConstructor(): WebSocketConstructor;\n}\n\n/**\n * Optional `config` override mixin for hook/action parameters. When omitted, the\n * config is read from context (in the react layer) or must be passed explicitly.\n */\nexport interface ConfigParameter {\n /** Use this config instead of the one from context. */\n config?: Config;\n}\n\n/**\n * Create an SDK {@link Config}.\n *\n * @example\n * ```ts\n * import { createConfig } from \"@symmio/trading-core\";\n * import { createPublicClient, createWalletClient, http } from \"viem\";\n * import { hyperEvm } from \"viem/chains\";\n *\n * const publicClient = createPublicClient({ chain: hyperEvm, transport: http() });\n * const walletClient = createWalletClient({ account, chain: hyperEvm, transport: http() });\n *\n * const config = createConfig({\n * symmioConfig: { [SymmioSupportedChainId.HYPER_EVM]: { addresses: { affiliatesAddress: \"0xYourHyperEvmAffiliate…\" } } },\n * getClient: () => publicClient,\n * getWalletClient: async () => walletClient,\n * });\n * ```\n */\nexport function createConfig(parameters: CreateConfigParameters): Config {\n const {\n getClient,\n getWalletClient,\n symmioConfig,\n defaultChainId,\n simulateBeforeWrite = true,\n webSocketConstructor,\n } = parameters;\n\n // Affiliate is mandatory per chain: every supported chain's `symmioConfig`\n // entry must set a non-zero `addresses.affiliatesAddress`, or a trade would\n // silently fall back to the built-in default affiliate and lose attribution.\n // Check the raw input (not the merged config, whose default would mask a gap).\n for (const chainId of listSupportedChains()) {\n const affiliate = symmioConfig?.[chainId]?.addresses?.affiliatesAddress;\n if (!affiliate || affiliate === zeroAddress)\n throw new SymmError(\n \"config\",\n \"AFFILIATE_ADDRESS_REQUIRED\",\n `createConfig: \\`symmioConfig[${chainId}].addresses.affiliatesAddress\\` is required and must be non-zero. Affiliate addresses are per chain — set your registered affiliate for every supported chain so trades are attributed to you and earn your fee share.`,\n );\n }\n\n const chainConfigs = buildChainConfigs(symmioConfig);\n\n const chainIds = Object.keys(chainConfigs).map(Number);\n if (chainIds.length === 0)\n throw new SymmError(\"config\", \"NO_CHAINS_CONFIGURED\", \"createConfig: no supported chains are configured.\");\n const resolvedDefaultChainId = defaultChainId ?? chainIds[0]!;\n\n /** Per-chain config fingerprints, precomputed once from the resolved registry. */\n const chainConfigKeys: Record<number, string> = {};\n for (const id of chainIds) chainConfigKeys[id] = hashChainConfig(chainConfigs[id]!);\n\n function getChainConfig(chainId?: number): SymmioChainConfig {\n const id = chainId ?? resolvedDefaultChainId;\n const config = chainConfigs[id];\n\n if (!config) throw new SymmError(\"config\", \"UNSUPPORTED_CHAIN\", `Unsupported chain id: ${id}.`);\n return config;\n }\n\n function getChainConfigKey(chainId?: number): string {\n const id = chainId ?? resolvedDefaultChainId;\n return chainConfigKeys[id] ?? \"unsupported\";\n }\n\n return {\n chains: chainIds,\n simulateBeforeWrite,\n defaultChainId: resolvedDefaultChainId,\n getChainConfig,\n getChainConfigKey,\n getClient(clientParameters) {\n return getClient({ chainId: clientParameters?.chainId ?? resolvedDefaultChainId });\n },\n async getWalletClient(clientParameters) {\n if (!getWalletClient) {\n throw new SymmError(\n \"config\",\n \"NO_WALLET_CLIENT\",\n \"createConfig: no `getWalletClient` resolver was provided; write/sign actions are unavailable.\",\n );\n }\n return getWalletClient({\n chainId: clientParameters?.chainId ?? resolvedDefaultChainId,\n from: clientParameters?.from,\n });\n },\n getWebSocketConstructor() {\n const ctor = webSocketConstructor ?? (globalThis as { WebSocket?: WebSocketConstructor }).WebSocket;\n if (!ctor)\n throw new SymmError(\n \"config\",\n \"NO_WEBSOCKET\",\n \"No WebSocket implementation available. Pass `webSocketConstructor` to createConfig (e.g. the `ws` package in Node).\",\n );\n return ctor;\n },\n };\n}\n"],"mappings":";;;;;;AA8LA,SAAgB,EAAa,GAA4C;CACvE,IAAM,EACJ,cACA,oBACA,iBACA,mBACA,yBAAsB,IACtB,4BACE;CAMJ,KAAK,IAAM,KAAW,EAAoB,GAAG;EAC3C,IAAM,IAAY,IAAe,IAAU,WAAW;EACtD,IAAI,CAAC,KAAa,MAAc,GAC9B,MAAM,IAAI,EACR,UACA,8BACA,gCAAgC,EAAQ,uNAC1C;CACJ;CAEA,IAAM,IAAe,EAAkB,CAAY,GAE7C,IAAW,OAAO,KAAK,CAAY,EAAE,IAAI,MAAM;CACrD,IAAI,EAAS,WAAW,GACtB,MAAM,IAAI,EAAU,UAAU,wBAAwB,mDAAmD;CAC3G,IAAM,IAAyB,KAAkB,EAAS,IAGpD,IAA0C,CAAC;CACjD,KAAK,IAAM,KAAM,GAAU,EAAgB,KAAM,EAAgB,EAAa,EAAI;CAElF,SAAS,EAAe,GAAqC;EAC3D,IAAM,IAAK,KAAW,GAChB,IAAS,EAAa;EAE5B,IAAI,CAAC,GAAQ,MAAM,IAAI,EAAU,UAAU,qBAAqB,yBAAyB,EAAG,EAAE;EAC9F,OAAO;CACT;CAEA,SAAS,EAAkB,GAA0B;EAEnD,OAAO,EADI,KAAW,MACQ;CAChC;CAEA,OAAO;EACL,QAAQ;EACR;EACA,gBAAgB;EAChB;EACA;EACA,UAAU,GAAkB;GAC1B,OAAO,EAAU,EAAE,SAAS,GAAkB,WAAW,EAAuB,CAAC;EACnF;EACA,MAAM,gBAAgB,GAAkB;GACtC,IAAI,CAAC,GACH,MAAM,IAAI,EACR,UACA,oBACA,+FACF;GAEF,OAAO,EAAgB;IACrB,SAAS,GAAkB,WAAW;IACtC,MAAM,GAAkB;GAC1B,CAAC;EACH;EACA,0BAA0B;GACxB,IAAM,IAAO,KAAyB,WAAoD;GAC1F,IAAI,CAAC,GACH,MAAM,IAAI,EACR,UACA,gBACA,qHACF;GACF,OAAO;EACT;CACF;AACF"}
|
|
1
|
+
{"version":3,"file":"create-config.js","names":[],"sources":["../../../src/core/config/create-config.ts"],"sourcesContent":["import { type Address, type PublicClient } from \"viem\";\nimport { SymmError } from \"../../shared/errors/symm-error\";\nimport type { DeepPartial } from \"../../shared/types/properties\";\nimport type { WebSocketConstructor } from \"../../shared/types/websocket\";\nimport { listSupportedChains, type SymmioChainConfig, type SymmioContractAddresses } from \"../chains\";\nimport { hashChainConfig } from \"./config-key\";\nimport { buildChainConfigs } from \"./merge-chain-config\";\nimport type { SymmioWalletClient } from \"./types\";\n\n/**\n * Per-chain SYMMIO configuration input for {@link createConfig}, deep-merged onto\n * that chain's built-in defaults.\n *\n * Every field is optional to override **except** `addresses.affiliatesAddress` —\n * your frontend's on-chain affiliate for that chain (your identity in SYMMIO),\n * attached to every quote so the protocol attributes the trade to you and routes\n * your fee share. It is mandatory in the type because affiliate addresses are per\n * chain (a registration on one chain is not valid on another) and a missing one\n * would silently fall back to the built-in default affiliate, losing attribution.\n */\nexport type SymmioChainConfigInput = Omit<DeepPartial<SymmioChainConfig>, \"addresses\"> & {\n addresses: DeepPartial<SymmioContractAddresses> & Pick<SymmioContractAddresses, \"affiliatesAddress\">;\n};\n\nexport type { SymmioWalletClient } from \"./types\";\n\n/** Resolve a viem `PublicClient` for reads, optionally for a specific chain. */\nexport type GetClientFn = (parameters?: { chainId?: number }) => PublicClient;\n\n/**\n * Returns the wallet client the SDK should sign/write with.\n *\n * The SDK does not pick between multiple wallets. The consumer's resolver\n * receives the optional `from` (passed by the action) and is responsible for\n * returning the right wallet client — e.g. session-key when `from` matches the\n * session key, wagmi-connected wallet otherwise. The resolver is called fresh\n * per action so account switches in the connected wallet propagate without\n * recreating the config.\n */\nexport type GetWalletClientFn = (parameters: { chainId: number; from?: Address }) => Promise<SymmioWalletClient>;\n\n/**\n * Parameters for {@link createConfig}.\n */\nexport interface CreateConfigParameters {\n /**\n * Per-chain SYMMIO configuration, keyed by chain id — deep-merged onto the\n * SDK's built-in defaults. Each entry may override that chain's `addresses`,\n * `subgraphs`, `solver`, `priceService`, `notifications`, and `muon` endpoints.\n *\n * **Required.** Every supported chain must supply an\n * `addresses.affiliatesAddress` — your frontend's on-chain **affiliate**\n * (your identity in SYMMIO on that chain), attached to every quote\n * (`sendQuoteWithAffiliateAndData`) so the protocol knows who sourced the trade\n * and routes your share of the trading fee to you. Affiliate addresses are per\n * chain: a registration on one chain is not valid on another. `createConfig`\n * throws `AFFILIATE_ADDRESS_REQUIRED` for any supported chain **missing** it, so\n * a trade can never silently fall back to the built-in default affiliate and lose\n * attribution.\n *\n * The zero address is accepted here (the SDK only checks presence) — treat it\n * as a **testing placeholder**. On-chain it is a **no-affiliate sentinel**: the\n * trade still opens, you just receive **no share of the trading fee** (nothing\n * is attributed to you). What reverts on-chain is a **non-zero _unregistered_**\n * affiliate — that fails with `PartyAFacet: Invalid affiliate` at trade time. Use\n * a **registered** affiliate to earn your fee share.\n *\n * @example\n * ```ts\n * symmioConfig: {\n * [SymmioSupportedChainId.HYPER_EVM]: {\n * addresses: { affiliatesAddress: \"0xYourHyperEvmAffiliate…\" },\n * // optional: subgraphs, solver, priceService, notifications, muon\n * },\n * }\n * ```\n */\n symmioConfig: Partial<Record<number, SymmioChainConfigInput>>;\n /**\n * Returns the viem `PublicClient` used for read actions. Framework layers\n * inject this — e.g. `@symmio/trading-react` bridges it to wagmi's\n * `getPublicClient`. In a plain Node script, return your own viem client.\n */\n getClient: GetClientFn;\n /**\n * Returns the bound viem `WalletClient` to sign/write with. Receives the\n * optional `from` from the action — when the consumer has multiple potential\n * signers (e.g. session-key + connected wallet), this resolver picks. The\n * SDK does no address matching itself; passing `from` is just a hint.\n *\n * Optional — read-only configs may omit it; write/sign actions then throw.\n */\n getWalletClient?: GetWalletClientFn;\n /**\n * Chain used when an action or query omits `chainId`. Defaults to the first\n * built-in supported chain.\n */\n defaultChainId?: number;\n /**\n * Dry-run every write with `simulateContract` before sending it, aborting (and\n * throwing the decoded revert) if the transaction would fail. Defaults to\n * `true`. Override for a single call with the write's `simulateBeforeWrite`\n * option; set `false` here to disable the pre-flight for all writes.\n */\n simulateBeforeWrite?: boolean;\n /**\n * WebSocket implementation used by streaming actions (e.g. `watchNotifications`).\n * Defaults to `globalThis.WebSocket` — set in browsers and Node 22+. Pass an\n * implementation explicitly to run streams in environments without a global\n * (e.g. the `ws` package in older Node, or a mock in tests).\n */\n webSocketConstructor?: WebSocketConstructor;\n}\n\n/**\n * The immutable SDK config every action and query factory receives as its first\n * argument. Holds the per-chain registry and the viem-client resolvers.\n */\nexport interface Config {\n /** Chain ids the config knows about (built-in defaults plus overrides). */\n readonly chains: readonly number[];\n /** Chain used when an action or query omits `chainId`. */\n readonly defaultChainId: number;\n /**\n * Default for the pre-send dry-run on writes. When `true` (the default), a\n * write runs `simulateContract` and aborts if it would revert, unless the call\n * passes `simulateBeforeWrite: false`.\n */\n readonly simulateBeforeWrite: boolean;\n /**\n * Resolve the fully-merged config for a chain.\n * @throws {SymmError} when the chain is not supported.\n */\n getChainConfig(chainId?: number): SymmioChainConfig;\n /**\n * Stable fingerprint of a chain's fully-resolved config (addresses, solver,\n * subgraphs). Identical for identical config across reloads and SSR; changes\n * iff that chain's resolved config changes.\n *\n * The query option factories fold this into every query key, so a runtime\n * override produces a fresh key — TanStack refetches with the new config\n * instead of serving stale cache. Returns a stable sentinel for chains the\n * config does not know about (it never throws, so it is safe to call while\n * building query options for an unsupported chain).\n */\n getChainConfigKey(chainId?: number): string;\n /** Resolve the viem `PublicClient` for reads on a chain. */\n getClient(parameters?: { chainId?: number }): PublicClient;\n /**\n * Resolve the wallet client for writes / off-chain signs.\n *\n * Forwards `chainId` (defaulting to `defaultChainId`) and the optional\n * `from` to the consumer's `getWalletClient` resolver. The resolver decides\n * which wallet to return; the SDK does not perform address matching.\n *\n * @throws {SymmError} when the config was created without `getWalletClient`.\n */\n getWalletClient(parameters?: { chainId?: number; from?: Address }): Promise<SymmioWalletClient>;\n /**\n * Resolve the WebSocket implementation streaming actions open connections\n * with. Returns the injected `webSocketConstructor`, falling back to\n * `globalThis.WebSocket`.\n *\n * @throws {SymmError} when neither an injected constructor nor a global\n * `WebSocket` is available.\n */\n getWebSocketConstructor(): WebSocketConstructor;\n}\n\n/**\n * Optional `config` override mixin for hook/action parameters. When omitted, the\n * config is read from context (in the react layer) or must be passed explicitly.\n */\nexport interface ConfigParameter {\n /** Use this config instead of the one from context. */\n config?: Config;\n}\n\n/**\n * Create an SDK {@link Config}.\n *\n * @example\n * ```ts\n * import { createConfig } from \"@symmio/trading-core\";\n * import { createPublicClient, createWalletClient, http } from \"viem\";\n * import { hyperEvm } from \"viem/chains\";\n *\n * const publicClient = createPublicClient({ chain: hyperEvm, transport: http() });\n * const walletClient = createWalletClient({ account, chain: hyperEvm, transport: http() });\n *\n * const config = createConfig({\n * symmioConfig: { [SymmioSupportedChainId.HYPER_EVM]: { addresses: { affiliatesAddress: \"0xYourHyperEvmAffiliate…\" } } },\n * getClient: () => publicClient,\n * getWalletClient: async () => walletClient,\n * });\n * ```\n */\nexport function createConfig(parameters: CreateConfigParameters): Config {\n const {\n getClient,\n getWalletClient,\n symmioConfig,\n defaultChainId,\n simulateBeforeWrite = true,\n webSocketConstructor,\n } = parameters;\n\n // Affiliate is mandatory per chain: every supported chain's `symmioConfig`\n // entry must set `addresses.affiliatesAddress`. The value may be the zero\n // address — on-chain that's a no-affiliate sentinel (trades open, no fee share);\n // a non-zero *unregistered* affiliate is what reverts at trade time. So the SDK\n // only enforces that the field is present, not that it is non-zero. The presence\n // check keeps a trade from silently falling back to the built-in default and\n // losing attribution. Check\n // the raw input (not the merged config, whose default would mask a gap).\n for (const chainId of listSupportedChains()) {\n const affiliate = symmioConfig?.[chainId]?.addresses?.affiliatesAddress;\n if (!affiliate)\n throw new SymmError(\n \"config\",\n \"AFFILIATE_ADDRESS_REQUIRED\",\n `createConfig: \\`symmioConfig[${chainId}].addresses.affiliatesAddress\\` is required. Affiliate addresses are per chain — set a *registered* affiliate for every supported chain to earn your fee share. The zero address is accepted as a no-affiliate sentinel (trades open, but no fee is attributed); a non-zero unregistered address reverts on-chain at trade time with \"PartyAFacet: Invalid affiliate\".`,\n );\n }\n\n const chainConfigs = buildChainConfigs(symmioConfig);\n\n const chainIds = Object.keys(chainConfigs).map(Number);\n if (chainIds.length === 0)\n throw new SymmError(\"config\", \"NO_CHAINS_CONFIGURED\", \"createConfig: no supported chains are configured.\");\n const resolvedDefaultChainId = defaultChainId ?? chainIds[0]!;\n\n /** Per-chain config fingerprints, precomputed once from the resolved registry. */\n const chainConfigKeys: Record<number, string> = {};\n for (const id of chainIds) chainConfigKeys[id] = hashChainConfig(chainConfigs[id]!);\n\n function getChainConfig(chainId?: number): SymmioChainConfig {\n const id = chainId ?? resolvedDefaultChainId;\n const config = chainConfigs[id];\n\n if (!config) throw new SymmError(\"config\", \"UNSUPPORTED_CHAIN\", `Unsupported chain id: ${id}.`);\n return config;\n }\n\n function getChainConfigKey(chainId?: number): string {\n const id = chainId ?? resolvedDefaultChainId;\n return chainConfigKeys[id] ?? \"unsupported\";\n }\n\n return {\n chains: chainIds,\n simulateBeforeWrite,\n defaultChainId: resolvedDefaultChainId,\n getChainConfig,\n getChainConfigKey,\n getClient(clientParameters) {\n return getClient({ chainId: clientParameters?.chainId ?? resolvedDefaultChainId });\n },\n async getWalletClient(clientParameters) {\n if (!getWalletClient) {\n throw new SymmError(\n \"config\",\n \"NO_WALLET_CLIENT\",\n \"createConfig: no `getWalletClient` resolver was provided; write/sign actions are unavailable.\",\n );\n }\n return getWalletClient({\n chainId: clientParameters?.chainId ?? resolvedDefaultChainId,\n from: clientParameters?.from,\n });\n },\n getWebSocketConstructor() {\n const ctor = webSocketConstructor ?? (globalThis as { WebSocket?: WebSocketConstructor }).WebSocket;\n if (!ctor)\n throw new SymmError(\n \"config\",\n \"NO_WEBSOCKET\",\n \"No WebSocket implementation available. Pass `webSocketConstructor` to createConfig (e.g. the `ws` package in Node).\",\n );\n return ctor;\n },\n };\n}\n"],"mappings":";;;;;AAqMA,SAAgB,EAAa,GAA4C;CACvE,IAAM,EACJ,cACA,oBACA,iBACA,mBACA,yBAAsB,IACtB,4BACE;CAUJ,KAAK,IAAM,KAAW,EAAoB,GAExC,IAAI,CADc,IAAe,IAAU,WAAW,mBAEpD,MAAM,IAAI,EACR,UACA,8BACA,gCAAgC,EAAQ,uWAC1C;CAGJ,IAAM,IAAe,EAAkB,CAAY,GAE7C,IAAW,OAAO,KAAK,CAAY,EAAE,IAAI,MAAM;CACrD,IAAI,EAAS,WAAW,GACtB,MAAM,IAAI,EAAU,UAAU,wBAAwB,mDAAmD;CAC3G,IAAM,IAAyB,KAAkB,EAAS,IAGpD,IAA0C,CAAC;CACjD,KAAK,IAAM,KAAM,GAAU,EAAgB,KAAM,EAAgB,EAAa,EAAI;CAElF,SAAS,EAAe,GAAqC;EAC3D,IAAM,IAAK,KAAW,GAChB,IAAS,EAAa;EAE5B,IAAI,CAAC,GAAQ,MAAM,IAAI,EAAU,UAAU,qBAAqB,yBAAyB,EAAG,EAAE;EAC9F,OAAO;CACT;CAEA,SAAS,EAAkB,GAA0B;EAEnD,OAAO,EADI,KAAW,MACQ;CAChC;CAEA,OAAO;EACL,QAAQ;EACR;EACA,gBAAgB;EAChB;EACA;EACA,UAAU,GAAkB;GAC1B,OAAO,EAAU,EAAE,SAAS,GAAkB,WAAW,EAAuB,CAAC;EACnF;EACA,MAAM,gBAAgB,GAAkB;GACtC,IAAI,CAAC,GACH,MAAM,IAAI,EACR,UACA,oBACA,+FACF;GAEF,OAAO,EAAgB;IACrB,SAAS,GAAkB,WAAW;IACtC,MAAM,GAAkB;GAC1B,CAAC;EACH;EACA,0BAA0B;GACxB,IAAM,IAAO,KAAyB,WAAoD;GAC1F,IAAI,CAAC,GACH,MAAM,IAAI,EACR,UACA,gBACA,qHACF;GACF,OAAO;EACT;CACF;AACF"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@symmio/trading-core",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.1",
|
|
4
4
|
"description": "Framework-agnostic SYMMIO SDK. Contract calls, calculations, and transformations with no framework assumptions.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"homepage": "https://github.com/SYMM-IO/Trading-SDK/tree/main/packages/trading-core#readme",
|