@dev.sail.money/sailor 0.0.2-13 → 0.0.2-16

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.
Files changed (33) hide show
  1. package/package.json +1 -1
  2. package/packages/cli/dist/index.cjs +292 -11
  3. package/packages/sdk/dist/intelligence.d.ts +1 -1
  4. package/packages/sdk/dist/intelligence.js +1 -1
  5. package/packages/sdk/dist/templates/ammLiquidity.d.ts +24 -11
  6. package/packages/sdk/dist/templates/ammLiquidity.d.ts.map +1 -1
  7. package/packages/sdk/dist/templates/ammLiquidity.js +39 -31
  8. package/packages/sdk/dist/templates/ammLiquidity.js.map +1 -1
  9. package/packages/sdk/dist/templates/approveAndCallBatch.d.ts +24 -10
  10. package/packages/sdk/dist/templates/approveAndCallBatch.d.ts.map +1 -1
  11. package/packages/sdk/dist/templates/approveAndCallBatch.js +36 -23
  12. package/packages/sdk/dist/templates/approveAndCallBatch.js.map +1 -1
  13. package/packages/sdk/dist/templates/boundedBorrow.d.ts +19 -9
  14. package/packages/sdk/dist/templates/boundedBorrow.d.ts.map +1 -1
  15. package/packages/sdk/dist/templates/boundedBorrow.js +28 -19
  16. package/packages/sdk/dist/templates/boundedBorrow.js.map +1 -1
  17. package/packages/sdk/dist/templates/boundedSwap.d.ts +19 -9
  18. package/packages/sdk/dist/templates/boundedSwap.d.ts.map +1 -1
  19. package/packages/sdk/dist/templates/boundedSwap.js +30 -20
  20. package/packages/sdk/dist/templates/boundedSwap.js.map +1 -1
  21. package/packages/sdk/dist/templates/defiBundle.d.ts +35 -9
  22. package/packages/sdk/dist/templates/defiBundle.d.ts.map +1 -1
  23. package/packages/sdk/dist/templates/defiBundle.js +84 -22
  24. package/packages/sdk/dist/templates/defiBundle.js.map +1 -1
  25. package/packages/sdk/dist/templates/pendle.d.ts +23 -8
  26. package/packages/sdk/dist/templates/pendle.d.ts.map +1 -1
  27. package/packages/sdk/dist/templates/pendle.js +34 -14
  28. package/packages/sdk/dist/templates/pendle.js.map +1 -1
  29. package/packages/sdk/dist/templates/transferTarget.d.ts +11 -3
  30. package/packages/sdk/dist/templates/transferTarget.d.ts.map +1 -1
  31. package/packages/sdk/dist/templates/transferTarget.js +14 -7
  32. package/packages/sdk/dist/templates/transferTarget.js.map +1 -1
  33. package/packages/sdk/package.json +1 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dev.sail.money/sailor",
3
- "version": "0.0.2-13",
3
+ "version": "0.0.2-16",
4
4
  "description": "Operator toolkit for Sail Protocol",
