damm-sdk 1.4.21 → 1.4.23
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/dist/index.cjs +25103 -31382
- package/dist/index.cjs.map +81 -120
- package/dist/index.js +25725 -31298
- package/dist/index.js.map +101 -129
- package/dist/integrations/ccip/ccip.router.d.ts.map +1 -1
- package/dist/integrations/enso/enso.d.ts +75 -0
- package/dist/integrations/enso/enso.d.ts.map +1 -0
- package/dist/integrations/enso/enso.route.api.d.ts +67 -0
- package/dist/integrations/enso/enso.route.api.d.ts.map +1 -0
- package/dist/integrations/enso/enso.router.abi.d.ts +68 -0
- package/dist/integrations/enso/enso.router.abi.d.ts.map +1 -0
- package/dist/integrations/enso/index.d.ts +4 -0
- package/dist/integrations/enso/index.d.ts.map +1 -0
- package/dist/integrations/index.d.ts +1 -0
- package/dist/integrations/index.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/integrations/ccip/ccip.router.ts +1 -0
- package/src/integrations/enso/enso.route.api.ts +127 -0
- package/src/integrations/enso/enso.router.abi.ts +48 -0
- package/src/integrations/enso/enso.ts +172 -0
- package/src/integrations/enso/index.ts +3 -0
- package/src/integrations/index.ts +1 -0
- package/src/lib/contractsRegistry.json +13 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ccip.router.d.ts","sourceRoot":"","sources":["../../../src/integrations/ccip/ccip.router.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,IAAI,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAE/D,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAIpC;;;;GAIG;AACH,eAAO,MAAM,oBAAoB,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,
|
|
1
|
+
{"version":3,"file":"ccip.router.d.ts","sourceRoot":"","sources":["../../../src/integrations/ccip/ccip.router.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,IAAI,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAE/D,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAIpC;;;;GAIG;AACH,eAAO,MAAM,oBAAoB,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAShE,CAAC;AAEH;;;GAGG;AACH,eAAO,MAAM,oBAAoB,YAAa,MAAM,KAAG,MAMtD,CAAC;AAIF,MAAM,MAAM,eAAe,GAAG,QAAQ,CAAC;IACnC,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;CAClB,CAAC,CAAC;AAEH,MAAM,MAAM,cAAc,GAAG,QAAQ,CAAC;IAClC,qCAAqC;IACrC,QAAQ,EAAE,SAAS,CAAC;IACpB,0CAA0C;IAC1C,IAAI,EAAE,SAAS,CAAC;IAChB,uBAAuB;IACvB,YAAY,EAAE,SAAS,eAAe,EAAE,CAAC;IACzC,6CAA6C;IAC7C,QAAQ,EAAE,OAAO,CAAC;IAClB,mCAAmC;IACnC,SAAS,EAAE,SAAS,CAAC;CACxB,CAAC,CAAC;AAIH,MAAM,MAAM,UAAU,GAAG,QAAQ,CAAC;IAC9B,wBAAwB,EAAE,MAAM,CAAC;IACjC,OAAO,EAAE,cAAc,CAAC;CAC3B,CAAC,CAAC;AAEH;;;GAGG;AACH,eAAO,MAAM,kBAAkB,SAAU,UAAU,KAAG,SAcrD,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,aAAa;mBAIP,OAAO;UAChB,UAAU;MAChB,WAAW,IAAI,CAOlB,CAAC;AAIF,MAAM,MAAM,YAAY,GAAG,QAAQ,CAAC;IAChC,wBAAwB,EAAE,MAAM,CAAC;IACjC,OAAO,EAAE,cAAc,CAAC;IACxB,mEAAmE;IACnE,SAAS,EAAE,MAAM,CAAC;CACrB,CAAC,CAAC;AAEH;;GAEG;AACH,eAAO,MAAM,gBAAgB,SAAU,YAAY,KAAG,SAcrD,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,WAAW;mBAIL,OAAO;UAChB,YAAY;MAClB,WAAW,IAAI,CAOlB,CAAC;AAIF;;;GAGG;AACH,eAAO,MAAM,gBAAgB;cAKf,OAAO;WACV,OAAO;YACN,MAAM;MACd,cAWH,CAAC"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Enso RouterV2 transaction builders.
|
|
3
|
+
*
|
|
4
|
+
* Enso's `/v1/shortcuts/route` API only returns `routeSingle(Token tokenOut,
|
|
5
|
+
* bytes data)` calldata. Our Zodiac Roles scopes only permit the stricter
|
|
6
|
+
* 4-arg `safeRouteSingle(Token tokenIn, Token tokenOut, address receiver,
|
|
7
|
+
* bytes data)`, which validates tokenIn consumption and an explicit receiver.
|
|
8
|
+
*
|
|
9
|
+
* The shortcut `bundle` payload is identical between the two entry points —
|
|
10
|
+
* safeRouteSingle just layers additional validation on top — so we fetch the
|
|
11
|
+
* route once, extract the bundle, and re-encode as safeRouteSingle.
|
|
12
|
+
*
|
|
13
|
+
* Workflow:
|
|
14
|
+
* ensoSafeRouteSingleTrx({ api args, routerAddress })
|
|
15
|
+
* → fetchEnsoRoute(...) (HTTP)
|
|
16
|
+
* → rewrapRouteSingleAsSafeRouteSingle(...) (pure)
|
|
17
|
+
* → createCall({ to: routerAddress, data, … }) (Unwrapable<Call>)
|
|
18
|
+
*/
|
|
19
|
+
import { type Address } from "viem";
|
|
20
|
+
import type { Call, HexString, Unwrapable } from "../../types";
|
|
21
|
+
import { type EnsoRouteArgs } from "./enso.route.api.ts";
|
|
22
|
+
export declare enum EnsoTokenType {
|
|
23
|
+
Native = 0,
|
|
24
|
+
ERC20 = 1
|
|
25
|
+
}
|
|
26
|
+
export type EnsoToken = Readonly<{
|
|
27
|
+
tokenType: EnsoTokenType;
|
|
28
|
+
data: HexString;
|
|
29
|
+
}>;
|
|
30
|
+
/**
|
|
31
|
+
* Encode a token as Enso's `Token` struct:
|
|
32
|
+
* - ERC20: (tokenType=1, abi.encode(address, uint256))
|
|
33
|
+
* - Native: (tokenType=0, abi.encode(uint256))
|
|
34
|
+
*/
|
|
35
|
+
export declare const encodeEnsoToken: (token: Address, amount: bigint) => EnsoToken;
|
|
36
|
+
export declare class UnexpectedEnsoSelectorError extends Error {
|
|
37
|
+
readonly selector: string;
|
|
38
|
+
constructor(selector: string);
|
|
39
|
+
}
|
|
40
|
+
export type RewrapArgs = Readonly<{
|
|
41
|
+
routeSingleCalldata: HexString;
|
|
42
|
+
tokenIn: Address;
|
|
43
|
+
amountIn: bigint;
|
|
44
|
+
receiver: Address;
|
|
45
|
+
}>;
|
|
46
|
+
/**
|
|
47
|
+
* Decode `routeSingle(tokenOut, bundle)` calldata, then re-encode as
|
|
48
|
+
* `safeRouteSingle(tokenIn, tokenOut, receiver, bundle)` using the same
|
|
49
|
+
* bundle payload. The bundle is byte-identical; only the wrapper changes.
|
|
50
|
+
*
|
|
51
|
+
* Throws `UnexpectedEnsoSelectorError` if the input doesn't start with the
|
|
52
|
+
* routeSingle selector — a fail-fast guard in case Enso's API ever switches
|
|
53
|
+
* output format.
|
|
54
|
+
*/
|
|
55
|
+
export declare const rewrapRouteSingleAsSafeRouteSingle: (args: RewrapArgs) => HexString;
|
|
56
|
+
export declare class EnsoUnexpectedRouterError extends Error {
|
|
57
|
+
readonly got: Address;
|
|
58
|
+
readonly expected: Address;
|
|
59
|
+
constructor(got: Address, expected: Address);
|
|
60
|
+
}
|
|
61
|
+
export type EnsoSafeRouteSingleTrxArgs = EnsoRouteArgs & Readonly<{
|
|
62
|
+
/** Address of the Enso RouterV2 on the target chain. Must match the scope in Zodiac Roles. */
|
|
63
|
+
routerAddress: Address;
|
|
64
|
+
}>;
|
|
65
|
+
/**
|
|
66
|
+
* Fetch an Enso route and return a `safeRouteSingle` call ready to be added
|
|
67
|
+
* to a MultisendBuilder.
|
|
68
|
+
*
|
|
69
|
+
* Aborts (throws) if Enso's API returns a tx targeting any address other than
|
|
70
|
+
* the provided RouterV2 — this protects against the API silently switching to
|
|
71
|
+
* EnsoWallet or EnsoShortcutsDelegate, neither of which our Zodiac scope
|
|
72
|
+
* permits.
|
|
73
|
+
*/
|
|
74
|
+
export declare const ensoSafeRouteSingleTrx: (args: EnsoSafeRouteSingleTrxArgs) => Promise<Unwrapable<Call>>;
|
|
75
|
+
//# sourceMappingURL=enso.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"enso.d.ts","sourceRoot":"","sources":["../../../src/integrations/enso/enso.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,EAA+D,KAAK,OAAO,EAAE,MAAM,MAAM,CAAC;AACjG,OAAO,KAAK,EAAE,IAAI,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAG/D,OAAO,EAAkB,KAAK,aAAa,EAA0B,MAAM,qBAAqB,CAAC;AAIjG,oBAAY,aAAa;IACrB,MAAM,IAAI;IACV,KAAK,IAAI;CACZ;AAED,MAAM,MAAM,SAAS,GAAG,QAAQ,CAAC;IAC7B,SAAS,EAAE,aAAa,CAAC;IACzB,IAAI,EAAE,SAAS,CAAC;CACnB,CAAC,CAAC;AAMH;;;;GAIG;AACH,eAAO,MAAM,eAAe,UAAW,OAAO,UAAU,MAAM,KAAG,SAWhE,CAAC;AAMF,qBAAa,2BAA4B,SAAQ,KAAK;IAClD,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;gBACd,QAAQ,EAAE,MAAM;CAQ/B;AAED,MAAM,MAAM,UAAU,GAAG,QAAQ,CAAC;IAC9B,mBAAmB,EAAE,SAAS,CAAC;IAC/B,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,OAAO,CAAC;CACrB,CAAC,CAAC;AAEH;;;;;;;;GAQG;AACH,eAAO,MAAM,kCAAkC,SAAU,UAAU,KAAG,SAyBrE,CAAC;AAIF,qBAAa,yBAA0B,SAAQ,KAAK;IAChD,QAAQ,CAAC,GAAG,EAAE,OAAO,CAAC;IACtB,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;gBACf,GAAG,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO;CAS9C;AAED,MAAM,MAAM,0BAA0B,GAAG,aAAa,GAClD,QAAQ,CAAC;IACL,8FAA8F;IAC9F,aAAa,EAAE,OAAO,CAAC;CAC1B,CAAC,CAAC;AAEP;;;;;;;;GAQG;AACH,eAAO,MAAM,sBAAsB,SAAgB,0BAA0B,KAAG,QAAQ,WAAW,IAAI,CAAC,CAsBvG,CAAC"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Enso Shortcuts API client.
|
|
3
|
+
*
|
|
4
|
+
* Fetches a swap route from Enso's public `/v1/shortcuts/route` endpoint and
|
|
5
|
+
* returns the raw `tx.data` (which is always `routeSingle` calldata — see
|
|
6
|
+
* `enso.ts` for the rewrap into `safeRouteSingle`).
|
|
7
|
+
*
|
|
8
|
+
* API reference: https://docs.enso.build/pages/api-reference/shortcuts/route
|
|
9
|
+
*/
|
|
10
|
+
import type { Address } from "viem";
|
|
11
|
+
import type { HexString } from "../../types";
|
|
12
|
+
export declare const ENSO_API_BASE: "https://api.enso.finance";
|
|
13
|
+
/**
|
|
14
|
+
* Raw response shape from the Enso route endpoint. We only model the fields
|
|
15
|
+
* we use; Enso returns many more (amountOut, priceImpact, route, …) that are
|
|
16
|
+
* intentionally ignored.
|
|
17
|
+
*/
|
|
18
|
+
export type EnsoRouteResponse = Readonly<{
|
|
19
|
+
tx: Readonly<{
|
|
20
|
+
to: HexString;
|
|
21
|
+
data: HexString;
|
|
22
|
+
value: string;
|
|
23
|
+
}>;
|
|
24
|
+
}>;
|
|
25
|
+
export type EnsoRouteArgs = Readonly<{
|
|
26
|
+
chainId: number;
|
|
27
|
+
/** Caller address — also used as `receiver` by default. */
|
|
28
|
+
fromAddress: Address;
|
|
29
|
+
/** Destination for the swap output. Typically equal to `fromAddress` (the Safe). */
|
|
30
|
+
receiver: Address;
|
|
31
|
+
tokenIn: Address;
|
|
32
|
+
tokenOut: Address;
|
|
33
|
+
/** Decimal string, no decimals adjustment — matches token units. */
|
|
34
|
+
amountIn: string;
|
|
35
|
+
/**
|
|
36
|
+
* Slippage in integer basis points (e.g. 20 = 0.2%, 300 = 3%).
|
|
37
|
+
*
|
|
38
|
+
* Enso's `slippage` param is a number string in bips. Passing a decimal
|
|
39
|
+
* like `0.2` triggers a 400 Bad Request ("slippage must be a number
|
|
40
|
+
* string").
|
|
41
|
+
*/
|
|
42
|
+
slippageBips: number;
|
|
43
|
+
/** Optional Enso API key for 10 rps; no key = 1 rps global limit. */
|
|
44
|
+
apiKey?: string;
|
|
45
|
+
/** Override the API base URL (useful for tests). */
|
|
46
|
+
apiBase?: string;
|
|
47
|
+
}>;
|
|
48
|
+
export declare class EnsoRouteApiError extends Error {
|
|
49
|
+
readonly status: number;
|
|
50
|
+
readonly statusText: string;
|
|
51
|
+
readonly tokenIn: Address;
|
|
52
|
+
readonly tokenOut: Address;
|
|
53
|
+
constructor({ status, statusText, tokenIn, tokenOut, }: {
|
|
54
|
+
status: number;
|
|
55
|
+
statusText: string;
|
|
56
|
+
tokenIn: Address;
|
|
57
|
+
tokenOut: Address;
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Fetch a shortcut route from Enso. Always returns `routeSingle` calldata —
|
|
62
|
+
* use `rewrapRouteSingleAsSafeRouteSingle` in `enso.ts` to convert to
|
|
63
|
+
* `safeRouteSingle` before submitting on-chain if your Safe's Zodiac scope
|
|
64
|
+
* only permits safeRouteSingle.
|
|
65
|
+
*/
|
|
66
|
+
export declare const fetchEnsoRoute: (args: EnsoRouteArgs) => Promise<EnsoRouteResponse>;
|
|
67
|
+
//# sourceMappingURL=enso.route.api.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"enso.route.api.d.ts","sourceRoot":"","sources":["../../../src/integrations/enso/enso.route.api.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AACpC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAE7C,eAAO,MAAM,aAAa,4BAAsC,CAAC;AAEjE;;;;GAIG;AACH,MAAM,MAAM,iBAAiB,GAAG,QAAQ,CAAC;IACrC,EAAE,EAAE,QAAQ,CAAC;QACT,EAAE,EAAE,SAAS,CAAC;QACd,IAAI,EAAE,SAAS,CAAC;QAChB,KAAK,EAAE,MAAM,CAAC;KACjB,CAAC,CAAC;CACN,CAAC,CAAC;AAEH,MAAM,MAAM,aAAa,GAAG,QAAQ,CAAC;IACjC,OAAO,EAAE,MAAM,CAAC;IAChB,2DAA2D;IAC3D,WAAW,EAAE,OAAO,CAAC;IACrB,oFAAoF;IACpF,QAAQ,EAAE,OAAO,CAAC;IAClB,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,OAAO,CAAC;IAClB,oEAAoE;IACpE,QAAQ,EAAE,MAAM,CAAC;IACjB;;;;;;OAMG;IACH,YAAY,EAAE,MAAM,CAAC;IACrB,qEAAqE;IACrE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,oDAAoD;IACpD,OAAO,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC,CAAC;AAEH,qBAAa,iBAAkB,SAAQ,KAAK;IACxC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;gBAEf,EACR,MAAM,EACN,UAAU,EACV,OAAO,EACP,QAAQ,GACX,EAAE;QACC,MAAM,EAAE,MAAM,CAAC;QACf,UAAU,EAAE,MAAM,CAAC;QACnB,OAAO,EAAE,OAAO,CAAC;QACjB,QAAQ,EAAE,OAAO,CAAC;KACrB;CAQJ;AAED;;;;;GAKG;AACH,eAAO,MAAM,cAAc,SAAgB,aAAa,KAAG,QAAQ,iBAAiB,CA0CnF,CAAC"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Enso RouterV2 — minimal ABI covering the entry points we use:
|
|
3
|
+
*
|
|
4
|
+
* routeSingle(Token tokenOut, bytes data)
|
|
5
|
+
* safeRouteSingle(Token tokenIn, Token tokenOut, address receiver, bytes data)
|
|
6
|
+
*
|
|
7
|
+
* `Token` is Enso's internal struct `{ uint8 tokenType, bytes data }` where:
|
|
8
|
+
* - tokenType = 0 (Native): data = abi.encode(uint256 amount)
|
|
9
|
+
* - tokenType = 1 (ERC20): data = abi.encode(address token, uint256 amount)
|
|
10
|
+
*
|
|
11
|
+
* We intentionally expose only these two selectors — we never call the Enso
|
|
12
|
+
* router with routeMulti / safeRouteMulti / delegate variants from any DAMM
|
|
13
|
+
* context, and shipping their ABIs here would just invite unaudited usage.
|
|
14
|
+
*/
|
|
15
|
+
declare const _default: readonly [{
|
|
16
|
+
readonly name: "routeSingle";
|
|
17
|
+
readonly type: "function";
|
|
18
|
+
readonly stateMutability: "payable";
|
|
19
|
+
readonly inputs: readonly [{
|
|
20
|
+
readonly name: "tokenOut";
|
|
21
|
+
readonly type: "tuple";
|
|
22
|
+
readonly components: readonly [{
|
|
23
|
+
readonly name: "tokenType";
|
|
24
|
+
readonly type: "uint8";
|
|
25
|
+
}, {
|
|
26
|
+
readonly name: "data";
|
|
27
|
+
readonly type: "bytes";
|
|
28
|
+
}];
|
|
29
|
+
}, {
|
|
30
|
+
readonly name: "data";
|
|
31
|
+
readonly type: "bytes";
|
|
32
|
+
}];
|
|
33
|
+
readonly outputs: readonly [];
|
|
34
|
+
}, {
|
|
35
|
+
readonly name: "safeRouteSingle";
|
|
36
|
+
readonly type: "function";
|
|
37
|
+
readonly stateMutability: "payable";
|
|
38
|
+
readonly inputs: readonly [{
|
|
39
|
+
readonly name: "tokenIn";
|
|
40
|
+
readonly type: "tuple";
|
|
41
|
+
readonly components: readonly [{
|
|
42
|
+
readonly name: "tokenType";
|
|
43
|
+
readonly type: "uint8";
|
|
44
|
+
}, {
|
|
45
|
+
readonly name: "data";
|
|
46
|
+
readonly type: "bytes";
|
|
47
|
+
}];
|
|
48
|
+
}, {
|
|
49
|
+
readonly name: "tokenOut";
|
|
50
|
+
readonly type: "tuple";
|
|
51
|
+
readonly components: readonly [{
|
|
52
|
+
readonly name: "tokenType";
|
|
53
|
+
readonly type: "uint8";
|
|
54
|
+
}, {
|
|
55
|
+
readonly name: "data";
|
|
56
|
+
readonly type: "bytes";
|
|
57
|
+
}];
|
|
58
|
+
}, {
|
|
59
|
+
readonly name: "receiver";
|
|
60
|
+
readonly type: "address";
|
|
61
|
+
}, {
|
|
62
|
+
readonly name: "data";
|
|
63
|
+
readonly type: "bytes";
|
|
64
|
+
}];
|
|
65
|
+
readonly outputs: readonly [];
|
|
66
|
+
}];
|
|
67
|
+
export default _default;
|
|
68
|
+
//# sourceMappingURL=enso.router.abi.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"enso.router.abi.d.ts","sourceRoot":"","sources":["../../../src/integrations/enso/enso.router.abi.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAWH,wBAuBW"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/integrations/enso/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAC7D,cAAc,QAAQ,CAAC;AACvB,cAAc,kBAAkB,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/integrations/index.ts"],"names":[],"mappings":"AAAA,cAAc,UAAU,CAAC;AACzB,cAAc,UAAU,CAAC;AACzB,cAAc,aAAa,CAAC;AAC5B,cAAc,aAAa,CAAC;AAC5B,cAAc,OAAO,CAAC;AACtB,cAAc,UAAU,CAAC;AACzB,cAAc,WAAW,CAAC;AAC1B,cAAc,YAAY,CAAC;AAC3B,cAAc,YAAY,CAAC;AAC3B,cAAc,cAAc,CAAC;AAC7B,cAAc,SAAS,CAAC;AACxB,cAAc,cAAc,CAAC;AAC7B,cAAc,eAAe,CAAC;AAC9B,cAAc,SAAS,CAAC;AACxB,cAAc,OAAO,CAAC;AACtB,cAAc,QAAQ,CAAC;AACvB,cAAc,QAAQ,CAAC;AACvB,cAAc,UAAU,CAAC;AACzB,cAAc,cAAc,CAAC;AAC7B,cAAc,aAAa,CAAC;AAC5B,cAAc,SAAS,CAAC;AACxB,cAAc,WAAW,CAAC;AAC1B,cAAc,aAAa,CAAC;AAC5B,cAAc,QAAQ,CAAC;AACvB,cAAc,UAAU,CAAC;AACzB,cAAc,YAAY,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/integrations/index.ts"],"names":[],"mappings":"AAAA,cAAc,UAAU,CAAC;AACzB,cAAc,UAAU,CAAC;AACzB,cAAc,aAAa,CAAC;AAC5B,cAAc,aAAa,CAAC;AAC5B,cAAc,OAAO,CAAC;AACtB,cAAc,UAAU,CAAC;AACzB,cAAc,WAAW,CAAC;AAC1B,cAAc,YAAY,CAAC;AAC3B,cAAc,YAAY,CAAC;AAC3B,cAAc,cAAc,CAAC;AAC7B,cAAc,SAAS,CAAC;AACxB,cAAc,cAAc,CAAC;AAC7B,cAAc,eAAe,CAAC;AAC9B,cAAc,SAAS,CAAC;AACxB,cAAc,OAAO,CAAC;AACtB,cAAc,QAAQ,CAAC;AACvB,cAAc,QAAQ,CAAC;AACvB,cAAc,UAAU,CAAC;AACzB,cAAc,cAAc,CAAC;AAC7B,cAAc,aAAa,CAAC;AAC5B,cAAc,SAAS,CAAC;AACxB,cAAc,WAAW,CAAC;AAC1B,cAAc,aAAa,CAAC;AAC5B,cAAc,QAAQ,CAAC;AACvB,cAAc,UAAU,CAAC;AACzB,cAAc,YAAY,CAAC;AAC3B,cAAc,QAAQ,CAAC"}
|
package/package.json
CHANGED
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Enso Shortcuts API client.
|
|
3
|
+
*
|
|
4
|
+
* Fetches a swap route from Enso's public `/v1/shortcuts/route` endpoint and
|
|
5
|
+
* returns the raw `tx.data` (which is always `routeSingle` calldata — see
|
|
6
|
+
* `enso.ts` for the rewrap into `safeRouteSingle`).
|
|
7
|
+
*
|
|
8
|
+
* API reference: https://docs.enso.build/pages/api-reference/shortcuts/route
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import type { Address } from "viem";
|
|
12
|
+
import type { HexString } from "../../types";
|
|
13
|
+
|
|
14
|
+
export const ENSO_API_BASE = "https://api.enso.finance" as const;
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Raw response shape from the Enso route endpoint. We only model the fields
|
|
18
|
+
* we use; Enso returns many more (amountOut, priceImpact, route, …) that are
|
|
19
|
+
* intentionally ignored.
|
|
20
|
+
*/
|
|
21
|
+
export type EnsoRouteResponse = Readonly<{
|
|
22
|
+
tx: Readonly<{
|
|
23
|
+
to: HexString;
|
|
24
|
+
data: HexString;
|
|
25
|
+
value: string;
|
|
26
|
+
}>;
|
|
27
|
+
}>;
|
|
28
|
+
|
|
29
|
+
export type EnsoRouteArgs = Readonly<{
|
|
30
|
+
chainId: number;
|
|
31
|
+
/** Caller address — also used as `receiver` by default. */
|
|
32
|
+
fromAddress: Address;
|
|
33
|
+
/** Destination for the swap output. Typically equal to `fromAddress` (the Safe). */
|
|
34
|
+
receiver: Address;
|
|
35
|
+
tokenIn: Address;
|
|
36
|
+
tokenOut: Address;
|
|
37
|
+
/** Decimal string, no decimals adjustment — matches token units. */
|
|
38
|
+
amountIn: string;
|
|
39
|
+
/**
|
|
40
|
+
* Slippage in integer basis points (e.g. 20 = 0.2%, 300 = 3%).
|
|
41
|
+
*
|
|
42
|
+
* Enso's `slippage` param is a number string in bips. Passing a decimal
|
|
43
|
+
* like `0.2` triggers a 400 Bad Request ("slippage must be a number
|
|
44
|
+
* string").
|
|
45
|
+
*/
|
|
46
|
+
slippageBips: number;
|
|
47
|
+
/** Optional Enso API key for 10 rps; no key = 1 rps global limit. */
|
|
48
|
+
apiKey?: string;
|
|
49
|
+
/** Override the API base URL (useful for tests). */
|
|
50
|
+
apiBase?: string;
|
|
51
|
+
}>;
|
|
52
|
+
|
|
53
|
+
export class EnsoRouteApiError extends Error {
|
|
54
|
+
readonly status: number;
|
|
55
|
+
readonly statusText: string;
|
|
56
|
+
readonly tokenIn: Address;
|
|
57
|
+
readonly tokenOut: Address;
|
|
58
|
+
|
|
59
|
+
constructor({
|
|
60
|
+
status,
|
|
61
|
+
statusText,
|
|
62
|
+
tokenIn,
|
|
63
|
+
tokenOut,
|
|
64
|
+
}: {
|
|
65
|
+
status: number;
|
|
66
|
+
statusText: string;
|
|
67
|
+
tokenIn: Address;
|
|
68
|
+
tokenOut: Address;
|
|
69
|
+
}) {
|
|
70
|
+
super(`Enso route API request failed with status ${status} (${statusText}) for swap ${tokenIn} -> ${tokenOut}`);
|
|
71
|
+
this.name = "EnsoRouteApiError";
|
|
72
|
+
this.status = status;
|
|
73
|
+
this.statusText = statusText;
|
|
74
|
+
this.tokenIn = tokenIn;
|
|
75
|
+
this.tokenOut = tokenOut;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Fetch a shortcut route from Enso. Always returns `routeSingle` calldata —
|
|
81
|
+
* use `rewrapRouteSingleAsSafeRouteSingle` in `enso.ts` to convert to
|
|
82
|
+
* `safeRouteSingle` before submitting on-chain if your Safe's Zodiac scope
|
|
83
|
+
* only permits safeRouteSingle.
|
|
84
|
+
*/
|
|
85
|
+
export const fetchEnsoRoute = async (args: EnsoRouteArgs): Promise<EnsoRouteResponse> => {
|
|
86
|
+
const {
|
|
87
|
+
chainId,
|
|
88
|
+
fromAddress,
|
|
89
|
+
receiver,
|
|
90
|
+
tokenIn,
|
|
91
|
+
tokenOut,
|
|
92
|
+
amountIn,
|
|
93
|
+
slippageBips,
|
|
94
|
+
apiKey,
|
|
95
|
+
apiBase = ENSO_API_BASE,
|
|
96
|
+
} = args;
|
|
97
|
+
|
|
98
|
+
const params = new URLSearchParams({
|
|
99
|
+
chainId: String(chainId),
|
|
100
|
+
fromAddress,
|
|
101
|
+
receiver,
|
|
102
|
+
tokenIn,
|
|
103
|
+
tokenOut,
|
|
104
|
+
amountIn,
|
|
105
|
+
slippage: String(slippageBips),
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
const headers: Record<string, string> = { Accept: "application/json" };
|
|
109
|
+
if (apiKey) {
|
|
110
|
+
headers["Authorization"] = `Bearer ${apiKey}`;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const response = await fetch(`${apiBase}/api/v1/shortcuts/route?${params.toString()}`, {
|
|
114
|
+
headers,
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
if (!response.ok) {
|
|
118
|
+
throw new EnsoRouteApiError({
|
|
119
|
+
status: response.status,
|
|
120
|
+
statusText: response.statusText,
|
|
121
|
+
tokenIn,
|
|
122
|
+
tokenOut,
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
return (await response.json()) as EnsoRouteResponse;
|
|
127
|
+
};
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Enso RouterV2 — minimal ABI covering the entry points we use:
|
|
3
|
+
*
|
|
4
|
+
* routeSingle(Token tokenOut, bytes data)
|
|
5
|
+
* safeRouteSingle(Token tokenIn, Token tokenOut, address receiver, bytes data)
|
|
6
|
+
*
|
|
7
|
+
* `Token` is Enso's internal struct `{ uint8 tokenType, bytes data }` where:
|
|
8
|
+
* - tokenType = 0 (Native): data = abi.encode(uint256 amount)
|
|
9
|
+
* - tokenType = 1 (ERC20): data = abi.encode(address token, uint256 amount)
|
|
10
|
+
*
|
|
11
|
+
* We intentionally expose only these two selectors — we never call the Enso
|
|
12
|
+
* router with routeMulti / safeRouteMulti / delegate variants from any DAMM
|
|
13
|
+
* context, and shipping their ABIs here would just invite unaudited usage.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
const tokenTuple = {
|
|
17
|
+
name: "token",
|
|
18
|
+
type: "tuple",
|
|
19
|
+
components: [
|
|
20
|
+
{ name: "tokenType", type: "uint8" },
|
|
21
|
+
{ name: "data", type: "bytes" },
|
|
22
|
+
],
|
|
23
|
+
} as const;
|
|
24
|
+
|
|
25
|
+
export default [
|
|
26
|
+
{
|
|
27
|
+
name: "routeSingle",
|
|
28
|
+
type: "function",
|
|
29
|
+
stateMutability: "payable",
|
|
30
|
+
inputs: [
|
|
31
|
+
{ ...tokenTuple, name: "tokenOut" },
|
|
32
|
+
{ name: "data", type: "bytes" },
|
|
33
|
+
],
|
|
34
|
+
outputs: [],
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
name: "safeRouteSingle",
|
|
38
|
+
type: "function",
|
|
39
|
+
stateMutability: "payable",
|
|
40
|
+
inputs: [
|
|
41
|
+
{ ...tokenTuple, name: "tokenIn" },
|
|
42
|
+
{ ...tokenTuple, name: "tokenOut" },
|
|
43
|
+
{ name: "receiver", type: "address" },
|
|
44
|
+
{ name: "data", type: "bytes" },
|
|
45
|
+
],
|
|
46
|
+
outputs: [],
|
|
47
|
+
},
|
|
48
|
+
] as const;
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Enso RouterV2 transaction builders.
|
|
3
|
+
*
|
|
4
|
+
* Enso's `/v1/shortcuts/route` API only returns `routeSingle(Token tokenOut,
|
|
5
|
+
* bytes data)` calldata. Our Zodiac Roles scopes only permit the stricter
|
|
6
|
+
* 4-arg `safeRouteSingle(Token tokenIn, Token tokenOut, address receiver,
|
|
7
|
+
* bytes data)`, which validates tokenIn consumption and an explicit receiver.
|
|
8
|
+
*
|
|
9
|
+
* The shortcut `bundle` payload is identical between the two entry points —
|
|
10
|
+
* safeRouteSingle just layers additional validation on top — so we fetch the
|
|
11
|
+
* route once, extract the bundle, and re-encode as safeRouteSingle.
|
|
12
|
+
*
|
|
13
|
+
* Workflow:
|
|
14
|
+
* ensoSafeRouteSingleTrx({ api args, routerAddress })
|
|
15
|
+
* → fetchEnsoRoute(...) (HTTP)
|
|
16
|
+
* → rewrapRouteSingleAsSafeRouteSingle(...) (pure)
|
|
17
|
+
* → createCall({ to: routerAddress, data, … }) (Unwrapable<Call>)
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
import { decodeFunctionData, encodeAbiParameters, encodeFunctionData, type Address } from "viem";
|
|
21
|
+
import type { Call, HexString, Unwrapable } from "../../types";
|
|
22
|
+
import { createCall } from "../../types";
|
|
23
|
+
import ensoRouterAbi from "./enso.router.abi.ts";
|
|
24
|
+
import { fetchEnsoRoute, type EnsoRouteArgs, type EnsoRouteResponse } from "./enso.route.api.ts";
|
|
25
|
+
|
|
26
|
+
// --- Token struct --------------------------------------------------------
|
|
27
|
+
|
|
28
|
+
export enum EnsoTokenType {
|
|
29
|
+
Native = 0,
|
|
30
|
+
ERC20 = 1,
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export type EnsoToken = Readonly<{
|
|
34
|
+
tokenType: EnsoTokenType;
|
|
35
|
+
data: HexString;
|
|
36
|
+
}>;
|
|
37
|
+
|
|
38
|
+
const ZERO_ADDRESS: Address = "0x0000000000000000000000000000000000000000";
|
|
39
|
+
|
|
40
|
+
const isNativeToken = (token: Address): boolean => token.toLowerCase() === ZERO_ADDRESS;
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Encode a token as Enso's `Token` struct:
|
|
44
|
+
* - ERC20: (tokenType=1, abi.encode(address, uint256))
|
|
45
|
+
* - Native: (tokenType=0, abi.encode(uint256))
|
|
46
|
+
*/
|
|
47
|
+
export const encodeEnsoToken = (token: Address, amount: bigint): EnsoToken => {
|
|
48
|
+
if (isNativeToken(token)) {
|
|
49
|
+
return {
|
|
50
|
+
tokenType: EnsoTokenType.Native,
|
|
51
|
+
data: encodeAbiParameters([{ type: "uint256" }], [amount]),
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
return {
|
|
55
|
+
tokenType: EnsoTokenType.ERC20,
|
|
56
|
+
data: encodeAbiParameters([{ type: "address" }, { type: "uint256" }], [token, amount]),
|
|
57
|
+
};
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
// --- routeSingle → safeRouteSingle rewrap --------------------------------
|
|
61
|
+
|
|
62
|
+
const ROUTE_SINGLE_SELECTOR = "0xb94c3609" as const;
|
|
63
|
+
|
|
64
|
+
export class UnexpectedEnsoSelectorError extends Error {
|
|
65
|
+
readonly selector: string;
|
|
66
|
+
constructor(selector: string) {
|
|
67
|
+
super(
|
|
68
|
+
`Expected routeSingle selector ${ROUTE_SINGLE_SELECTOR}, got ${selector}. ` +
|
|
69
|
+
`The Enso API may have changed its output format.`,
|
|
70
|
+
);
|
|
71
|
+
this.name = "UnexpectedEnsoSelectorError";
|
|
72
|
+
this.selector = selector;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export type RewrapArgs = Readonly<{
|
|
77
|
+
routeSingleCalldata: HexString;
|
|
78
|
+
tokenIn: Address;
|
|
79
|
+
amountIn: bigint;
|
|
80
|
+
receiver: Address;
|
|
81
|
+
}>;
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Decode `routeSingle(tokenOut, bundle)` calldata, then re-encode as
|
|
85
|
+
* `safeRouteSingle(tokenIn, tokenOut, receiver, bundle)` using the same
|
|
86
|
+
* bundle payload. The bundle is byte-identical; only the wrapper changes.
|
|
87
|
+
*
|
|
88
|
+
* Throws `UnexpectedEnsoSelectorError` if the input doesn't start with the
|
|
89
|
+
* routeSingle selector — a fail-fast guard in case Enso's API ever switches
|
|
90
|
+
* output format.
|
|
91
|
+
*/
|
|
92
|
+
export const rewrapRouteSingleAsSafeRouteSingle = (args: RewrapArgs): HexString => {
|
|
93
|
+
const { routeSingleCalldata, tokenIn, amountIn, receiver } = args;
|
|
94
|
+
|
|
95
|
+
const selector = routeSingleCalldata.slice(0, 10).toLowerCase();
|
|
96
|
+
if (selector !== ROUTE_SINGLE_SELECTOR) {
|
|
97
|
+
throw new UnexpectedEnsoSelectorError(selector);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const decoded = decodeFunctionData({
|
|
101
|
+
abi: ensoRouterAbi,
|
|
102
|
+
data: routeSingleCalldata,
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
if (decoded.functionName !== "routeSingle") {
|
|
106
|
+
throw new UnexpectedEnsoSelectorError(selector);
|
|
107
|
+
}
|
|
108
|
+
const [tokenOutStruct, bundle] = decoded.args as readonly [EnsoToken, HexString];
|
|
109
|
+
|
|
110
|
+
const tokenInStruct = encodeEnsoToken(tokenIn, amountIn);
|
|
111
|
+
|
|
112
|
+
return encodeFunctionData({
|
|
113
|
+
abi: ensoRouterAbi,
|
|
114
|
+
functionName: "safeRouteSingle",
|
|
115
|
+
args: [tokenInStruct, tokenOutStruct, receiver, bundle],
|
|
116
|
+
}) as HexString;
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
// --- High-level helper: fetch route + rewrap + build Call ----------------
|
|
120
|
+
|
|
121
|
+
export class EnsoUnexpectedRouterError extends Error {
|
|
122
|
+
readonly got: Address;
|
|
123
|
+
readonly expected: Address;
|
|
124
|
+
constructor(got: Address, expected: Address) {
|
|
125
|
+
super(
|
|
126
|
+
`Enso API routed to ${got} but we expected RouterV2 ${expected}. ` +
|
|
127
|
+
`Unsupported routing (e.g. EnsoWallet / ShortcutsDelegate) — aborting.`,
|
|
128
|
+
);
|
|
129
|
+
this.name = "EnsoUnexpectedRouterError";
|
|
130
|
+
this.got = got;
|
|
131
|
+
this.expected = expected;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
export type EnsoSafeRouteSingleTrxArgs = EnsoRouteArgs &
|
|
136
|
+
Readonly<{
|
|
137
|
+
/** Address of the Enso RouterV2 on the target chain. Must match the scope in Zodiac Roles. */
|
|
138
|
+
routerAddress: Address;
|
|
139
|
+
}>;
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Fetch an Enso route and return a `safeRouteSingle` call ready to be added
|
|
143
|
+
* to a MultisendBuilder.
|
|
144
|
+
*
|
|
145
|
+
* Aborts (throws) if Enso's API returns a tx targeting any address other than
|
|
146
|
+
* the provided RouterV2 — this protects against the API silently switching to
|
|
147
|
+
* EnsoWallet or EnsoShortcutsDelegate, neither of which our Zodiac scope
|
|
148
|
+
* permits.
|
|
149
|
+
*/
|
|
150
|
+
export const ensoSafeRouteSingleTrx = async (args: EnsoSafeRouteSingleTrxArgs): Promise<Unwrapable<Call>> => {
|
|
151
|
+
const { routerAddress, tokenIn, amountIn, receiver } = args;
|
|
152
|
+
|
|
153
|
+
const route: EnsoRouteResponse = await fetchEnsoRoute(args);
|
|
154
|
+
|
|
155
|
+
if (route.tx.to.toLowerCase() !== routerAddress.toLowerCase()) {
|
|
156
|
+
throw new EnsoUnexpectedRouterError(route.tx.to as Address, routerAddress);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
const safeRouteSingleCalldata = rewrapRouteSingleAsSafeRouteSingle({
|
|
160
|
+
routeSingleCalldata: route.tx.data,
|
|
161
|
+
tokenIn,
|
|
162
|
+
amountIn: BigInt(amountIn),
|
|
163
|
+
receiver,
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
return createCall({
|
|
167
|
+
to: routerAddress,
|
|
168
|
+
data: safeRouteSingleCalldata,
|
|
169
|
+
operation: 0,
|
|
170
|
+
value: BigInt(route.tx.value || "0"),
|
|
171
|
+
});
|
|
172
|
+
};
|
|
@@ -1013,6 +1013,19 @@
|
|
|
1013
1013
|
"safeL2Singleton": "0x29fcB43b46531BcA003ddC8FCB67FFE91900C762",
|
|
1014
1014
|
"proxyFactory": "0x4e1DCf7AD4e460CfD30791CCC4F9c8a4f820ec67"
|
|
1015
1015
|
}
|
|
1016
|
+
},
|
|
1017
|
+
"tokens": {
|
|
1018
|
+
"wsteth": "0x601aC63637933D88285A025C685AC4e9a92a98dA",
|
|
1019
|
+
"usdt0": "0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb"
|
|
1020
|
+
},
|
|
1021
|
+
"aaveV3": {
|
|
1022
|
+
"pool": "0x7e324AbC5De01d112AfC03a584966ff199741C28"
|
|
1023
|
+
},
|
|
1024
|
+
"ccip": {
|
|
1025
|
+
"router": "0xfa546248C54939AA6C48279CdC1EAf9A1125c411"
|
|
1026
|
+
},
|
|
1027
|
+
"OFTAdapters": {
|
|
1028
|
+
"0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb": "0x9151434b16b9763660705744891fa906f660ecc5"
|
|
1016
1029
|
}
|
|
1017
1030
|
}
|
|
1018
1031
|
}
|