@dev.sail.money/sailor 0.0.2-12
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/AGENTS.md +111 -0
- package/LICENSE +21 -0
- package/README.md +337 -0
- package/docs/PERMISSION_MODEL.md +93 -0
- package/examples/permissions/BoundedBet_Limitless_Base.sol +96 -0
- package/examples/permissions/BoundedBorrow_AaveV3_Arbitrum.sol +94 -0
- package/examples/permissions/BoundedPerp_GMXv2_Arbitrum.sol +143 -0
- package/examples/permissions/BoundedSwap_UniswapV3_Base.sol +113 -0
- package/examples/permissions/BoundedSwap_UniswapV4_Unichain.sol +144 -0
- package/examples/permissions/BoundedTransfer_ERC20_Ethereum.sol +73 -0
- package/examples/permissions/README.md +52 -0
- package/examples/permissions/foundry.toml +10 -0
- package/examples/permissions/interfaces/IPermission.sol +18 -0
- package/package.json +39 -0
- package/packages/cli/README.md +34 -0
- package/packages/cli/dist/index.cjs +42801 -0
- package/packages/cli/dist/server.cjs +51201 -0
- package/packages/sdk/README.md +65 -0
- package/packages/sdk/dist/abis/MandateFactory.d.ts +140 -0
- package/packages/sdk/dist/abis/MandateFactory.d.ts.map +1 -0
- package/packages/sdk/dist/abis/MandateFactory.js +93 -0
- package/packages/sdk/dist/abis/MandateFactory.js.map +1 -0
- package/packages/sdk/dist/abis/SailGovernance.d.ts +57 -0
- package/packages/sdk/dist/abis/SailGovernance.d.ts.map +1 -0
- package/packages/sdk/dist/abis/SailGovernance.js +52 -0
- package/packages/sdk/dist/abis/SailGovernance.js.map +1 -0
- package/packages/sdk/dist/abis/SailKernel.d.ts +466 -0
- package/packages/sdk/dist/abis/SailKernel.d.ts.map +1 -0
- package/packages/sdk/dist/abis/SailKernel.js +311 -0
- package/packages/sdk/dist/abis/SailKernel.js.map +1 -0
- package/packages/sdk/dist/abis/index.d.ts +4 -0
- package/packages/sdk/dist/abis/index.d.ts.map +1 -0
- package/packages/sdk/dist/abis/index.js +7 -0
- package/packages/sdk/dist/abis/index.js.map +1 -0
- package/packages/sdk/dist/capabilities.d.ts +77 -0
- package/packages/sdk/dist/capabilities.d.ts.map +1 -0
- package/packages/sdk/dist/capabilities.js +158 -0
- package/packages/sdk/dist/capabilities.js.map +1 -0
- package/packages/sdk/dist/client.d.ts +37 -0
- package/packages/sdk/dist/client.d.ts.map +1 -0
- package/packages/sdk/dist/client.js +646 -0
- package/packages/sdk/dist/client.js.map +1 -0
- package/packages/sdk/dist/deployments.d.ts +82 -0
- package/packages/sdk/dist/deployments.d.ts.map +1 -0
- package/packages/sdk/dist/deployments.js +197 -0
- package/packages/sdk/dist/deployments.js.map +1 -0
- package/packages/sdk/dist/discovery.d.ts +10 -0
- package/packages/sdk/dist/discovery.d.ts.map +1 -0
- package/packages/sdk/dist/discovery.js +41 -0
- package/packages/sdk/dist/discovery.js.map +1 -0
- package/packages/sdk/dist/eip712.d.ts +257 -0
- package/packages/sdk/dist/eip712.d.ts.map +1 -0
- package/packages/sdk/dist/eip712.js +255 -0
- package/packages/sdk/dist/eip712.js.map +1 -0
- package/packages/sdk/dist/errors.d.ts +47 -0
- package/packages/sdk/dist/errors.d.ts.map +1 -0
- package/packages/sdk/dist/errors.js +168 -0
- package/packages/sdk/dist/errors.js.map +1 -0
- package/packages/sdk/dist/fees.d.ts +16 -0
- package/packages/sdk/dist/fees.d.ts.map +1 -0
- package/packages/sdk/dist/fees.js +51 -0
- package/packages/sdk/dist/fees.js.map +1 -0
- package/packages/sdk/dist/index.d.ts +23 -0
- package/packages/sdk/dist/index.d.ts.map +1 -0
- package/packages/sdk/dist/index.js +16 -0
- package/packages/sdk/dist/index.js.map +1 -0
- package/packages/sdk/dist/intelligence.d.ts +923 -0
- package/packages/sdk/dist/intelligence.d.ts.map +1 -0
- package/packages/sdk/dist/intelligence.js +357 -0
- package/packages/sdk/dist/intelligence.js.map +1 -0
- package/packages/sdk/dist/keyring.d.ts +60 -0
- package/packages/sdk/dist/keyring.d.ts.map +1 -0
- package/packages/sdk/dist/keyring.js +159 -0
- package/packages/sdk/dist/keyring.js.map +1 -0
- package/packages/sdk/dist/lifi.d.ts +83 -0
- package/packages/sdk/dist/lifi.d.ts.map +1 -0
- package/packages/sdk/dist/lifi.js +69 -0
- package/packages/sdk/dist/lifi.js.map +1 -0
- package/packages/sdk/dist/safe.d.ts +158 -0
- package/packages/sdk/dist/safe.d.ts.map +1 -0
- package/packages/sdk/dist/safe.js +163 -0
- package/packages/sdk/dist/safe.js.map +1 -0
- package/packages/sdk/dist/signing.d.ts +106 -0
- package/packages/sdk/dist/signing.d.ts.map +1 -0
- package/packages/sdk/dist/signing.js +2 -0
- package/packages/sdk/dist/signing.js.map +1 -0
- package/packages/sdk/dist/templates/ammLiquidity.d.ts +16 -0
- package/packages/sdk/dist/templates/ammLiquidity.d.ts.map +1 -0
- package/packages/sdk/dist/templates/ammLiquidity.js +60 -0
- package/packages/sdk/dist/templates/ammLiquidity.js.map +1 -0
- package/packages/sdk/dist/templates/approveAndCallBatch.d.ts +14 -0
- package/packages/sdk/dist/templates/approveAndCallBatch.d.ts.map +1 -0
- package/packages/sdk/dist/templates/approveAndCallBatch.js +53 -0
- package/packages/sdk/dist/templates/approveAndCallBatch.js.map +1 -0
- package/packages/sdk/dist/templates/boundedBorrow.d.ts +16 -0
- package/packages/sdk/dist/templates/boundedBorrow.d.ts.map +1 -0
- package/packages/sdk/dist/templates/boundedBorrow.js +56 -0
- package/packages/sdk/dist/templates/boundedBorrow.js.map +1 -0
- package/packages/sdk/dist/templates/boundedSwap.d.ts +16 -0
- package/packages/sdk/dist/templates/boundedSwap.d.ts.map +1 -0
- package/packages/sdk/dist/templates/boundedSwap.js +56 -0
- package/packages/sdk/dist/templates/boundedSwap.js.map +1 -0
- package/packages/sdk/dist/templates/defiBundle.d.ts +14 -0
- package/packages/sdk/dist/templates/defiBundle.d.ts.map +1 -0
- package/packages/sdk/dist/templates/defiBundle.js +52 -0
- package/packages/sdk/dist/templates/defiBundle.js.map +1 -0
- package/packages/sdk/dist/templates/index.d.ts +15 -0
- package/packages/sdk/dist/templates/index.d.ts.map +1 -0
- package/packages/sdk/dist/templates/index.js +8 -0
- package/packages/sdk/dist/templates/index.js.map +1 -0
- package/packages/sdk/dist/templates/pendle.d.ts +14 -0
- package/packages/sdk/dist/templates/pendle.d.ts.map +1 -0
- package/packages/sdk/dist/templates/pendle.js +52 -0
- package/packages/sdk/dist/templates/pendle.js.map +1 -0
- package/packages/sdk/dist/templates/transferTarget.d.ts +10 -0
- package/packages/sdk/dist/templates/transferTarget.d.ts.map +1 -0
- package/packages/sdk/dist/templates/transferTarget.js +42 -0
- package/packages/sdk/dist/templates/transferTarget.js.map +1 -0
- package/packages/sdk/dist/types.d.ts +382 -0
- package/packages/sdk/dist/types.d.ts.map +1 -0
- package/packages/sdk/dist/types.js +2 -0
- package/packages/sdk/dist/types.js.map +1 -0
- package/packages/sdk/package.json +52 -0
- package/packages/ui/dist/assets/Arc-VDBY7LNS-BChRXCXW.js +1 -0
- package/packages/ui/dist/assets/Brave-BRAKJXDS-mq-Xo37j.js +1 -0
- package/packages/ui/dist/assets/Browser-76IHF3Y2-BMhRaC5Z.js +1 -0
- package/packages/ui/dist/assets/Chrome-65Q5P54Y-DR9MQEVr.js +1 -0
- package/packages/ui/dist/assets/Edge-XSPUTORV-DEoZslQE.js +1 -0
- package/packages/ui/dist/assets/Firefox-AAHGJQIP-Bp_Hm04m.js +1 -0
- package/packages/ui/dist/assets/Linux-OO4TNCLJ-B0aw93n9.js +1 -0
- package/packages/ui/dist/assets/Macos-MW4AE7LN-Vvm8Drw3.js +1 -0
- package/packages/ui/dist/assets/Opera-KQZLSACL-Cwv5MDFy.js +1 -0
- package/packages/ui/dist/assets/Safari-ZPL37GXR-C4Ggg6rz.js +1 -0
- package/packages/ui/dist/assets/Windows-PPTHQER6-BlyV2p7Y.js +1 -0
- package/packages/ui/dist/assets/add-DaJhwIBV.js +15 -0
- package/packages/ui/dist/assets/all-wallets-BUxsqWXi.js +6 -0
- package/packages/ui/dist/assets/apechain-SX5YFU6N-q5qBv-mp.js +1 -0
- package/packages/ui/dist/assets/app-store-DkltwTqE.js +17 -0
- package/packages/ui/dist/assets/apple-owVOeaIT.js +18 -0
- package/packages/ui/dist/assets/ar_AR-LIPSOZP5-BQrIDibT.js +1519 -0
- package/packages/ui/dist/assets/arbitrum-WURIBY6W-CqVkHBr5.js +1 -0
- package/packages/ui/dist/assets/arrow-bottom-D2mmNJve.js +8 -0
- package/packages/ui/dist/assets/arrow-bottom-circle-CbNYijx-.js +11 -0
- package/packages/ui/dist/assets/arrow-left-DJB61s4C.js +8 -0
- package/packages/ui/dist/assets/arrow-right-BBrsQ9R4.js +8 -0
- package/packages/ui/dist/assets/arrow-top-Cil6bOc8.js +8 -0
- package/packages/ui/dist/assets/assets-Q6ZU7ZJ5-P8HioiAD.js +1 -0
- package/packages/ui/dist/assets/avalanche-KOMJD3XY-Dsn_JPR4.js +1 -0
- package/packages/ui/dist/assets/bank-CbwEmRo3.js +14 -0
- package/packages/ui/dist/assets/base-OAXLRA4F-CoYTVIiL.js +1 -0
- package/packages/ui/dist/assets/base-QS6CYWIN-CsjdbWCf.js +1 -0
- package/packages/ui/dist/assets/basic-CLNfjw3m.js +2128 -0
- package/packages/ui/dist/assets/berachain-NJECWIVC-DumxnFvf.js +1 -0
- package/packages/ui/dist/assets/blast-V555OVXZ-BbhJh1tj.js +1 -0
- package/packages/ui/dist/assets/browser-B5TtF4Pb.js +14 -0
- package/packages/ui/dist/assets/bsc-N647EYR2-B2nLKXWV.js +1 -0
- package/packages/ui/dist/assets/card-CO7BVB-C.js +14 -0
- package/packages/ui/dist/assets/ccip-2W7K3_J3.js +1 -0
- package/packages/ui/dist/assets/celo-GEP4TUHG-CenIBYLU.js +1 -0
- package/packages/ui/dist/assets/checkmark-BEtSHq9m.js +11 -0
- package/packages/ui/dist/assets/checkmark-bold-D9xGHzPE.js +8 -0
- package/packages/ui/dist/assets/chevron-bottom-BDztht6i.js +8 -0
- package/packages/ui/dist/assets/chevron-left-EV4GFNbc.js +8 -0
- package/packages/ui/dist/assets/chevron-right-B4_bB9oR.js +8 -0
- package/packages/ui/dist/assets/chevron-top-D54xPNzF.js +8 -0
- package/packages/ui/dist/assets/chrome-store-DYUpAJJq.js +61 -0
- package/packages/ui/dist/assets/clock-Ca1T1Soz.js +8 -0
- package/packages/ui/dist/assets/close-BZqWjurK.js +8 -0
- package/packages/ui/dist/assets/coinPlaceholder-e6fl2XDo.js +8 -0
- package/packages/ui/dist/assets/compass-DCLC7zIh.js +8 -0
- package/packages/ui/dist/assets/connect-UA7M4XW6-IY3X6Bmr.js +1 -0
- package/packages/ui/dist/assets/copy-Th2AaD-O.js +15 -0
- package/packages/ui/dist/assets/core-Ckx_cyuH.js +907 -0
- package/packages/ui/dist/assets/create-FASO7PVG-D_rvSpre.js +1 -0
- package/packages/ui/dist/assets/cronos-HJPAQTAE-BEOvlOC4.js +1 -0
- package/packages/ui/dist/assets/cursor-DV7rOqbJ.js +3 -0
- package/packages/ui/dist/assets/cursor-transparent-BKHeABKB.js +12 -0
- package/packages/ui/dist/assets/de_DE-YE3KOFHU-BRt5ztUe.js +1519 -0
- package/packages/ui/dist/assets/degen-FQQ4XGHB-CeHTs88l.js +1 -0
- package/packages/ui/dist/assets/desktop-CBjY8t6F.js +9 -0
- package/packages/ui/dist/assets/disconnect-DbSs2cli.js +8 -0
- package/packages/ui/dist/assets/discord-ZlLOAUkM.js +17 -0
- package/packages/ui/dist/assets/es_419-7LMPU7G4-DH7rM0yQ.js +1519 -0
- package/packages/ui/dist/assets/ethereum-RGGVA4PY-SWGOlkuk.js +1 -0
- package/packages/ui/dist/assets/etherscan-CKUrqWYN.js +6 -0
- package/packages/ui/dist/assets/events-CiKP71cK.js +1 -0
- package/packages/ui/dist/assets/exclamation-triangle-DA1QzFiO.js +4 -0
- package/packages/ui/dist/assets/extension-BVJkmvpJ.js +8 -0
- package/packages/ui/dist/assets/external-link-D_bsR7B2.js +8 -0
- package/packages/ui/dist/assets/facebook-CmFmhojx.js +26 -0
- package/packages/ui/dist/assets/fallback-Ofl6uSnB.js +1 -0
- package/packages/ui/dist/assets/farcaster-Co-M3Ss8.js +12 -0
- package/packages/ui/dist/assets/filters-B1WwNaFU.js +8 -0
- package/packages/ui/dist/assets/flow-5FQJFCTK-CUie2reO.js +1 -0
- package/packages/ui/dist/assets/fr_FR-VBJP3ZLL-B-_ocunw.js +1519 -0
- package/packages/ui/dist/assets/github-CP4fP6gn.js +18 -0
- package/packages/ui/dist/assets/gnosis-37ZC4RBL-B137OtHZ.js +1 -0
- package/packages/ui/dist/assets/google-CsOIXJ6V.js +18 -0
- package/packages/ui/dist/assets/gravity-J5YQHTYH-Bj6B0uod.js +1 -0
- package/packages/ui/dist/assets/hardhat-TX56IT5N-CV1FY-wE.js +1 -0
- package/packages/ui/dist/assets/help-circle-DiMkomdF.js +12 -0
- package/packages/ui/dist/assets/hi_IN-WBVD5XYI-D73g2UFs.js +1519 -0
- package/packages/ui/dist/assets/hyperevm-VKPAA4SA-CHwraEsx.js +1 -0
- package/packages/ui/dist/assets/id-lmscL5LX.js +12 -0
- package/packages/ui/dist/assets/id_ID-SBYANJ7G-Cjpa4ay6.js +1519 -0
- package/packages/ui/dist/assets/image-B-ubJrY5.js +4 -0
- package/packages/ui/dist/assets/index-BaukYv-x.js +16 -0
- package/packages/ui/dist/assets/index-CF0KMmke.js +395 -0
- package/packages/ui/dist/assets/index-CKxgNxS9.css +1 -0
- package/packages/ui/dist/assets/index-CZR1Qjhs.js +1 -0
- package/packages/ui/dist/assets/index-DVgfCzCo.js +1 -0
- package/packages/ui/dist/assets/index-Dbh5V1Z0.js +1 -0
- package/packages/ui/dist/assets/index-Q2Yai4Fe.js +2103 -0
- package/packages/ui/dist/assets/index.es-C78cE5SI.js +26 -0
- package/packages/ui/dist/assets/info-Cqg57EVo.js +3 -0
- package/packages/ui/dist/assets/info-circle-DkeSWNKV.js +12 -0
- package/packages/ui/dist/assets/ink-FZMYZWHG-62p-5IK5.js +1 -0
- package/packages/ui/dist/assets/ja_JP-ZRMWJV3I-DXbifiMm.js +1519 -0
- package/packages/ui/dist/assets/kaia-65D2U3PU-JmuLQ4gC.js +1 -0
- package/packages/ui/dist/assets/ko_KR-FR54RFUG-upinSHjQ.js +1519 -0
- package/packages/ui/dist/assets/lightbulb-DNlO4qKh.js +3 -0
- package/packages/ui/dist/assets/linea-QRMVQ5DY-DuI3vv0d.js +1 -0
- package/packages/ui/dist/assets/login-UP3DZBGS-Db_wM5oQ.js +1 -0
- package/packages/ui/dist/assets/mail-kVQ8Jb9Y.js +8 -0
- package/packages/ui/dist/assets/manta-SI27YFEJ-CpVOKa06.js +1 -0
- package/packages/ui/dist/assets/mantle-CKIUT334-DR2WgqzU.js +1 -0
- package/packages/ui/dist/assets/metaMaskWallet-EI6MED72-D5HFOsnz.js +1 -0
- package/packages/ui/dist/assets/metamask-sdk-CBalSvz7.js +542 -0
- package/packages/ui/dist/assets/mobile-BEteuhF7.js +9 -0
- package/packages/ui/dist/assets/monad-4KWC6TSS-DVXSkpiz.js +1 -0
- package/packages/ui/dist/assets/more-DBWmXQli.js +11 -0
- package/packages/ui/dist/assets/ms_MY-EZSGYYYQ-4cPLK-3L.js +1519 -0
- package/packages/ui/dist/assets/native-CJ5et6AR.js +1 -0
- package/packages/ui/dist/assets/network-placeholder-Dg1uUHiL.js +14 -0
- package/packages/ui/dist/assets/nftPlaceholder-i3AHSiD9.js +8 -0
- package/packages/ui/dist/assets/off-BtMm0fi2.js +8 -0
- package/packages/ui/dist/assets/optimism-HAF2GUT7-ec6Nqxs9.js +1 -0
- package/packages/ui/dist/assets/parseSignature-Cb5FlWWg.js +1 -0
- package/packages/ui/dist/assets/play-store-iKKkXa6a.js +32 -0
- package/packages/ui/dist/assets/plus-CA5NaRtb.js +13 -0
- package/packages/ui/dist/assets/polygon-WW6ZI7PM-DXlmm4L1.js +1 -0
- package/packages/ui/dist/assets/pt_BR-JQFQ3P4L-DOHfdcA2.js +1519 -0
- package/packages/ui/dist/assets/qr-code-D2kiqR7h.js +6 -0
- package/packages/ui/dist/assets/rainbowWallet-O26YNBMX-DUhYus-9.js +1 -0
- package/packages/ui/dist/assets/recycle-horizontal-Dcme7R03.js +9 -0
- package/packages/ui/dist/assets/refresh-Dega3sDp.js +8 -0
- package/packages/ui/dist/assets/refresh-S4T5V5GX-CwqIaaxK.js +1 -0
- package/packages/ui/dist/assets/reown-logo-xNkksyWJ.js +12 -0
- package/packages/ui/dist/assets/ronin-EMCPYXZT-N-QBHZdV.js +1 -0
- package/packages/ui/dist/assets/ru_RU-Z42UEJBP-Cvb2oWxQ.js +1519 -0
- package/packages/ui/dist/assets/safeWallet-5MNKTR5Z-D-5imDLD.js +1 -0
- package/packages/ui/dist/assets/sanko-RHQYXGM5-OX010CbN.js +1 -0
- package/packages/ui/dist/assets/scan-4UYSQ56Q-CjMz6-XC.js +1 -0
- package/packages/ui/dist/assets/scroll-5OBGQVOV-DJFECiai.js +1 -0
- package/packages/ui/dist/assets/search-HYl7NO8x.js +8 -0
- package/packages/ui/dist/assets/secp256k1-Cxd6_SiH.js +1 -0
- package/packages/ui/dist/assets/send-CJU8CUAo.js +15 -0
- package/packages/ui/dist/assets/sign-A7IJEUT5-CGsRnPrd.js +1 -0
- package/packages/ui/dist/assets/superposition-HG6MMR2Y-bRkgatRO.js +1 -0
- package/packages/ui/dist/assets/swapHorizontal-IMUKiUre.js +8 -0
- package/packages/ui/dist/assets/swapHorizontalBold-CNYnNJ9-.js +8 -0
- package/packages/ui/dist/assets/swapHorizontalMedium-B9VxEYsT.js +16 -0
- package/packages/ui/dist/assets/swapHorizontalRoundedBold-Dz33l_Jh.js +8 -0
- package/packages/ui/dist/assets/swapVertical-CHUmjVJ0.js +8 -0
- package/packages/ui/dist/assets/telegram-kl9S2mbU.js +16 -0
- package/packages/ui/dist/assets/th_TH-4YB4VSB2-BUipNP-V.js +1519 -0
- package/packages/ui/dist/assets/three-dots-U5lhA1Am.js +5 -0
- package/packages/ui/dist/assets/tr_TR-5FKHPPIO-D5jTpIm9.js +1519 -0
- package/packages/ui/dist/assets/twitch-KTEUWXEp.js +18 -0
- package/packages/ui/dist/assets/twitterIcon-BHiq8mRg.js +6 -0
- package/packages/ui/dist/assets/uk_UA-ZD4IBC52-DgnQrpzl.js +1519 -0
- package/packages/ui/dist/assets/unichain-C5BWO2ZY-BfguYsnu.js +1 -0
- package/packages/ui/dist/assets/verify-CfN-BXNd.js +8 -0
- package/packages/ui/dist/assets/verify-filled-DwZccetj.js +8 -0
- package/packages/ui/dist/assets/vi_VN-5EVRZKLY-x078672g.js +1519 -0
- package/packages/ui/dist/assets/w3m-modal-CS-PFqPE.js +642 -0
- package/packages/ui/dist/assets/wallet-DVlGkhOY.js +8 -0
- package/packages/ui/dist/assets/wallet-placeholder-CvR_iEWX.js +14 -0
- package/packages/ui/dist/assets/walletConnectWallet-YHWKVTDY-D3lyiczV.js +1 -0
- package/packages/ui/dist/assets/walletconnect-8pZBDvVI.js +30 -0
- package/packages/ui/dist/assets/warning-circle-ylLEE0Yp.js +12 -0
- package/packages/ui/dist/assets/x-C_TBsTMj.js +12 -0
- package/packages/ui/dist/assets/xdc-KJ3TDBYO-DNV6zchh.js +1 -0
- package/packages/ui/dist/assets/zetachain-TLDS5IPW-Udhyw16T.js +1 -0
- package/packages/ui/dist/assets/zh_CN-4XK5YJPR-Bt6Yz5Ek.js +1519 -0
- package/packages/ui/dist/assets/zh_HK-N4YN2WSI-Cvzl1V16.js +1519 -0
- package/packages/ui/dist/assets/zh_TW-CNCRXH6Z-BNelatfN.js +1519 -0
- package/packages/ui/dist/assets/zksync-DH7HK5U4-Dt4usFw6.js +1 -0
- package/packages/ui/dist/assets/zora-FYL5H3IO-iB4wygST.js +1 -0
- package/packages/ui/dist/index.html +14 -0
- package/scripts/check-docs.mjs +262 -0
- package/scripts/check-init.mjs +109 -0
- package/scripts/postinstall.js +366 -0
- package/templates/custom-mandate/.sail/contracts/interfaces/IPermission.sol +18 -0
- package/templates/custom-mandate/README.md +85 -0
- package/templates/custom-mandate/foundry.toml +8 -0
- package/templates/custom-mandate/mandates/BoundedCallPermission.sol +35 -0
- package/templates/custom-mandate/mandates/README.md +16 -0
- package/templates/dca-rebalancer/.cursor/rules +25 -0
- package/templates/dca-rebalancer/.env.example +6 -0
- package/templates/dca-rebalancer/.github/workflows/agent-tick.yml +32 -0
- package/templates/dca-rebalancer/.sail/.gitkeep +0 -0
- package/templates/dca-rebalancer/.sail/README.md +13 -0
- package/templates/dca-rebalancer/.sail/config.json +10 -0
- package/templates/dca-rebalancer/AGENTS.md +246 -0
- package/templates/dca-rebalancer/AGENT_PLAYBOOK.md +110 -0
- package/templates/dca-rebalancer/CLAUDE.md +2 -0
- package/templates/dca-rebalancer/README.md +16 -0
- package/templates/dca-rebalancer/_gitignore +13 -0
- package/templates/dca-rebalancer/docs/PERMISSION_MODEL.md +93 -0
- package/templates/dca-rebalancer/package.json +17 -0
- package/templates/dca-rebalancer/src/agent.ts +253 -0
- package/templates/dca-rebalancer/src/config.ts +27 -0
- package/templates/dca-rebalancer/src/mandate.ts +67 -0
- package/templates/dca-rebalancer/tsconfig.json +8 -0
- package/templates/dca-rebalancer/ui/README.md +3 -0
- package/templates/lifi-permissions/LifiBoundedApprovePermissionCloneable.sol +84 -0
- package/templates/lifi-permissions/LifiDiamondSwapPermissionCloneable.sol +97 -0
- package/templates/lifi-permissions/README.md +53 -0
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
pragma solidity 0.8.26;
|
|
3
|
+
|
|
4
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
5
|
+
// Protocol : Aave V3
|
|
6
|
+
// Version : Pool (proxy) — fully on-chain, oracle-based liquidation
|
|
7
|
+
// Chain : Arbitrum mainnet
|
|
8
|
+
// Target : Aave V3 Pool 0x794a61358D6845594F94dc1DB02A252b5b4814aD
|
|
9
|
+
//
|
|
10
|
+
// ENFORCED ON-CHAIN (via kernel evaluate() on every dispatch):
|
|
11
|
+
// borrow(address asset, uint256 amount, uint256 interestRateMode,
|
|
12
|
+
// uint16 referralCode, address onBehalfOf)
|
|
13
|
+
// • target must be AAVE_POOL
|
|
14
|
+
// • asset must be in ALLOWED_ASSETS
|
|
15
|
+
// • amount ≤ MAX_BORROW_AMOUNT
|
|
16
|
+
// • onBehalfOf must equal ctx.account (the SMA — agent cannot borrow on behalf of others)
|
|
17
|
+
// • interestRateMode must be in ALLOWED_RATE_MODES
|
|
18
|
+
// (1 = stable [deprecated in V3.1], 2 = variable; restrict to [2] for V3.1+)
|
|
19
|
+
//
|
|
20
|
+
// NOT ENFORCED (agent code — can change without a new contract):
|
|
21
|
+
// • Health factor management — the kernel cannot check post-borrow health factor
|
|
22
|
+
// • referralCode (informational only, does not affect fund safety)
|
|
23
|
+
// • Repayment timing — agent decides when to repay
|
|
24
|
+
// • Collateral composition — managed by prior deposit permissions
|
|
25
|
+
//
|
|
26
|
+
// VERIFY BEFORE USE:
|
|
27
|
+
// • Confirm Aave V3 Pool address on Arbitrum (0x794a... — verify on Arbiscan).
|
|
28
|
+
// • Selector 0xa415bcad = borrow(address,uint256,uint256,uint16,address).
|
|
29
|
+
// Compute: keccak256("borrow(address,uint256,uint256,uint16,address)")[0:4]
|
|
30
|
+
// and confirm it matches before deploying.
|
|
31
|
+
// • Aave V3.1 deprecated stable-rate borrowing (interestRateMode=1).
|
|
32
|
+
// If using V3.1+, set allowedRateModes = [2] (variable only).
|
|
33
|
+
// • MAX_BORROW_AMOUNT is in the asset's base units (e.g. 6 decimals for USDC).
|
|
34
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
35
|
+
|
|
36
|
+
import {IPermission, Context} from "@sail/interfaces/IPermission.sol";
|
|
37
|
+
|
|
38
|
+
contract BoundedBorrow_AaveV3_Arbitrum is IPermission {
|
|
39
|
+
bytes32 private constant DISCRIMINATOR = keccak256("BoundedBorrow_AaveV3_Arbitrum");
|
|
40
|
+
|
|
41
|
+
address public immutable AAVE_POOL;
|
|
42
|
+
mapping(address => bool) public isAllowedAsset;
|
|
43
|
+
uint256 public immutable MAX_BORROW_AMOUNT;
|
|
44
|
+
mapping(uint256 => bool) public isAllowedRateMode;
|
|
45
|
+
|
|
46
|
+
// borrow(address,uint256,uint256,uint16,address)
|
|
47
|
+
// VERIFY: keccak256("borrow(address,uint256,uint256,uint16,address)")[0:4] == 0xa415bcad
|
|
48
|
+
bytes4 private constant SEL_BORROW = 0xa415bcad;
|
|
49
|
+
|
|
50
|
+
/// @param aavePool Aave V3 Pool proxy address
|
|
51
|
+
/// @param allowedAssets Assets the agent may borrow
|
|
52
|
+
/// @param maxBorrowAmount Per-call borrow cap in asset base units
|
|
53
|
+
/// @param allowedRateModes Interest rate modes allowed (2 = variable; use [2] for V3.1+)
|
|
54
|
+
constructor(
|
|
55
|
+
address aavePool,
|
|
56
|
+
address[] memory allowedAssets,
|
|
57
|
+
uint256 maxBorrowAmount,
|
|
58
|
+
uint256[] memory allowedRateModes
|
|
59
|
+
) {
|
|
60
|
+
AAVE_POOL = aavePool;
|
|
61
|
+
MAX_BORROW_AMOUNT = maxBorrowAmount;
|
|
62
|
+
for (uint256 i = 0; i < allowedAssets.length; i++) {
|
|
63
|
+
isAllowedAsset[allowedAssets[i]] = true;
|
|
64
|
+
}
|
|
65
|
+
for (uint256 i = 0; i < allowedRateModes.length; i++) {
|
|
66
|
+
isAllowedRateMode[allowedRateModes[i]] = true;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function evaluate(bytes calldata txData, Context calldata ctx) external view returns (bool) {
|
|
71
|
+
if (ctx.target != AAVE_POOL) return false;
|
|
72
|
+
if (ctx.selector != SEL_BORROW) return false;
|
|
73
|
+
// borrow(address asset, uint256 amount, uint256 interestRateMode, uint16 referralCode, address onBehalfOf)
|
|
74
|
+
// = 5 ABI-encoded 32-byte slots after the 4-byte selector
|
|
75
|
+
if (txData.length < 4 + 5 * 32) return false;
|
|
76
|
+
|
|
77
|
+
(
|
|
78
|
+
address asset,
|
|
79
|
+
uint256 amount,
|
|
80
|
+
uint256 interestRateMode,
|
|
81
|
+
/* uint16 referralCode — not bounded */,
|
|
82
|
+
address onBehalfOf
|
|
83
|
+
) = abi.decode(txData[4:], (address, uint256, uint256, uint16, address));
|
|
84
|
+
|
|
85
|
+
if (!isAllowedAsset[asset]) return false;
|
|
86
|
+
if (amount > MAX_BORROW_AMOUNT) return false;
|
|
87
|
+
if (onBehalfOf != ctx.account) return false; // agent borrows only for the SMA
|
|
88
|
+
if (!isAllowedRateMode[interestRateMode]) return false;
|
|
89
|
+
|
|
90
|
+
return true;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function discriminator() external pure returns (bytes32) { return DISCRIMINATOR; }
|
|
94
|
+
}
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
pragma solidity 0.8.26;
|
|
3
|
+
|
|
4
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
5
|
+
// Protocol : GMX V2 (gmx-synthetics)
|
|
6
|
+
// Version : ExchangeRouter / OrderHandler — fully on-chain oracle execution
|
|
7
|
+
// NOT Hyperliquid (off-chain order book — permissions cannot bound orders)
|
|
8
|
+
// Chain : Arbitrum mainnet
|
|
9
|
+
// Target : ExchangeRouter 0x7c68c7866a64fa2160f78eeae12217ffbf871fa8
|
|
10
|
+
// (verify on Arbiscan — GMX may redeploy; check their official docs)
|
|
11
|
+
//
|
|
12
|
+
// ENFORCED ON-CHAIN (via kernel evaluate() on every dispatch):
|
|
13
|
+
// createOrder(CreateOrderParams params) selector 0x414577b7
|
|
14
|
+
// • target must be EXCHANGE_ROUTER
|
|
15
|
+
// • market must be in ALLOWED_MARKETS
|
|
16
|
+
// • initialCollateralDeltaAmount ≤ MAX_COLLATERAL_AMOUNT
|
|
17
|
+
// • sizeDeltaUsd ≤ MAX_SIZE_DELTA_USD
|
|
18
|
+
// • isLong must be in ALLOWED_DIRECTIONS (true=long, false=short, or both)
|
|
19
|
+
//
|
|
20
|
+
// NOT ENFORCED — documented limitations:
|
|
21
|
+
// • Leverage ratio: sizeDeltaUsd vs collateralDeltaAmount are bounded separately
|
|
22
|
+
// but their ratio (effective leverage) is not directly enforced here because
|
|
23
|
+
// it depends on collateral price. Add a price-oracle leverage check if needed.
|
|
24
|
+
// • acceptablePrice / triggerPrice: not bounded — agent controls entry price.
|
|
25
|
+
// Add bounds if the strategy requires a price range check.
|
|
26
|
+
// • decreasePositionSwapType, shouldUnwrapNativeToken, autoCancel: not bounded.
|
|
27
|
+
// • swapPath (inside CreateOrderParamAddresses): not bounded — any intermediate
|
|
28
|
+
// tokens in the swap path are allowed. Restrict if needed.
|
|
29
|
+
// • receiver address: not bounded — set to ctx.account in your agent.
|
|
30
|
+
//
|
|
31
|
+
// STRUCT LAYOUT NOTE:
|
|
32
|
+
// This contract defines CreateOrderParams inline. It must match EXACTLY the
|
|
33
|
+
// struct layout in the deployed ExchangeRouter's IBaseOrderUtils. If GMX
|
|
34
|
+
// updates the struct (e.g. adds a field), this permission will misparse calldata
|
|
35
|
+
// and return false (fail closed — safe but non-functional).
|
|
36
|
+
// VERIFY against BaseOrderUtils.sol at:
|
|
37
|
+
// https://github.com/gmx-io/gmx-synthetics/blob/main/contracts/order/BaseOrderUtils.sol
|
|
38
|
+
//
|
|
39
|
+
// VERIFY BEFORE USE:
|
|
40
|
+
// • Confirm ExchangeRouter address on Arbitrum (0x7c68... — verify on Arbiscan).
|
|
41
|
+
// • Selector 0x414577b7 = createOrder(IBaseOrderUtils.CreateOrderParams).
|
|
42
|
+
// Verify against the deployed contract's ABI tab on Arbiscan.
|
|
43
|
+
// • sizeDeltaUsd is in USD with 30 decimals (GMX V2 standard). E.g. $1000 = 1e33.
|
|
44
|
+
// • initialCollateralDeltaAmount is in collateral token base units.
|
|
45
|
+
// • Test with real calldata samples from GMX V2 on Arbitrum testnet before mainnet.
|
|
46
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
47
|
+
|
|
48
|
+
import {IPermission, Context} from "@sail/interfaces/IPermission.sol";
|
|
49
|
+
|
|
50
|
+
contract BoundedPerp_GMXv2_Arbitrum is IPermission {
|
|
51
|
+
bytes32 private constant DISCRIMINATOR = keccak256("BoundedPerp_GMXv2_Arbitrum");
|
|
52
|
+
|
|
53
|
+
address public immutable EXCHANGE_ROUTER;
|
|
54
|
+
mapping(address => bool) public isAllowedMarket;
|
|
55
|
+
uint256 public immutable MAX_COLLATERAL_AMOUNT;
|
|
56
|
+
/// @dev sizeDeltaUsd uses GMX V2's 30-decimal USD representation. 1 USD = 1e30.
|
|
57
|
+
uint256 public immutable MAX_SIZE_DELTA_USD;
|
|
58
|
+
bool public immutable ALLOW_LONG;
|
|
59
|
+
bool public immutable ALLOW_SHORT;
|
|
60
|
+
|
|
61
|
+
// createOrder(IBaseOrderUtils.CreateOrderParams)
|
|
62
|
+
// VERIFY: keccak256("createOrder(...)")[0:4] == 0x414577b7 on deployed ExchangeRouter
|
|
63
|
+
bytes4 private constant SEL_CREATE_ORDER = 0x414577b7;
|
|
64
|
+
|
|
65
|
+
// ── Inline struct definitions — MUST match IBaseOrderUtils.CreateOrderParams ──
|
|
66
|
+
// Verify against:
|
|
67
|
+
// https://github.com/gmx-io/gmx-synthetics/blob/main/contracts/order/BaseOrderUtils.sol
|
|
68
|
+
|
|
69
|
+
struct CreateOrderParamAddresses {
|
|
70
|
+
address receiver;
|
|
71
|
+
address callbackContract;
|
|
72
|
+
address uiFeeReceiver;
|
|
73
|
+
address market;
|
|
74
|
+
address initialCollateralToken;
|
|
75
|
+
address[] swapPath; // dynamic — makes this struct dynamic
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
struct CreateOrderParamNumbers {
|
|
79
|
+
uint256 sizeDeltaUsd;
|
|
80
|
+
uint256 initialCollateralDeltaAmount;
|
|
81
|
+
uint256 triggerPrice;
|
|
82
|
+
uint256 acceptablePrice;
|
|
83
|
+
uint256 executionFee;
|
|
84
|
+
uint256 callbackGasLimit;
|
|
85
|
+
uint256 minOutputAmount;
|
|
86
|
+
uint256 validFromTime;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
struct CreateOrderParams {
|
|
90
|
+
CreateOrderParamAddresses addresses;
|
|
91
|
+
CreateOrderParamNumbers numbers;
|
|
92
|
+
uint8 orderType;
|
|
93
|
+
uint8 decreasePositionSwapType;
|
|
94
|
+
bool isLong;
|
|
95
|
+
bool shouldUnwrapNativeToken;
|
|
96
|
+
bool autoCancel;
|
|
97
|
+
bytes32 referralCode;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/// @param exchangeRouter GMX V2 ExchangeRouter address
|
|
101
|
+
/// @param allowedMarkets GMX V2 market addresses the agent may trade
|
|
102
|
+
/// @param maxCollateralAmount Per-order collateral cap in collateral token base units
|
|
103
|
+
/// @param maxSizeDeltaUsd Per-order position size cap in GMX USD (30 decimals)
|
|
104
|
+
/// @param allowLong Whether long orders are permitted
|
|
105
|
+
/// @param allowShort Whether short orders are permitted
|
|
106
|
+
constructor(
|
|
107
|
+
address exchangeRouter,
|
|
108
|
+
address[] memory allowedMarkets,
|
|
109
|
+
uint256 maxCollateralAmount,
|
|
110
|
+
uint256 maxSizeDeltaUsd,
|
|
111
|
+
bool allowLong,
|
|
112
|
+
bool allowShort
|
|
113
|
+
) {
|
|
114
|
+
EXCHANGE_ROUTER = exchangeRouter;
|
|
115
|
+
MAX_COLLATERAL_AMOUNT = maxCollateralAmount;
|
|
116
|
+
MAX_SIZE_DELTA_USD = maxSizeDeltaUsd;
|
|
117
|
+
ALLOW_LONG = allowLong;
|
|
118
|
+
ALLOW_SHORT = allowShort;
|
|
119
|
+
for (uint256 i = 0; i < allowedMarkets.length; i++) {
|
|
120
|
+
isAllowedMarket[allowedMarkets[i]] = true;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function evaluate(bytes calldata txData, Context calldata ctx) external view returns (bool) {
|
|
125
|
+
if (ctx.target != EXCHANGE_ROUTER) return false;
|
|
126
|
+
if (ctx.selector != SEL_CREATE_ORDER) return false;
|
|
127
|
+
if (txData.length < 4) return false;
|
|
128
|
+
|
|
129
|
+
// abi.decode handles the nested dynamic struct (address[] swapPath) correctly.
|
|
130
|
+
// A malformed calldata or struct layout mismatch causes a revert → false (fail closed).
|
|
131
|
+
CreateOrderParams memory p = abi.decode(txData[4:], (CreateOrderParams));
|
|
132
|
+
|
|
133
|
+
if (!isAllowedMarket[p.addresses.market]) return false;
|
|
134
|
+
if (p.numbers.initialCollateralDeltaAmount > MAX_COLLATERAL_AMOUNT) return false;
|
|
135
|
+
if (p.numbers.sizeDeltaUsd > MAX_SIZE_DELTA_USD) return false;
|
|
136
|
+
if (p.isLong && !ALLOW_LONG) return false;
|
|
137
|
+
if (!p.isLong && !ALLOW_SHORT) return false;
|
|
138
|
+
|
|
139
|
+
return true;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
function discriminator() external pure returns (bytes32) { return DISCRIMINATOR; }
|
|
143
|
+
}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
pragma solidity 0.8.26;
|
|
3
|
+
|
|
4
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
5
|
+
// Protocol : Uniswap V3
|
|
6
|
+
// Version : SwapRouter02 (NOT the older SwapRouter — different selectors)
|
|
7
|
+
// Chain : Base mainnet
|
|
8
|
+
// Target : SwapRouter02 0x2626664c2603336E57B271c5C0b26F421741e481
|
|
9
|
+
//
|
|
10
|
+
// ENFORCED ON-CHAIN (via kernel evaluate() on every dispatch):
|
|
11
|
+
// exactInputSingle path (selector 0x04e45aaf):
|
|
12
|
+
// • target must be SWAP_ROUTER
|
|
13
|
+
// • tokenIn must equal FIXED_TOKEN_IN
|
|
14
|
+
// • tokenOut must be in ALLOWED_TOKENS_OUT
|
|
15
|
+
// • amountIn ≤ MAX_AMOUNT_IN
|
|
16
|
+
// • amountOutMinimum ≥ amountIn × MIN_BPS / 10 000 (slippage floor)
|
|
17
|
+
// approve path (selector 0x095ea7b3):
|
|
18
|
+
// • target must be FIXED_TOKEN_IN (the ERC-20 being approved)
|
|
19
|
+
// • spender must be SWAP_ROUTER
|
|
20
|
+
// • amount ≤ MAX_AMOUNT_IN
|
|
21
|
+
//
|
|
22
|
+
// NOT ENFORCED (agent code — can change without a new contract):
|
|
23
|
+
// • fee tier, sqrtPriceLimitX96, recipient address
|
|
24
|
+
// • swap frequency / cadence
|
|
25
|
+
//
|
|
26
|
+
// VERIFY BEFORE USE:
|
|
27
|
+
// • Confirm SwapRouter02 address on your chain (Base default shown above).
|
|
28
|
+
// • Selector 0x04e45aaf = exactInputSingle((address,address,uint24,address,uint256,uint256,uint160))
|
|
29
|
+
// on SwapRouter02. The older SwapRouter uses a different selector (0x414577b7).
|
|
30
|
+
// • Confirm that amountOutMinimum slippage floor fits your price-impact expectations for the
|
|
31
|
+
// chosen pool. Large amountIn values may trigger price impact beyond MIN_BPS.
|
|
32
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
33
|
+
|
|
34
|
+
import {IPermission, Context} from "@sail/interfaces/IPermission.sol";
|
|
35
|
+
|
|
36
|
+
contract BoundedSwap_UniswapV3_Base is IPermission {
|
|
37
|
+
bytes32 private constant DISCRIMINATOR = keccak256("BoundedSwap_UniswapV3_Base");
|
|
38
|
+
|
|
39
|
+
address public immutable SWAP_ROUTER;
|
|
40
|
+
address public immutable FIXED_TOKEN_IN;
|
|
41
|
+
mapping(address => bool) public isAllowedTokenOut;
|
|
42
|
+
uint256 public immutable MAX_AMOUNT_IN;
|
|
43
|
+
/// @dev Slippage floor in basis points. 9 900 = allow at most 1% slippage.
|
|
44
|
+
uint256 public immutable MIN_BPS;
|
|
45
|
+
|
|
46
|
+
bytes4 private constant SEL_EXACT_INPUT_SINGLE = 0x04e45aaf;
|
|
47
|
+
bytes4 private constant SEL_APPROVE = 0x095ea7b3;
|
|
48
|
+
|
|
49
|
+
struct ExactInputSingleParams {
|
|
50
|
+
address tokenIn;
|
|
51
|
+
address tokenOut;
|
|
52
|
+
uint24 fee;
|
|
53
|
+
address recipient;
|
|
54
|
+
uint256 amountIn;
|
|
55
|
+
uint256 amountOutMinimum;
|
|
56
|
+
uint160 sqrtPriceLimitX96;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/// @param swapRouter SwapRouter02 address (0x2626... on Base)
|
|
60
|
+
/// @param fixedTokenIn The one token the agent is allowed to sell
|
|
61
|
+
/// @param allowedTokensOut Tokens the agent may receive
|
|
62
|
+
/// @param maxAmountIn Per-call spend cap in fixedTokenIn base units
|
|
63
|
+
/// @param minBps Minimum amountOutMinimum as fraction of amountIn ×10 000
|
|
64
|
+
/// e.g. 9900 → require amountOutMinimum ≥ 99% of amountIn
|
|
65
|
+
/// (denominated in fixedTokenIn units, not USD — set per your pair)
|
|
66
|
+
constructor(
|
|
67
|
+
address swapRouter,
|
|
68
|
+
address fixedTokenIn,
|
|
69
|
+
address[] memory allowedTokensOut,
|
|
70
|
+
uint256 maxAmountIn,
|
|
71
|
+
uint256 minBps
|
|
72
|
+
) {
|
|
73
|
+
require(minBps <= 10_000, "minBps > 10000");
|
|
74
|
+
SWAP_ROUTER = swapRouter;
|
|
75
|
+
FIXED_TOKEN_IN = fixedTokenIn;
|
|
76
|
+
MAX_AMOUNT_IN = maxAmountIn;
|
|
77
|
+
MIN_BPS = minBps;
|
|
78
|
+
for (uint256 i = 0; i < allowedTokensOut.length; i++) {
|
|
79
|
+
isAllowedTokenOut[allowedTokensOut[i]] = true;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function evaluate(bytes calldata txData, Context calldata ctx) external view returns (bool) {
|
|
84
|
+
if (txData.length < 4) return false;
|
|
85
|
+
|
|
86
|
+
// exactInputSingle: agent swaps FIXED_TOKEN_IN for an allowed output token
|
|
87
|
+
if (ctx.target == SWAP_ROUTER && ctx.selector == SEL_EXACT_INPUT_SINGLE) {
|
|
88
|
+
if (txData.length < 4 + 7 * 32) return false;
|
|
89
|
+
ExactInputSingleParams memory p = abi.decode(txData[4:], (ExactInputSingleParams));
|
|
90
|
+
if (p.tokenIn != FIXED_TOKEN_IN) return false;
|
|
91
|
+
if (!isAllowedTokenOut[p.tokenOut]) return false;
|
|
92
|
+
if (p.amountIn > MAX_AMOUNT_IN) return false;
|
|
93
|
+
// Slippage floor: require amountOutMinimum ≥ amountIn * MIN_BPS / 10 000.
|
|
94
|
+
// This is not a USD check — it's a ratio check in tokenIn units.
|
|
95
|
+
// For a USDC→WETH swap, set MIN_BPS conservatively (e.g. 9 900 for 1% slippage).
|
|
96
|
+
if (p.amountOutMinimum < (p.amountIn * MIN_BPS) / 10_000) return false;
|
|
97
|
+
return true;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// approve: agent approves the router to spend FIXED_TOKEN_IN
|
|
101
|
+
if (ctx.target == FIXED_TOKEN_IN && ctx.selector == SEL_APPROVE) {
|
|
102
|
+
if (txData.length < 4 + 2 * 32) return false;
|
|
103
|
+
(address spender, uint256 amount) = abi.decode(txData[4:], (address, uint256));
|
|
104
|
+
if (spender != SWAP_ROUTER) return false;
|
|
105
|
+
if (amount > MAX_AMOUNT_IN) return false;
|
|
106
|
+
return true;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
return false;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function discriminator() external pure returns (bytes32) { return DISCRIMINATOR; }
|
|
113
|
+
}
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
pragma solidity 0.8.26;
|
|
3
|
+
|
|
4
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
5
|
+
// Protocol : Uniswap V4
|
|
6
|
+
// Version : Universal Router + PoolManager (V4 singleton)
|
|
7
|
+
// NOTE: V4 is NOT the same as V3. Calldata encoding is completely
|
|
8
|
+
// different — do NOT adapt a V3 permission for V4.
|
|
9
|
+
// Chain : Unichain mainnet
|
|
10
|
+
// Target : Universal Router 0xef740bf23acae26f6492b10de645d6b98dc8eaf3
|
|
11
|
+
// (verify on Uniscan before use)
|
|
12
|
+
//
|
|
13
|
+
// ENFORCED ON-CHAIN (via kernel evaluate() on every dispatch):
|
|
14
|
+
// execute(bytes,bytes[]) or execute(bytes,bytes[],uint256):
|
|
15
|
+
// • target must be UNIVERSAL_ROUTER
|
|
16
|
+
// • first command byte (masking the allow-failure MSB) must be V4_SWAP (0x10)
|
|
17
|
+
// • exactly one command (single-swap path — disallow multi-hop command strings)
|
|
18
|
+
// • V4 action inside must be SWAP_EXACT_IN_SINGLE (0x00)
|
|
19
|
+
// • tokenIn (from poolKey, derived by zeroForOne) must be FIXED_CURRENCY_IN
|
|
20
|
+
// • tokenOut must be in ALLOWED_CURRENCIES_OUT
|
|
21
|
+
// • amountIn ≤ MAX_AMOUNT_IN
|
|
22
|
+
// • amountOutMinimum ≥ amountIn × MIN_BPS / 10 000
|
|
23
|
+
//
|
|
24
|
+
// NOT ENFORCED — documented limitations:
|
|
25
|
+
// • hookData is not inspected (hooks can alter swap behavior on-chain; if the
|
|
26
|
+
// pool uses a hook that significantly changes execution, this permission cannot
|
|
27
|
+
// constrain it. Deploy against pools with address(0) hooks or audited hooks only.)
|
|
28
|
+
// • fee tier and tickSpacing within the PoolKey are not constrained here
|
|
29
|
+
// (add pool-key checks if you want to restrict to a specific pool)
|
|
30
|
+
// • The ALL_CURRENCY_PAIR constant (FIXED_CURRENCY_IN, allowedCurrenciesOut) does
|
|
31
|
+
// not constrain which pool is used when multiple pools share the same currency pair
|
|
32
|
+
//
|
|
33
|
+
// VERIFY BEFORE USE:
|
|
34
|
+
// • Confirm Universal Router address on Unichain (shown above; verify on Uniscan).
|
|
35
|
+
// • V4_SWAP command byte = 0x10, SWAP_EXACT_IN_SINGLE action = 0x00 — verify
|
|
36
|
+
// against deployed UniversalRouter and V4Router on Unichain if contract is updated.
|
|
37
|
+
// • PoolKey struct layout (currency0, currency1, fee, tickSpacing, hooks) must
|
|
38
|
+
// match the deployed PoolManager on Unichain. If layout changes, update struct.
|
|
39
|
+
// • hookData is not bounded. Only use with unhookyed pools or audited, bounded hooks.
|
|
40
|
+
// • Calldata revert = false (kernel treats revert as denial) — malformed inputs
|
|
41
|
+
// are safely rejected, but verify with actual calldata samples before deployment.
|
|
42
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
43
|
+
|
|
44
|
+
import {IPermission, Context} from "@sail/interfaces/IPermission.sol";
|
|
45
|
+
|
|
46
|
+
contract BoundedSwap_UniswapV4_Unichain is IPermission {
|
|
47
|
+
bytes32 private constant DISCRIMINATOR = keccak256("BoundedSwap_UniswapV4_Unichain");
|
|
48
|
+
|
|
49
|
+
address public immutable UNIVERSAL_ROUTER;
|
|
50
|
+
address public immutable FIXED_CURRENCY_IN;
|
|
51
|
+
mapping(address => bool) public isAllowedCurrencyOut;
|
|
52
|
+
uint256 public immutable MAX_AMOUNT_IN;
|
|
53
|
+
uint256 public immutable MIN_BPS;
|
|
54
|
+
|
|
55
|
+
// execute(bytes,bytes[],uint256) — with deadline
|
|
56
|
+
bytes4 private constant SEL_EXECUTE_DEADLINE = 0x3593564c;
|
|
57
|
+
// execute(bytes,bytes[]) — without deadline
|
|
58
|
+
bytes4 private constant SEL_EXECUTE = 0x24856bc3;
|
|
59
|
+
// Universal Router command byte for V4_SWAP
|
|
60
|
+
uint8 private constant CMD_V4_SWAP = 0x10;
|
|
61
|
+
// Bit mask to strip the "allow failure" MSB from a command byte
|
|
62
|
+
uint8 private constant CMD_MASK = 0x3f;
|
|
63
|
+
// V4Router action: SWAP_EXACT_IN_SINGLE
|
|
64
|
+
uint8 private constant ACT_SWAP_EXACT_IN_SINGLE = 0x00;
|
|
65
|
+
|
|
66
|
+
// PoolKey layout must match the deployed V4 PoolManager on Unichain
|
|
67
|
+
struct PoolKey {
|
|
68
|
+
address currency0; // Currency — address type in V4
|
|
69
|
+
address currency1;
|
|
70
|
+
uint24 fee;
|
|
71
|
+
int24 tickSpacing;
|
|
72
|
+
address hooks; // IHooks — address(0) for unhookyed pools
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
struct ExactInputSingleParams {
|
|
76
|
+
PoolKey poolKey;
|
|
77
|
+
bool zeroForOne;
|
|
78
|
+
uint128 amountIn;
|
|
79
|
+
uint128 amountOutMinimum;
|
|
80
|
+
bytes hookData; // not inspected — see limitations header
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
constructor(
|
|
84
|
+
address universalRouter,
|
|
85
|
+
address fixedCurrencyIn,
|
|
86
|
+
address[] memory allowedCurrenciesOut,
|
|
87
|
+
uint256 maxAmountIn,
|
|
88
|
+
uint256 minBps
|
|
89
|
+
) {
|
|
90
|
+
require(minBps <= 10_000, "minBps > 10000");
|
|
91
|
+
UNIVERSAL_ROUTER = universalRouter;
|
|
92
|
+
FIXED_CURRENCY_IN = fixedCurrencyIn;
|
|
93
|
+
MAX_AMOUNT_IN = maxAmountIn;
|
|
94
|
+
MIN_BPS = minBps;
|
|
95
|
+
for (uint256 i = 0; i < allowedCurrenciesOut.length; i++) {
|
|
96
|
+
isAllowedCurrenciesOut[allowedCurrenciesOut[i]] = true;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
mapping(address => bool) private isAllowedCurrenciesOut;
|
|
101
|
+
|
|
102
|
+
function evaluate(bytes calldata txData, Context calldata ctx) external view returns (bool) {
|
|
103
|
+
if (ctx.target != UNIVERSAL_ROUTER) return false;
|
|
104
|
+
if (ctx.selector != SEL_EXECUTE_DEADLINE && ctx.selector != SEL_EXECUTE) return false;
|
|
105
|
+
if (txData.length < 4) return false;
|
|
106
|
+
|
|
107
|
+
// Decode the execute call. Both overloads start with (bytes commands, bytes[] inputs).
|
|
108
|
+
// abi.decode ignores trailing fields, so decoding as (bytes, bytes[]) works for both.
|
|
109
|
+
(bytes memory commands, bytes[] memory inputs) = abi.decode(txData[4:], (bytes, bytes[]));
|
|
110
|
+
|
|
111
|
+
// Enforce: exactly one command, and it must be V4_SWAP
|
|
112
|
+
if (commands.length != 1) return false;
|
|
113
|
+
if ((uint8(commands[0]) & CMD_MASK) != CMD_V4_SWAP) return false;
|
|
114
|
+
if (inputs.length != 1) return false;
|
|
115
|
+
|
|
116
|
+
// Decode the V4 router call (actions + per-action params)
|
|
117
|
+
(bytes memory v4Actions, bytes[] memory v4Params) =
|
|
118
|
+
abi.decode(inputs[0], (bytes, bytes[]));
|
|
119
|
+
|
|
120
|
+
// Enforce: exactly one V4 action, and it must be SWAP_EXACT_IN_SINGLE
|
|
121
|
+
if (v4Actions.length != 1) return false;
|
|
122
|
+
if (uint8(v4Actions[0]) != ACT_SWAP_EXACT_IN_SINGLE) return false;
|
|
123
|
+
if (v4Params.length != 1) return false;
|
|
124
|
+
|
|
125
|
+
// Decode ExactInputSingleParams from the action param.
|
|
126
|
+
// hookData is a dynamic bytes field — revert here means false (fail closed).
|
|
127
|
+
ExactInputSingleParams memory p = abi.decode(v4Params[0], (ExactInputSingleParams));
|
|
128
|
+
|
|
129
|
+
// Derive tokenIn and tokenOut from the PoolKey and zeroForOne flag.
|
|
130
|
+
// In V4, currency0 < currency1 (sorted by address). zeroForOne = true means
|
|
131
|
+
// trading currency0 for currency1.
|
|
132
|
+
address tokenIn = p.zeroForOne ? p.poolKey.currency0 : p.poolKey.currency1;
|
|
133
|
+
address tokenOut = p.zeroForOne ? p.poolKey.currency1 : p.poolKey.currency0;
|
|
134
|
+
|
|
135
|
+
if (tokenIn != FIXED_CURRENCY_IN) return false;
|
|
136
|
+
if (!isAllowedCurrenciesOut[tokenOut]) return false;
|
|
137
|
+
if (p.amountIn > MAX_AMOUNT_IN) return false;
|
|
138
|
+
if (p.amountOutMinimum < (uint256(p.amountIn) * MIN_BPS) / 10_000) return false;
|
|
139
|
+
|
|
140
|
+
return true;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
function discriminator() external pure returns (bytes32) { return DISCRIMINATOR; }
|
|
144
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
pragma solidity 0.8.26;
|
|
3
|
+
|
|
4
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
5
|
+
// Protocol : ERC-20
|
|
6
|
+
// Version : Standard ERC-20 (version-agnostic)
|
|
7
|
+
// Chain : Ethereum mainnet (works on any EVM — the most general example)
|
|
8
|
+
//
|
|
9
|
+
// ENFORCED ON-CHAIN (via kernel evaluate() on every dispatch):
|
|
10
|
+
// transfer(address to, uint256 amount)
|
|
11
|
+
// • target must be in ALLOWED_TOKENS
|
|
12
|
+
// • recipient (to) must be in ALLOWED_RECIPIENTS
|
|
13
|
+
// • amount ≤ MAX_AMOUNT_PER_TRANSFER
|
|
14
|
+
//
|
|
15
|
+
// NOT ENFORCED (agent code — can change without a new contract):
|
|
16
|
+
// • transfer frequency / timing
|
|
17
|
+
// • choice of token within ALLOWED_TOKENS
|
|
18
|
+
// • choice of recipient within ALLOWED_RECIPIENTS
|
|
19
|
+
//
|
|
20
|
+
// VERIFY BEFORE USE:
|
|
21
|
+
// • Selector 0xa9059cbb = transfer(address,uint256) — universally standard.
|
|
22
|
+
// • ALLOWED_TOKENS prevents the agent from transferring tokens not in the set.
|
|
23
|
+
// If a protocol uses non-standard transfer methods (e.g. transferFrom or
|
|
24
|
+
// proprietary hooks), add separate selector entries.
|
|
25
|
+
// • MAX_AMOUNT_PER_TRANSFER is denominated in the token's base units.
|
|
26
|
+
// Different tokens have different decimals (USDC = 6, WETH = 18).
|
|
27
|
+
// Set one permission per token if amounts differ across tokens.
|
|
28
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
29
|
+
|
|
30
|
+
import {IPermission, Context} from "@sail/interfaces/IPermission.sol";
|
|
31
|
+
|
|
32
|
+
contract BoundedTransfer_ERC20_Ethereum is IPermission {
|
|
33
|
+
bytes32 private constant DISCRIMINATOR = keccak256("BoundedTransfer_ERC20_Ethereum");
|
|
34
|
+
|
|
35
|
+
mapping(address => bool) public isAllowedToken;
|
|
36
|
+
mapping(address => bool) public isAllowedRecipient;
|
|
37
|
+
uint256 public immutable MAX_AMOUNT_PER_TRANSFER;
|
|
38
|
+
|
|
39
|
+
// transfer(address,uint256)
|
|
40
|
+
bytes4 private constant SEL_TRANSFER = 0xa9059cbb;
|
|
41
|
+
|
|
42
|
+
/// @param allowedTokens ERC-20 contracts the agent may transfer from
|
|
43
|
+
/// @param allowedRecipients Addresses the agent may send to
|
|
44
|
+
/// @param maxAmountPerTransfer Per-call amount cap (in token base units)
|
|
45
|
+
constructor(
|
|
46
|
+
address[] memory allowedTokens,
|
|
47
|
+
address[] memory allowedRecipients,
|
|
48
|
+
uint256 maxAmountPerTransfer
|
|
49
|
+
) {
|
|
50
|
+
MAX_AMOUNT_PER_TRANSFER = maxAmountPerTransfer;
|
|
51
|
+
for (uint256 i = 0; i < allowedTokens.length; i++) {
|
|
52
|
+
isAllowedToken[allowedTokens[i]] = true;
|
|
53
|
+
}
|
|
54
|
+
for (uint256 i = 0; i < allowedRecipients.length; i++) {
|
|
55
|
+
isAllowedRecipient[allowedRecipients[i]] = true;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function evaluate(bytes calldata txData, Context calldata ctx) external view returns (bool) {
|
|
60
|
+
if (!isAllowedToken[ctx.target]) return false;
|
|
61
|
+
if (ctx.selector != SEL_TRANSFER) return false;
|
|
62
|
+
if (txData.length < 4 + 2 * 32) return false;
|
|
63
|
+
|
|
64
|
+
(address to, uint256 amount) = abi.decode(txData[4:], (address, uint256));
|
|
65
|
+
|
|
66
|
+
if (!isAllowedRecipient[to]) return false;
|
|
67
|
+
if (amount > MAX_AMOUNT_PER_TRANSFER) return false;
|
|
68
|
+
|
|
69
|
+
return true;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function discriminator() external pure returns (bytes32) { return DISCRIMINATOR; }
|
|
73
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# Permission Examples
|
|
2
|
+
|
|
3
|
+
These are example permission contracts for common DeFi protocols, maintained by Sailor.
|
|
4
|
+
|
|
5
|
+
**They are not part of Sail Protocol. They are not audited by Sail. They are not a supported
|
|
6
|
+
or exhaustive set.** The protocol accepts any contract implementing IPermission — these examples
|
|
7
|
+
teach the bounding pattern for specific protocols so you (and your AI agent) can adapt them or
|
|
8
|
+
write your own.
|
|
9
|
+
|
|
10
|
+
## Permissions are only as strong as the protocol is on-chain
|
|
11
|
+
|
|
12
|
+
A permission is evaluated by the kernel on every dispatch — but it can only see what happens
|
|
13
|
+
on-chain. For venues with off-chain order matching (e.g. Polymarket, Hyperliquid), a permission
|
|
14
|
+
can constrain deposits, withdrawals, and sub-accounts, but NOT the orders your agent signs
|
|
15
|
+
off-chain. Prefer fully on-chain venues — Uniswap, Aave, GMX, Synthetix, Limitless — where every
|
|
16
|
+
action passes through the kernel and your bounds actually hold.
|
|
17
|
+
|
|
18
|
+
## Permissions are protocol- and version-specific
|
|
19
|
+
|
|
20
|
+
Calldata differs by protocol and by version. A Uniswap V3 swap is a different decode than a
|
|
21
|
+
Uniswap V4 swap. Use the example closest to YOUR exact protocol+version+chain, verify the decode
|
|
22
|
+
against the protocol's real ABI, and confirm what it enforces before deploying.
|
|
23
|
+
|
|
24
|
+
You own what you deploy.
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## Examples
|
|
29
|
+
|
|
30
|
+
| File | Protocol | Version | Chain | Status |
|
|
31
|
+
|---|---|---|---|---|
|
|
32
|
+
| `BoundedSwap_UniswapV3_Base.sol` | Uniswap Swap | V3 SwapRouter02 | Base | Full decode |
|
|
33
|
+
| `BoundedSwap_UniswapV4_Unichain.sol` | Uniswap Swap | V4 Universal Router | Unichain | Partial decode — see header |
|
|
34
|
+
| `BoundedBorrow_AaveV3_Arbitrum.sol` | Aave Borrow | V3 Pool | Arbitrum | Full decode — verify selector |
|
|
35
|
+
| `BoundedTransfer_ERC20_Ethereum.sol` | ERC-20 Transfer | — | Ethereum (any EVM) | Full decode |
|
|
36
|
+
| `BoundedPerp_GMXv2_Arbitrum.sol` | GMX Perpetuals | V2 ExchangeRouter | Arbitrum | Partial decode — see header |
|
|
37
|
+
| `BoundedBet_Limitless_Base.sol` | Limitless Prediction | CTF Exchange | Base | UNVERIFIED ABI — see header |
|
|
38
|
+
|
|
39
|
+
## Using these examples
|
|
40
|
+
|
|
41
|
+
Each file is self-contained and explains in its header exactly what is and is not enforced.
|
|
42
|
+
Read the header before deploying.
|
|
43
|
+
|
|
44
|
+
To compile:
|
|
45
|
+
```bash
|
|
46
|
+
forge build
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
To deploy within a Sailor project (copy the .sol file to `mandates/` first):
|
|
50
|
+
```bash
|
|
51
|
+
sailor mandate deploy --contract <Name> --args '[...]' --attach --sma <SMA>
|
|
52
|
+
```
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
[profile.default]
|
|
2
|
+
src = "."
|
|
3
|
+
out = "out"
|
|
4
|
+
libs = ["lib"]
|
|
5
|
+
remappings = ["@sail/interfaces/=interfaces/"]
|
|
6
|
+
solc = "0.8.26"
|
|
7
|
+
optimizer = true
|
|
8
|
+
optimizer_runs = 200
|
|
9
|
+
# Examples compile with: forge build (from this directory)
|
|
10
|
+
# Deploy within a Sailor project using: sailor mandate deploy --contract <Name> --args '[...]'
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
pragma solidity 0.8.26;
|
|
3
|
+
|
|
4
|
+
struct Context {
|
|
5
|
+
address account;
|
|
6
|
+
address manager;
|
|
7
|
+
address submitter;
|
|
8
|
+
address target;
|
|
9
|
+
bytes4 selector;
|
|
10
|
+
uint256 value;
|
|
11
|
+
uint256 blockTimestamp;
|
|
12
|
+
uint256 blockNumber;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
interface IPermission {
|
|
16
|
+
function evaluate(bytes calldata txData, Context calldata ctx) external view returns (bool);
|
|
17
|
+
function discriminator() external view returns (bytes32);
|
|
18
|
+
}
|