5
5
  "bin": {
6
6
  "sailor": "packages/cli/dist/index.cjs"
@@ -40880,6 +40880,282 @@ Register it later with: sailor mandate attach --address ${deployed} --sma <SMA>`
40880
40880
  attached: options.attach ? { sma: options.sma, txHash: attachTxHash } : null
40881
40881
  });
40882
40882
  }
40883
+ var CLONE_INIT_PREFIX = "0x3d602d80600a3d3981f3363d3d373d3d3d363d73";
40884
+ var CLONE_INIT_SUFFIX = "0x5af43d82803e903d91602b57fd5bf3";
40885
+ var PERMISSION_FACTORY_ABI = [
40886
+ {
40887
+ type: "function",
40888
+ name: "deployAndAttach",
40889
+ stateMutability: "payable",
40890
+ inputs: [
40891
+ { name: "account", type: "address" },
40892
+ { name: "impl", type: "address" },
40893
+ { name: "salt", type: "bytes32" },
40894
+ { name: "initData", type: "bytes" },
40895
+ { name: "kernelDeadline", type: "uint256" },
40896
+ { name: "kernelSig", type: "bytes" }
40897
+ ],
40898
+ outputs: [{ name: "clone", type: "address" }]
40899
+ }
40900
+ ];
40901
+ var CLONE_TEMPLATES = {
40902
+ boundedApprove: {
40903
+ label: "Bounded Approve",
40904
+ buildInitData: (p) => encodeFunctionData({
40905
+ abi: [
40906
+ {
40907
+ type: "function",
40908
+ name: "initialize",
40909
+ stateMutability: "nonpayable",
40910
+ inputs: [
40911
+ { name: "allowedTokens", type: "address[]" },
40912
+ { name: "allowedSpenders", type: "address[]" },
40913
+ { name: "_maxAmountPerTx", type: "uint256" },
40914
+ { name: "_permissionSigner", type: "address" }
40915
+ ],
40916
+ outputs: []
40917
+ }
40918
+ ],
40919
+ functionName: "initialize",
40920
+ args: [p.tokens, p.spenders, p.max, p.permissionSigner]
40921
+ }),
40922
+ describe: (p) => [
40923
+ { label: "Allowed tokens", value: p.tokens.join(", ") },
40924
+ { label: "Allowed spenders", value: p.spenders.join(", ") },
40925
+ {
40926
+ label: "Max approval / tx",
40927
+ value: p.max === maxUint256 ? "unlimited (uint256 max)" : p.max.toString()
40928
+ }
40929
+ ]
40930
+ }
40931
+ };
40932
+ function predictCloneAddress(impl, factory, submitter, salt) {
40933
+ const namespacedSalt = keccak256(
40934
+ encodeAbiParameters([{ type: "address" }, { type: "bytes32" }], [submitter, salt])
40935
+ );
40936
+ const initCode = concatHex([CLONE_INIT_PREFIX, impl, CLONE_INIT_SUFFIX]);
40937
+ return getCreate2Address({
40938
+ from: factory,
40939
+ salt: namespacedSalt,
40940
+ bytecodeHash: keccak256(initCode)
40941
+ });
40942
+ }
40943
+ function parseAddressList(csv, flag) {
40944
+ if (!csv) throw new Error(`${flag} is required (comma-separated address list)`);
40945
+ const list = csv.split(",").map((s) => s.trim()).filter(Boolean);
40946
+ if (list.length === 0) throw new Error(`${flag} is empty`);
40947
+ for (const a of list) {
40948
+ if (!isAddress(a)) throw new Error(`${flag} contains an invalid address: ${a}`);
40949
+ }
40950
+ return list;
40951
+ }
40952
+ async function mandateDeployClone(options) {
40953
+ const project = requireProject();
40954
+ const channel = await createSigningChannel(process.cwd());
40955
+ try {
40956
+ await channel.start();
40957
+ await runDeployClone(project, channel, options);
40958
+ } catch (err) {
40959
+ fail(err, options.json);
40960
+ } finally {
40961
+ channel.stop();
40962
+ }
40963
+ }
40964
+ async function runDeployClone(project, channel, options) {
40965
+ const json = !!options.json;
40966
+ const say = (fn) => {
40967
+ if (!json) fn();
40968
+ };
40969
+ if (!isAddress(options.sma)) throw new Error(`Invalid --sma address: ${options.sma}`);
40970
+ const sma = options.sma;
40971
+ const spec = CLONE_TEMPLATES[options.template];
40972
+ if (!spec) {
40973
+ throw new Error(
40974
+ `Unsupported clone template "${options.template}". Supported: ${Object.keys(CLONE_TEMPLATES).join(", ")}`
40975
+ );
40976
+ }
40977
+ const impl = project.deployment.standaloneTemplates?.[options.template];
40978
+ if (!impl || !isAddress(impl)) {
40979
+ throw new Error(
40980
+ `No "${options.template}" standalone template is bundled for chain ${project.chainId}.`
40981
+ );
40982
+ }
40983
+ const chain2 = getChainById(project.chainId);
40984
+ const publicClient = publicClientFor(project);
40985
+ const agentSigner = await loadManagerSigner2();
40986
+ const registered = await publicClient.readContract({
40987
+ address: project.contracts.kernel,
40988
+ abi: SailKernelAbi,
40989
+ functionName: "registered",
40990
+ args: [sma]
40991
+ });
40992
+ if (!registered) {
40993
+ throw new Error(`SMA ${sma} is not registered with SailKernel; cannot register a permission.`);
40994
+ }
40995
+ const kernelConfig = await publicClient.readContract({
40996
+ address: project.contracts.kernel,
40997
+ abi: SailKernelAbi,
40998
+ functionName: "configs",
40999
+ args: [sma]
41000
+ });
41001
+ const permissionSigner = kernelConfig[0];
41002
+ const initParams = {
41003
+ permissionSigner,
41004
+ tokens: parseAddressList(options.tokens, "--tokens"),
41005
+ spenders: parseAddressList(options.spenders, "--spenders"),
41006
+ max: options.max ? BigInt(options.max) : maxUint256
41007
+ };
41008
+ const initData = spec.buildInitData(initParams);
41009
+ const submitter = agentSigner.address;
41010
+ const salt = keccak256(
41011
+ encodeAbiParameters(
41012
+ [{ type: "address" }, { type: "address" }, { type: "uint256" }],
41013
+ [sma, impl, BigInt(Math.floor(Date.now() / 1e3))]
41014
+ )
41015
+ );
41016
+ const clone = predictCloneAddress(impl, project.contracts.permissionFactory, submitter, salt);
41017
+ say(() => {
41018
+ console.log(`
41019
+ ${spec.label} clone (${options.template})`);
41020
+ console.log(` logic impl: ${impl}`);
41021
+ console.log(` predicted clone: ${clone}`);
41022
+ console.log(` SMA: ${sma}`);
41023
+ for (const d of spec.describe(initParams)) console.log(` ${d.label}: ${d.value}`);
41024
+ console.log(`
41025
+ \u2192 Signing station:
41026
+ Open ${channel.url} and connect your Owner wallet
41027
+ `);
41028
+ });
41029
+ const nonce = await publicClient.readContract({
41030
+ address: project.contracts.kernel,
41031
+ abi: SailKernelAbi,
41032
+ functionName: "signerNonces",
41033
+ args: [sma]
41034
+ });
41035
+ let registerPermissionHasDeadline = false;
41036
+ try {
41037
+ const caps = await detectKernelCapabilities(publicClient, project.contracts.kernel, {
41038
+ chainId: project.chainId
41039
+ });
41040
+ registerPermissionHasDeadline = caps.registerPermissionHasDeadline;
41041
+ } catch {
41042
+ }
41043
+ const deadline = registerPermissionHasDeadline ? BigInt(Math.floor(Date.now() / 1e3) + 300) : void 0;
41044
+ const typedData = buildRegisterPermissionTypedData({
41045
+ chainId: project.chainId,
41046
+ kernel: project.contracts.kernel,
41047
+ account: sma,
41048
+ permission: clone,
41049
+ nonce,
41050
+ hasDeadline: registerPermissionHasDeadline,
41051
+ deadline
41052
+ });
41053
+ const label = options.label ?? `${spec.label} (${options.template})`;
41054
+ say(
41055
+ () => console.log(
41056
+ `Pushing signing request \u2014 the mandate signer (${permissionSigner}) must sign in the browser.`
41057
+ )
41058
+ );
41059
+ const response = await channel.requestSignature({
41060
+ type: "typed-data",
41061
+ kind: "register-permission",
41062
+ title: `Authorize "${label}"`,
41063
+ description: `Sign to authorize a new ${spec.label} permission on your SMA. The agent deploys and registers it in one transaction.`,
41064
+ chainId: project.chainId,
41065
+ details: [
41066
+ { label: "SMA", value: sma },
41067
+ { label: "Permission (predicted)", value: clone },
41068
+ { label: "Template", value: options.template },
41069
+ { label: "Mandate signer", value: permissionSigner },
41070
+ ...spec.describe(initParams)
41071
+ ],
41072
+ typedData
41073
+ });
41074
+ if (response.status === "rejected") {
41075
+ throw new Error(`User rejected authorization: ${response.reason ?? "no reason given"}`);
41076
+ }
41077
+ if (response.status !== "signature") {
41078
+ throw new Error(`Expected EIP-712 signature response, got: ${response.status}`);
41079
+ }
41080
+ const signature = response.signature;
41081
+ try {
41082
+ const recoveredSigner = await recoverTypedDataAddress({
41083
+ domain: sailKernelDomain({ chainId: project.chainId, kernel: project.contracts.kernel }),
41084
+ types: registerPermissionHasDeadline ? REGISTER_PERMISSION_TYPES : REGISTER_PERMISSION_TYPES_NO_DEADLINE,
41085
+ primaryType: "RegisterPermission",
41086
+ message: registerPermissionHasDeadline ? { account: sma, permission: clone, nonce, deadline } : { account: sma, permission: clone, nonce },
41087
+ signature
41088
+ });
41089
+ if (recoveredSigner.toLowerCase() !== permissionSigner.toLowerCase()) {
41090
+ throw new Error(
41091
+ `Security: RegisterPermission was signed by ${recoveredSigner} but the on-chain mandate signer is ${permissionSigner}.
41092
+ Connect the owner wallet (mandate signer) in the browser \u2014 the agent wallet must never sign permission registrations.`
41093
+ );
41094
+ }
41095
+ } catch (err) {
41096
+ if (err.message.startsWith("Security:")) throw err;
41097
+ }
41098
+ const fee = await estimatePermissionFee(publicClient, project.contracts.governance, clone);
41099
+ if (!registerPermissionHasDeadline || deadline === void 0) {
41100
+ throw new Error(
41101
+ "deploy-clone requires a selective kernel (RegisterPermission with deadline). This chain's kernel does not match."
41102
+ );
41103
+ }
41104
+ say(() => console.log(`Submitting deployAndAttach (agent pays gas; fee ${fee} wei)\u2026`));
41105
+ const walletClient = createWalletClient({
41106
+ account: agentSigner.viemAccount,
41107
+ chain: chain2,
41108
+ transport: http(getRpcUrl(project.chainId))
41109
+ });
41110
+ const data = encodeFunctionData({
41111
+ abi: PERMISSION_FACTORY_ABI,
41112
+ functionName: "deployAndAttach",
41113
+ args: [sma, impl, salt, initData, deadline, signature]
41114
+ });
41115
+ const txHash = await walletClient.sendTransaction({
41116
+ to: project.contracts.permissionFactory,
41117
+ data,
41118
+ value: fee,
41119
+ account: agentSigner.viemAccount,
41120
+ chain: chain2
41121
+ });
41122
+ say(() => console.log("Waiting for confirmation\u2026"));
41123
+ const receipt = await publicClient.waitForTransactionReceipt({ hash: txHash });
41124
+ if (receipt.status !== "success") {
41125
+ throw new Error(`deployAndAttach reverted (tx ${txHash})`);
41126
+ }
41127
+ const attached = await pollForPermission(publicClient, project.contracts.kernel, sma, clone);
41128
+ if (!attached) {
41129
+ throw new Error(
41130
+ `Tx ${txHash} mined, but clone ${clone} is not in getPermissions(${sma}). Verify on-chain.`
41131
+ );
41132
+ }
41133
+ say(() => console.log("\u2713", `Deployed + registered ${spec.label} at ${clone}`));
41134
+ const store = new MandateStore();
41135
+ store.add({
41136
+ name: label,
41137
+ address: clone,
41138
+ txHash,
41139
+ chainId: project.chainId,
41140
+ deployedAt: (/* @__PURE__ */ new Date()).toISOString()
41141
+ });
41142
+ store.recordAttachment(clone, { sma, txHash });
41143
+ appendActivity({
41144
+ ts: nowIso(),
41145
+ actor: "agent",
41146
+ type: "permission_registered",
41147
+ permission: clone,
41148
+ name: label,
41149
+ sma,
41150
+ txHash,
41151
+ chainId: project.chainId
41152
+ });
41153
+ emit(json, () => {
41154
+ }, {
41155
+ status: "ok",
41156
+ clone: { template: options.template, address: clone, impl, txHash, sma, chainId: project.chainId }
41157
+ });
41158
+ }
40883
41159
  async function mandateAttach(options) {
40884
41160
  const project = requireProject();
40885
41161
  const channel = await createSigningChannel(process.cwd());
@@ -42114,7 +42390,8 @@ Configure the chain in @sail/chains or set KERNEL_ADDRESS in .sail/.env.local.`
42114
42390
  } catch (err) {
42115
42391
  console.error(`could not read registered permissions: ${err.message}`);
42116
42392
  }
42117
- let tickDispatched = 0;
42393
+ let tickExecuted = 0;
42394
+ let tickReverted = 0;
42118
42395
  let tickSkipped = 0;
42119
42396
  for (const rawDispatch of dispatches) {
42120
42397
  const dispatch = rawDispatch;
@@ -42193,9 +42470,15 @@ Configure the chain in @sail/chains or set KERNEL_ADDRESS in .sail/.env.local.`
42193
42470
  } catch {
42194
42471
  }
42195
42472
  }
42196
- appendActivity({ ts: nowIso(), actor: "agent", type: "dispatch_executed", permission, target, txHash: result.txHash });
42197
- console.log(`executed: ${result.txHash}`);
42198
- tickDispatched++;
42473
+ if (!result.success) {
42474
+ appendActivity({ ts: nowIso(), actor: "agent", type: "dispatch_reverted", permission, target, txHash: result.txHash, gasUsed: String(result.gasUsed) });
42475
+ console.error(`reverted: ${result.txHash} (gas used: ${result.gasUsed})`);
42476
+ tickReverted++;
42477
+ } else {
42478
+ appendActivity({ ts: nowIso(), actor: "agent", type: "dispatch_executed", permission, target, txHash: result.txHash });
42479
+ console.log(`executed: ${result.txHash}`);
42480
+ tickExecuted++;
42481
+ }
42199
42482
  } catch (err) {
42200
42483
  const reason = err.message;
42201
42484
  console.error(`dispatch error: ${reason}`);
@@ -42204,13 +42487,10 @@ Configure the chain in @sail/chains or set KERNEL_ADDRESS in .sail/.env.local.`
42204
42487
  }
42205
42488
  }
42206
42489
  if (dispatches.length > 0) {
42207
- if (tickSkipped > 0) {
42208
- console.log(
42209
- `tick complete: ${tickDispatched} dispatched, ${tickSkipped} skipped (no matching permission or denied)`
42210
- );
42211
- } else {
42212
- console.log(`tick complete: ${tickDispatched} dispatched`);
42213
- }
42490
+ const parts = [`${tickExecuted} executed`];
42491
+ if (tickReverted > 0) parts.push(`${tickReverted} reverted`);
42492
+ if (tickSkipped > 0) parts.push(`${tickSkipped} skipped`);
42493
+ console.log(`tick complete: ${parts.join(", ")}`);
42214
42494
  }
42215
42495
  appendActivity({ ts: nowIso(), actor: "agent", type: "tick_end" });
42216
42496
  }
@@ -42707,6 +42987,7 @@ mandate.command("prepare").description("Prepare a mandate draft for review and s
42707
42987
  mandate.command("sign").description("Review and confirm the permissions authorized for your SMA").option("--yes", "Skip the confirmation prompt (for non-interactive / CI use)").action(actionWith(mandateSign));
42708
42988
  mandate.command("deploy").description("Deploy a Foundry-compiled permission contract via the browser signing UI").option("--artifact <path>", "Path to the Foundry artifact JSON (out/<Name>.sol/<Name>.json)").option("--contract <name>", "Contract name; resolves to <out>/<name>.sol/<name>.json").option("--out <dir>", "Foundry output directory", "out").option("--name <label>", "Label to track this permission under (defaults to contract name)").option("--args <json>", `Constructor args as a JSON array, e.g. '[["0x.."],"1000"]'`).option("--build", "Run `forge build` before deploying").option("--attach", "After deploy, register the permission on --sma").option("--sma <address>", "SMA to register on (required with --attach)").option("--json", "Emit machine-readable JSON").action(actionWith(mandateDeploy));
42709
42989
  mandate.command("attach").description("Register an already-deployed permission on an SMA (EIP-712 RegisterPermission)").requiredOption("--address <mandateOrName>", "Permission address, or a name tracked locally").requiredOption("--sma <address>", "SMA to register the permission on").option("--label <label>", "Human-readable label shown in the signing UI").option("--json", "Emit machine-readable JSON").action(actionWith(mandateAttach));
42990
+ mandate.command("deploy-clone").description("Deploy + register a standalone clone permission (e.g. boundedApprove) via the signing UI").requiredOption("--template <key>", "Standalone clone template key (e.g. boundedApprove)").requiredOption("--sma <address>", "SMA to deploy the clone for and register it on").option("--tokens <csv>", "Comma-separated allowed token addresses").option("--spenders <csv>", "Comma-separated allowed spender addresses").option("--max <amount>", "Max amount per tx in base units (default: uint256 max)").option("--label <label>", "Human-readable label to track this permission under").option("--json", "Emit machine-readable JSON").action(actionWith(mandateDeployClone));
42710
42991
  mandate.command("revoke").description("Revoke permission(s) from an SMA (EIP-712 RevokePermissions, owner-authorized)").option("--address <permissionOrName>", "Permission address, or a name tracked locally").requiredOption("--sma <address>", "Safe (SMA) to revoke the permission(s) from").option("--all", "Revoke every permission currently registered on the SMA").option("--json", "Output JSON").action(actionWith(mandateRevoke));
42711
42992
  mandate.command("templates").description("Show how to author your own permission contract (and any community-deployed addresses)").option("--json", "Emit machine-readable JSON").action(actionWith(mandateTemplates));
42712
42993
  mandate.command("list").description("List permission contracts deployed from this project").action(action(async () => mandateContractsList()));
@@ -5,7 +5,7 @@
5
5
  * Do not edit manually — run `pnpm build` to regenerate.
6
6
  *
7
7
  * Spec version : 1.2.0
8
- * Generated at : 2026-06-06T08:08:18.501Z
8
+ * Generated at : 2026-06-06T19:10:39.495Z
9
9
  */
10
10
  export declare const SAIL_INTELLIGENCE_BASE_URL = "https://api.sail.money";
11
11
  export declare const SAIL_INTELLIGENCE_DOCS_URL = "https://api.sail.money/docs";
@@ -5,7 +5,7 @@
5
5
  * Do not edit manually — run `pnpm build` to regenerate.
6
6
  *
7
7
  * Spec version : 1.2.0
8
- * Generated at : 2026-06-06T08:08:18.501Z
8
+ * Generated at : 2026-06-06T19:10:39.495Z
9
9
  */
10
10
  export const SAIL_INTELLIGENCE_BASE_URL = "https://api.sail.money";
11
11
  export const SAIL_INTELLIGENCE_DOCS_URL = "https://api.sail.money/docs";
@@ -1,16 +1,29 @@
1
1
  import type { Address, PermissionTemplate } from "../types.js";
2
- /** Params for SharedAmmLiquidityPermission. */
2
+ /**
3
+ * Params for SharedAMMLiquidityPermission.
4
+ *
5
+ * Matches the on-chain `_applyConfig` decode exactly:
6
+ * abi.decode(params, (address[], address[], uint128, bool, bool, bool, bool, bool))
7
+ * → allowedTargets, allowedTokens, maxAmountPerTokenPerTx,
8
+ * allowMint, allowIncrease, allowDecrease, allowCollect, allowBurn
9
+ */
3
10
  export type AmmLiquidityParams = {
4
- /** Maximum total liquidity value in USD-equivalent (18-decimal WAD). */
5
- maxLiquidityValueUsd: number;
6
- /** Pool addresses the agent may LP into. */
7
- allowedPools: Address[];
8
- /** Protocol identifiers allowed (e.g. ["uniswapV3", "curveV2", "balancer"]). */
9
- allowedProtocols: string[];
10
- /** Whether single-sided deposits are permitted. */
11
- allowSingleSided: boolean;
12
- /** Maximum price range width in basis points (Uni V3 only). */
13
- maxRangeBps?: number;
11
+ /** Position-manager / router addresses the agent may call (UniV3 NPM, Aerodrome, …). */
12
+ allowedTargets: Address[];
13
+ /** Token addresses the agent may provide as liquidity. */
14
+ allowedTokens: Address[];
15
+ /** Maximum amount of any single token per tx, in that token's base units (uint128). */
16
+ maxAmountPerTokenPerTx: bigint;
17
+ /** Allow mint / open-position (and Aerodrome add-liquidity). */
18
+ allowMint: boolean;
19
+ /** Allow increaseLiquidity. */
20
+ allowIncrease: boolean;
21
+ /** Allow decreaseLiquidity (and Aerodrome remove-liquidity). */
22
+ allowDecrease: boolean;
23
+ /** Allow collect (fee withdrawal). */
24
+ allowCollect: boolean;
25
+ /** Allow burn (close position NFT). */
26
+ allowBurn: boolean;
14
27
  };
15
28
  export declare const ammLiquidityTemplate: PermissionTemplate<AmmLiquidityParams>;
16
29
  //# sourceMappingURL=ammLiquidity.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ammLiquidity.d.ts","sourceRoot":"","sources":["../../src/templates/ammLiquidity.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAA2B,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAExF,+CAA+C;AAC/C,MAAM,MAAM,kBAAkB,GAAG;IAC/B,wEAAwE;IACxE,oBAAoB,EAAE,MAAM,CAAC;IAC7B,4CAA4C;IAC5C,YAAY,EAAE,OAAO,EAAE,CAAC;IACxB,gFAAgF;IAChF,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,mDAAmD;IACnD,gBAAgB,EAAE,OAAO,CAAC;IAC1B,+DAA+D;IAC/D,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,CAAC;AAUF,eAAO,MAAM,oBAAoB,EAAE,kBAAkB,CAAC,kBAAkB,CAuDvE,CAAC"}
1
+ {"version":3,"file":"ammLiquidity.d.ts","sourceRoot":"","sources":["../../src/templates/ammLiquidity.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAA2B,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAExF;;;;;;;GAOG;AACH,MAAM,MAAM,kBAAkB,GAAG;IAC/B,wFAAwF;IACxF,cAAc,EAAE,OAAO,EAAE,CAAC;IAC1B,0DAA0D;IAC1D,aAAa,EAAE,OAAO,EAAE,CAAC;IACzB,uFAAuF;IACvF,sBAAsB,EAAE,MAAM,CAAC;IAC/B,gEAAgE;IAChE,SAAS,EAAE,OAAO,CAAC;IACnB,+BAA+B;IAC/B,aAAa,EAAE,OAAO,CAAC;IACvB,gEAAgE;IAChE,aAAa,EAAE,OAAO,CAAC;IACvB,sCAAsC;IACtC,YAAY,EAAE,OAAO,CAAC;IACtB,uCAAuC;IACvC,SAAS,EAAE,OAAO,CAAC;CACpB,CAAC;AAaF,eAAO,MAAM,oBAAoB,EAAE,kBAAkB,CAAC,kBAAkB,CAyDvE,CAAC"}
@@ -1,56 +1,64 @@
1
1
  import { decodeAbiParameters, encodeAbiParameters } from "viem";
2
2
  const ABI = [
3
- { name: "maxLiquidityValueUsd", type: "uint256" },
4
- { name: "allowedPools", type: "address[]" },
5
- { name: "allowedProtocols", type: "string[]" },
6
- { name: "allowSingleSided", type: "bool" },
7
- { name: "maxRangeBps", type: "uint256" },
3
+ { name: "allowedTargets", type: "address[]" },
4
+ { name: "allowedTokens", type: "address[]" },
5
+ { name: "maxAmountPerTokenPerTx", type: "uint128" },
6
+ { name: "allowMint", type: "bool" },
7
+ { name: "allowIncrease", type: "bool" },
8
+ { name: "allowDecrease", type: "bool" },
9
+ { name: "allowCollect", type: "bool" },
10
+ { name: "allowBurn", type: "bool" },
8
11
  ];
9
12
  export const ammLiquidityTemplate = {
10
- name: "SharedAmmLiquidityPermission",
13
+ name: "SharedAMMLiquidityPermission",
11
14
  address: "0x0000000000000000000000000000000000000000",
12
15
  encoder: {
13
16
  encode(params) {
14
17
  return encodeAbiParameters(ABI, [
15
- BigInt(Math.round(params.maxLiquidityValueUsd)),
16
- params.allowedPools,
17
- params.allowedProtocols,
18
- params.allowSingleSided,
19
- BigInt(params.maxRangeBps ?? 0),
18
+ params.allowedTargets,
19
+ params.allowedTokens,
20
+ params.maxAmountPerTokenPerTx,
21
+ params.allowMint,
22
+ params.allowIncrease,
23
+ params.allowDecrease,
24
+ params.allowCollect,
25
+ params.allowBurn,
20
26
  ]);
21
27
  },
22
28
  decode(data) {
23
29
  const decoded = decodeAbiParameters(ABI, data);
24
- const maxRangeBps = Number(decoded[4]);
25
30
  return {
26
- maxLiquidityValueUsd: Number(decoded[0]),
27
- allowedPools: [...decoded[1]],
28
- allowedProtocols: [...decoded[2]],
29
- allowSingleSided: decoded[3],
30
- ...(maxRangeBps > 0 ? { maxRangeBps } : {}),
31
+ allowedTargets: [...decoded[0]],
32
+ allowedTokens: [...decoded[1]],
33
+ maxAmountPerTokenPerTx: decoded[2],
34
+ allowMint: decoded[3],
35
+ allowIncrease: decoded[4],
36
+ allowDecrease: decoded[5],
37
+ allowCollect: decoded[6],
38
+ allowBurn: decoded[7],
31
39
  };
32
40
  },
33
41
  },
34
42
  explainer: {
35
43
  explain(params) {
36
44
  const warnings = [];
37
- if (params.allowSingleSided) {
38
- warnings.push("Single-sided deposits permittedmay result in immediate impermanent loss");
45
+ if (params.allowedTargets.length === 0) {
46
+ warnings.push("No targets specifiedall liquidity operations will be blocked");
39
47
  }
40
- if (params.maxRangeBps !== undefined && params.maxRangeBps > 5000) {
41
- warnings.push(`Wide price range allowed: ±${params.maxRangeBps / 100}%`);
42
- }
43
- const rangeNote = params.maxRangeBps !== undefined
44
- ? `Maximum price range (Uni V3): ±${params.maxRangeBps / 100}%`
45
- : null;
48
+ const ops = [
49
+ params.allowMint && "mint",
50
+ params.allowIncrease && "increase",
51
+ params.allowDecrease && "decrease",
52
+ params.allowCollect && "collect",
53
+ params.allowBurn && "burn",
54
+ ].filter(Boolean);
46
55
  return {
47
- templateName: "SharedAmmLiquidityPermission",
56
+ templateName: "SharedAMMLiquidityPermission",
48
57
  humanReadable: [
49
- `Maximum liquidity value: $${params.maxLiquidityValueUsd.toLocaleString()} USD`,
50
- `Allowed protocols: ${params.allowedProtocols.join(", ")}`,
51
- `Allowed pools (${params.allowedPools.length}): ${params.allowedPools.join(", ")}`,
52
- `Single-sided deposits: ${params.allowSingleSided ? "allowed" : "not allowed"}`,
53
- ...(rangeNote ? [rangeNote] : []),
58
+ `Maximum amount per token per tx: ${params.maxAmountPerTokenPerTx.toString()} (base units)`,
59
+ `Allowed targets (${params.allowedTargets.length}): ${params.allowedTargets.join(", ")}`,
60
+ `Allowed tokens: ${params.allowedTokens.join(", ")}`,
61
+ `Enabled operations: ${ops.length ? ops.join(", ") : "none"}`,
54
62
  ],
55
63
  warnings,
56
64
  };
@@ -1 +1 @@
1
- {"version":3,"file":"ammLiquidity.js","sourceRoot":"","sources":["../../src/templates/ammLiquidity.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,MAAM,MAAM,CAAC;AAiBhE,MAAM,GAAG,GAAG;IACV,EAAE,IAAI,EAAE,sBAAsB,EAAE,IAAI,EAAE,SAAS,EAAE;IACjD,EAAE,IAAI,EAAE,cAAc,EAAE,IAAI,EAAE,WAAW,EAAE;IAC3C,EAAE,IAAI,EAAE,kBAAkB,EAAE,IAAI,EAAE,UAAU,EAAE;IAC9C,EAAE,IAAI,EAAE,kBAAkB,EAAE,IAAI,EAAE,MAAM,EAAE;IAC1C,EAAE,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE,SAAS,EAAE;CAChC,CAAC;AAEX,MAAM,CAAC,MAAM,oBAAoB,GAA2C;IAC1E,IAAI,EAAE,8BAA8B;IACpC,OAAO,EAAE,4CAA4C;IAErD,OAAO,EAAE;QACP,MAAM,CAAC,MAA0B;YAC/B,OAAO,mBAAmB,CAAC,GAAG,EAAE;gBAC9B,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,oBAAoB,CAAC,CAAC;gBAC/C,MAAM,CAAC,YAAY;gBACnB,MAAM,CAAC,gBAAgB;gBACvB,MAAM,CAAC,gBAAgB;gBACvB,MAAM,CAAC,MAAM,CAAC,WAAW,IAAI,CAAC,CAAC;aAChC,CAAC,CAAC;QACL,CAAC;QACD,MAAM,CAAC,IAAS;YACd,MAAM,OAAO,GAAG,mBAAmB,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;YAC/C,MAAM,WAAW,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;YACvC,OAAO;gBACL,oBAAoB,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;gBACxC,YAAY,EAAE,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;gBAC7B,gBAAgB,EAAE,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;gBACjC,gBAAgB,EAAE,OAAO,CAAC,CAAC,CAAC;gBAC5B,GAAG,CAAC,WAAW,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aAC5C,CAAC;QACJ,CAAC;KACF;IAED,SAAS,EAAE;QACT,OAAO,CAAC,MAA0B;YAChC,MAAM,QAAQ,GAAa,EAAE,CAAC;YAC9B,IAAI,MAAM,CAAC,gBAAgB,EAAE,CAAC;gBAC5B,QAAQ,CAAC,IAAI,CACX,4EAA4E,CAC7E,CAAC;YACJ,CAAC;YACD,IAAI,MAAM,CAAC,WAAW,KAAK,SAAS,IAAI,MAAM,CAAC,WAAW,GAAG,IAAI,EAAE,CAAC;gBAClE,QAAQ,CAAC,IAAI,CAAC,8BAA8B,MAAM,CAAC,WAAW,GAAG,GAAG,GAAG,CAAC,CAAC;YAC3E,CAAC;YACD,MAAM,SAAS,GACb,MAAM,CAAC,WAAW,KAAK,SAAS;gBAC9B,CAAC,CAAC,kCAAkC,MAAM,CAAC,WAAW,GAAG,GAAG,GAAG;gBAC/D,CAAC,CAAC,IAAI,CAAC;YACX,OAAO;gBACL,YAAY,EAAE,8BAA8B;gBAC5C,aAAa,EAAE;oBACb,6BAA6B,MAAM,CAAC,oBAAoB,CAAC,cAAc,EAAE,MAAM;oBAC/E,sBAAsB,MAAM,CAAC,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;oBAC1D,kBAAkB,MAAM,CAAC,YAAY,CAAC,MAAM,MAAM,MAAM,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;oBAClF,0BAA0B,MAAM,CAAC,gBAAgB,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,aAAa,EAAE;oBAC/E,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;iBAClC;gBACD,QAAQ;aACT,CAAC;QACJ,CAAC;KACF;CACF,CAAC"}
1
+ {"version":3,"file":"ammLiquidity.js","sourceRoot":"","sources":["../../src/templates/ammLiquidity.ts"],"names":[],"mappings":"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"}
@@ -1,14 +1,28 @@
1
- import type { Address, PermissionTemplate } from "../types.js";
2
- /** Params for SharedApproveAndCallBatchPermission. */
1
+ import type { Address, Hex, PermissionTemplate } from "../types.js";
2
+ /**
3
+ * Params for SharedApproveAndCallBatchPermission.
4
+ *
5
+ * Matches the on-chain `_applyConfig` decode exactly:
6
+ * abi.decode(params, (Config))
7
+ * where Config is the tuple
8
+ * (address[] tokens, address[] spenders, address[] consumingTargets,
9
+ * bytes4[] consumingSelectors, uint256[] maxApprovalAmounts, bool requireAmountMatch)
10
+ *
11
+ * Note: the contract encodes a SINGLE struct, so the blob is one top-level tuple.
12
+ */
3
13
  export type ApproveAndCallBatchParams = {
4
- /** Spender addresses that may receive ERC-20 approvals. */
5
- allowedSpenders: Address[];
6
- /** Token addresses for which approvals may be granted. */
7
- allowedTokens: Address[];
8
- /** Maximum total approval value per batch in USD-equivalent (18-decimal WAD). */
9
- maxApprovalValueUsd: number;
10
- /** Whether infinite (max-uint) approvals are permitted. */
11
- allowInfiniteApprovals: boolean;
14
+ /** Allowlisted ERC-20 tokens that may be approved. Index-parallel with `maxApprovalAmounts`. */
15
+ tokens: Address[];
16
+ /** Allowlisted spenders that may receive the allowance. */
17
+ spenders: Address[];
18
+ /** Allowlisted consuming-call targets (often the same as spenders). */
19
+ consumingTargets: Address[];
20
+ /** Allowlisted selectors for the consuming call (4-byte hex, e.g. "0x095ea7b3"). */
21
+ consumingSelectors: Hex[];
22
+ /** Max approve amount per token, index-parallel with `tokens`. */
23
+ maxApprovalAmounts: bigint[];
24
+ /** When true, the consuming call's leading uint256 arg must equal the approved amount. */
25
+ requireAmountMatch: boolean;
12
26
  };
13
27
  export declare const approveAndCallBatchTemplate: PermissionTemplate<ApproveAndCallBatchParams>;
14
28
  //# sourceMappingURL=approveAndCallBatch.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"approveAndCallBatch.d.ts","sourceRoot":"","sources":["../../src/templates/approveAndCallBatch.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAA2B,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAExF,sDAAsD;AACtD,MAAM,MAAM,yBAAyB,GAAG;IACtC,2DAA2D;IAC3D,eAAe,EAAE,OAAO,EAAE,CAAC;IAC3B,0DAA0D;IAC1D,aAAa,EAAE,OAAO,EAAE,CAAC;IACzB,iFAAiF;IACjF,mBAAmB,EAAE,MAAM,CAAC;IAC5B,2DAA2D;IAC3D,sBAAsB,EAAE,OAAO,CAAC;CACjC,CAAC;AASF,eAAO,MAAM,2BAA2B,EAAE,kBAAkB,CAAC,yBAAyB,CAgDrF,CAAC"}
1
+ {"version":3,"file":"approveAndCallBatch.d.ts","sourceRoot":"","sources":["../../src/templates/approveAndCallBatch.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,GAAG,EAAsB,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAExF;;;;;;;;;;GAUG;AACH,MAAM,MAAM,yBAAyB,GAAG;IACtC,gGAAgG;IAChG,MAAM,EAAE,OAAO,EAAE,CAAC;IAClB,2DAA2D;IAC3D,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,uEAAuE;IACvE,gBAAgB,EAAE,OAAO,EAAE,CAAC;IAC5B,oFAAoF;IACpF,kBAAkB,EAAE,GAAG,EAAE,CAAC;IAC1B,kEAAkE;IAClE,kBAAkB,EAAE,MAAM,EAAE,CAAC;IAC7B,0FAA0F;IAC1F,kBAAkB,EAAE,OAAO,CAAC;CAC7B,CAAC;AAaF,eAAO,MAAM,2BAA2B,EAAE,kBAAkB,CAAC,yBAAyB,CA4DrF,CAAC"}