@dev.sail.money/sailor 0.0.2
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 +51202 -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
package/AGENTS.md
ADDED
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
# Sailor — Codebase Guide
|
|
2
|
+
|
|
3
|
+
Sailor is the operator toolkit for Sail Protocol. It does **not** deploy the protocol or author
|
|
4
|
+
permission templates — it targets already-deployed SailKernel instances and gives operators the
|
|
5
|
+
tooling to create SMAs, register permission contracts, and run strategy agents.
|
|
6
|
+
|
|
7
|
+
## Repo structure
|
|
8
|
+
|
|
9
|
+
| Package / path | Name | Role |
|
|
10
|
+
|---|---|---|
|
|
11
|
+
| `packages/sdk` | `@sail/sdk` | SailorClient, LocalKeyring, kernel ABIs, EIP-712 builders, deployment registry |
|
|
12
|
+
| `packages/cli` | `sailor` | CLI: init, keys, account, mandate, onboard, station, ui, run, session, scan, status, owner, doctor, capabilities |
|
|
13
|
+
| `packages/chains` | `@sail/chains` | Per-chain address registry (kernel, mandateFactory, governance) |
|
|
14
|
+
| `packages/ui` | `sailor-ui` | Local dashboard + browser-driven onboarding wizard at localhost:3333 |
|
|
15
|
+
| `templates/dca-rebalancer` | — | Default project scaffold: DCA rebalancer + Foundry workspace |
|
|
16
|
+
| `templates/custom-mandate` | — | Solidity reference: IPermission scaffold (not a project template) |
|
|
17
|
+
|
|
18
|
+
## Protocol roles
|
|
19
|
+
|
|
20
|
+
The code uses internal identifiers that differ from user-facing terms:
|
|
21
|
+
|
|
22
|
+
| User-facing term | Code identifier | Meaning |
|
|
23
|
+
|---|---|---|
|
|
24
|
+
| Owner | `owner` | Holds the Safe; custody anchor; never touches the agent runtime |
|
|
25
|
+
| Mandate signer | `permissionSigner` | Authorizes permission registration via EIP-712 |
|
|
26
|
+
| Agent wallet | `manager` | Signs dispatches; key at `.sail/keys/manager.json` |
|
|
27
|
+
|
|
28
|
+
Use the user-facing terms in all CLI output, prompts, and errors. The code identifiers are internal.
|
|
29
|
+
|
|
30
|
+
## Dispatch model
|
|
31
|
+
|
|
32
|
+
Active kernels vary by chain — verified on-chain via `DISPATCH_TYPEHASH()`:
|
|
33
|
+
|
|
34
|
+
| Chain | Kernel | Model | DISPATCH_TYPEHASH |
|
|
35
|
+
|---|---|---|---|
|
|
36
|
+
| Base 8453 | `0x6319d3dfDDe3804ba93D65752b00c52bFb05a1ab` | **selective** | `0xbe50c539...` |
|
|
37
|
+
| Base Sepolia 84532 | `0xf1D0F4C9893612627409948BAa9d82a01a373799` | **selective** | `0xbe50c539...` |
|
|
38
|
+
| Arbitrum 42161 | `0x2716B12832DED0EF5688519c5Fe069EFc0374E02` | **selective** | `0xbe50c539...` |
|
|
39
|
+
| Unichain 130 | `0xD985029960a9B7C2E7E38e102C448b8b8539B156` | **selective** | `0xbe50c539...` |
|
|
40
|
+
|
|
41
|
+
All four kernels are live and bootstrapped (genesis allowlist set, `createAccount` verified working, zero fees). Unichain (130) additionally has the full permission-template suite deployed and source-verified (7 shared + 12 standalone) — it is the only chain with templates so far; the other three have core only. `packages/sdk/src/deployments.ts` is the canonical source of truth for kernel addresses, templates, and metadata.
|
|
42
|
+
|
|
43
|
+
**Always use `detectKernelCapabilities` for the real model** — it reads the on-chain typehash and
|
|
44
|
+
overrides the static label in `deployments.ts`. The static label is a fallback for offline use only.
|
|
45
|
+
|
|
46
|
+
Type strings:
|
|
47
|
+
```
|
|
48
|
+
conjunctive: Dispatch(address account,address target,uint256 value,bytes32 dataHash,uint256 nonce,uint256 deadline)
|
|
49
|
+
selective: Dispatch(address account,address permission,address target,uint256 value,bytes32 dataHash,uint256 nonce,uint256 deadline)
|
|
50
|
+
|
|
51
|
+
conjunctive RegisterPermission: RegisterPermission(address account,address permission,uint256 nonce)
|
|
52
|
+
selective RegisterPermission: RegisterPermission(address account,address permission,uint256 nonce,uint256 deadline)
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
`buildRegisterPermissionTypedData` accepts `hasDeadline` from `KernelCapabilities.registerPermissionHasDeadline`.
|
|
56
|
+
Pass the detected value — never hardcode the type shape.
|
|
57
|
+
|
|
58
|
+
## Active addresses
|
|
59
|
+
|
|
60
|
+
All four chain records in `packages/sdk/src/deployments.ts` are live — no commented-out or pending
|
|
61
|
+
addresses remain. This file is the source of truth this guide mirrors.
|
|
62
|
+
|
|
63
|
+
- `packages/sdk/src/deployments.ts` — `SailDeployment` records; canonical source of truth
|
|
64
|
+
- `packages/chains/src/index.ts` — `ChainConfig` per chainId; kept in sync with deployments
|
|
65
|
+
|
|
66
|
+
## Key files
|
|
67
|
+
|
|
68
|
+
| File | What it owns |
|
|
69
|
+
|---|---|
|
|
70
|
+
| `packages/sdk/src/deployments.ts` | Active + PENDING addresses, `dispatchModel` per chain |
|
|
71
|
+
| `packages/sdk/src/capabilities.ts` | On-chain typehash detection; capability cache |
|
|
72
|
+
| `packages/sdk/src/eip712.ts` | `buildRegisterPermissionTypedData`, `REGISTER_PERMISSION_TYPES` |
|
|
73
|
+
| `packages/cli/src/commands/onboard.ts` | SMA creation + permission registration flow |
|
|
74
|
+
| `packages/cli/src/commands/mandate-contracts.ts` | Deploy / attach / revoke permission contracts |
|
|
75
|
+
| `packages/cli/src/lib/mandates.ts` | `MandateStore` — `.sail/state/mandates.json` source of truth |
|
|
76
|
+
| `packages/ui/server.js` | Local API + WebSocket proxy; signing station relay |
|
|
77
|
+
|
|
78
|
+
## Build
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
pnpm install
|
|
82
|
+
pnpm build # builds all packages; dependency order: sdk → chains → cli → ui
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
Build order matters — `cli` imports from `sdk` and `chains`.
|
|
86
|
+
|
|
87
|
+
## Test
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
pnpm test # vitest — no chain needed, ~1.3s
|
|
91
|
+
pnpm test:ui # playwright — requires pnpm build first
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
Test fixtures live in `packages/ui/test/fixtures/` — isolated directories with pre-canned `.sail/`
|
|
95
|
+
state; no real RPC needed.
|
|
96
|
+
|
|
97
|
+
## Conventions
|
|
98
|
+
|
|
99
|
+
- `SAIL_DIR` — env var pointing to the project's `.sail/` directory (used by the UI server)
|
|
100
|
+
- `SAIL_PASSPHRASE` — unlocks `.sail/keys/manager.json` headlessly; read from `.sail/.env.local`
|
|
101
|
+
- `SERVE_DIST=1` — makes the UI server serve the built React app at `/`
|
|
102
|
+
- All CLI commands support `--json` for machine-readable output
|
|
103
|
+
- Addresses in `.sail/` files stored checksummed; bigints as decimal strings
|
|
104
|
+
|
|
105
|
+
## What NOT to do
|
|
106
|
+
|
|
107
|
+
- Do not change active kernel/mandateFactory/governance addresses without confirming on-chain state
|
|
108
|
+
- Do not use conjunctive EIP-712 type strings in new code
|
|
109
|
+
- Do not add new root-level markdown files to this repo
|
|
110
|
+
- Always run `pnpm build` before `pnpm test:ui`
|
|
111
|
+
- Do not commit `SAIL_PASSPHRASE` or private keys
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Alejandro Dopico
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,337 @@
|
|
|
1
|
+
# Sailor
|
|
2
|
+
|
|
3
|
+
> A toolkit for building and operating Sail Protocol SMAs with AI agents.
|
|
4
|
+
|
|
5
|
+
Sailor is the operator layer for [Sail Protocol](../SailProtocol): the tooling an agent builder uses to create a Separately Managed Account, bound it with permissions, and run a strategy against it. It wraps the on-chain primitives — SailKernel dispatch, MandateFactory registration, EIP-712 mandate signing — behind a TypeScript SDK, a CLI, and a local dashboard. An agent is an async function that receives context and returns intended transactions; Sailor previews each through the kernel, executes the approved ones, and records what happened. It does not deploy the protocol or author new permission templates — that lives in Sail Protocol. It sits one level up: turning a deployed SailKernel into something an operator can actually drive.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## What's inside
|
|
10
|
+
|
|
11
|
+
| Package | Name | Role |
|
|
12
|
+
|---|---|---|
|
|
13
|
+
| `packages/sdk` | `@sail/sdk` | TypeScript library wrapping SailKernel and MandateFactory |
|
|
14
|
+
| `packages/cli` | `sailor` | CLI for account setup, mandate signing, and agent execution |
|
|
15
|
+
| `packages/chains` | `@sail/chains` | Per-chain address registry (EVM-compatible) |
|
|
16
|
+
| `packages/ui` | `sailor-ui` | Local dashboard running on localhost:3333 |
|
|
17
|
+
| `templates/dca-rebalancer` | — | Starter template: DCA portfolio rebalancer (default for `sailor init`) |
|
|
18
|
+
| `templates/custom-mandate` | — | Solidity reference: allowlist mandate contracts (not a project template) |
|
|
19
|
+
| `templates/lifi-permissions` | — | Solidity reference: LiFi clone permission contracts (not a project template) |
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## How it works
|
|
24
|
+
|
|
25
|
+
The path from nothing to a running agent is seven steps:
|
|
26
|
+
|
|
27
|
+
1. **Generate keys** — a manager key (the agent's dispatch signer) and a permissionSigner key, both generated and encrypted on disk.
|
|
28
|
+
2. **Deploy SMA** — a Safe registered with SailKernel, with the manager and permissionSigner addresses set at registration.
|
|
29
|
+
3. **Write a strategy** — an async `tick` function that receives a context and returns a list of intended dispatches.
|
|
30
|
+
4. **Sign a mandate** — a set of registered permissions that bound what the agent can do, authorized via EIP-712 by the permission signer through MetaMask or a local key.
|
|
31
|
+
5. **Dry-run** — the kernel's `previewBatch` confirms the named permission passes before anything executes on-chain.
|
|
32
|
+
6. **Run the agent** — locally on a cron schedule, or via GitHub Actions on a timer.
|
|
33
|
+
7. **Monitor** — the local dashboard on localhost:3333 reflects live mandate state, agent status, and activity.
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
## Roles
|
|
38
|
+
|
|
39
|
+
Sailor operates the three roles Sail Protocol separates:
|
|
40
|
+
|
|
41
|
+
| Role | Authority | Held by |
|
|
42
|
+
|---|---|---|
|
|
43
|
+
| **Owner** | Holds the Safe. Custody anchor. | The LP (Safe owner) — same wallet as MetaMask |
|
|
44
|
+
| **Permission Signer** | Signs mandate registration and revocation via EIP-712. | Same as Owner, or a separate key |
|
|
45
|
+
| **Manager** | Executes dispatches within permitted bounds. Signs each dispatch. | The agent key — encrypted in `.sail/keys/manager.json` |
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## Installation
|
|
50
|
+
|
|
51
|
+
### Start a new agent project (recommended)
|
|
52
|
+
|
|
53
|
+
Open your AI coding assistant and run in its terminal:
|
|
54
|
+
|
|
55
|
+
```sh
|
|
56
|
+
npx sailor init my-agent
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Then say **"start"** — your assistant takes it from there.
|
|
60
|
+
|
|
61
|
+
### Global CLI (for direct sailor commands)
|
|
62
|
+
|
|
63
|
+
```sh
|
|
64
|
+
npm install -g @sail.money/sailor
|
|
65
|
+
sailor init my-agent
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
## Quickstart
|
|
71
|
+
|
|
72
|
+
Prerequisites:
|
|
73
|
+
|
|
74
|
+
- Node.js 18+ (the CLI runs on 18; `pnpm install` needs Node 22+)
|
|
75
|
+
- A wallet (MetaMask or Rabby)
|
|
76
|
+
- An RPC URL (e.g. Alchemy free tier)
|
|
77
|
+
- A supported chain: **Base, Base Sepolia, Arbitrum, or Unichain** — these use the verified deployments bundled in `@sail/sdk`, so no `@sail/chains` entry is needed. Other chains require kernel + mandateFactory addresses in `@sail/chains` (see [State of the project](#state-of-the-project)).
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
npx sailor init my-agent && cd my-agent
|
|
81
|
+
npm install # or `pnpm install` (needs Node 22+)
|
|
82
|
+
|
|
83
|
+
# 1. Ground yourself — read-only, no gas, no wallet:
|
|
84
|
+
sailor capabilities # what you can build on this chain
|
|
85
|
+
sailor doctor # kernel model + RPC reachability + gas balances
|
|
86
|
+
|
|
87
|
+
# 2. Set up the account in the browser wizard (choose chain, connect wallet,
|
|
88
|
+
# generate the agent key, deploy your SMA):
|
|
89
|
+
sailor ui start # open http://localhost:3333 and follow steps 1–4
|
|
90
|
+
|
|
91
|
+
# 3. Back in the terminal: configure .sail/.env.local, fund the agent key for gas,
|
|
92
|
+
sailor mandate prepare # draft permissions → approve in the browser
|
|
93
|
+
sailor run # start the agent (use --once for a single tick)
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
The SMA is deployed through the browser wizard (it submits from your wallet), not a
|
|
97
|
+
terminal command — see the scaffolded project's `AGENTS.md` for the full 8-step flow.
|
|
98
|
+
|
|
99
|
+
---
|
|
100
|
+
|
|
101
|
+
## Templates
|
|
102
|
+
|
|
103
|
+
`sailor init` scaffolds a new agent project from a template. By default it
|
|
104
|
+
writes into the **current directory**; pass a name to create a subdirectory.
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
sailor init # scaffold into cwd
|
|
108
|
+
sailor init my-agent # create ./my-agent/ and scaffold there
|
|
109
|
+
sailor init --template dca-rebalancer # explicit (same as default)
|
|
110
|
+
sailor init my-agent --template <name> # named subdirectory + specific template
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### Available templates
|
|
114
|
+
|
|
115
|
+
| Template | Description |
|
|
116
|
+
|---|---|
|
|
117
|
+
| `dca-rebalancer` | Dollar-cost-averaging portfolio rebalancer. Includes a full agent loop, Foundry workspace for permission contracts, GitHub Actions cron job, and the operator guide (`AGENTS.md`). **Default.** |
|
|
118
|
+
|
|
119
|
+
### What makes a valid template
|
|
120
|
+
|
|
121
|
+
A valid template is any directory under `templates/` that contains a
|
|
122
|
+
`package.json`. Directories without one (e.g. `custom-mandate`,
|
|
123
|
+
`lifi-permissions`) are Solidity reference sources, not project scaffolds, and
|
|
124
|
+
are excluded from the available list.
|
|
125
|
+
|
|
126
|
+
### Adding a template
|
|
127
|
+
|
|
128
|
+
1. Create a directory under `templates/<your-template-name>/`.
|
|
129
|
+
2. Add a `package.json` (the `name` field is patched to the project name on
|
|
130
|
+
init).
|
|
131
|
+
3. Add a `.sail/` workspace structure if the agent needs local state.
|
|
132
|
+
4. The template will appear automatically in `sailor init --template <name>`.
|
|
133
|
+
|
|
134
|
+
Template files are bundled into the published `sailor` npm package via the
|
|
135
|
+
`files` field in the root `package.json`.
|
|
136
|
+
|
|
137
|
+
---
|
|
138
|
+
|
|
139
|
+
## Dashboard (`sailor ui`)
|
|
140
|
+
|
|
141
|
+
The Sailor dashboard is a local React app served at `http://localhost:3333`.
|
|
142
|
+
It shows live account state, mandate health, signer balances, and recent
|
|
143
|
+
activity — all read from the project's `.sail/` directory with no hosted
|
|
144
|
+
backend.
|
|
145
|
+
|
|
146
|
+
### Commands
|
|
147
|
+
|
|
148
|
+
```bash
|
|
149
|
+
sailor ui # start the dashboard (same as sailor ui start)
|
|
150
|
+
sailor ui start # start the dashboard at http://localhost:3333
|
|
151
|
+
sailor ui stop # stop the running dashboard
|
|
152
|
+
sailor ui status # show whether the dashboard is running + pid
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
### How it works
|
|
156
|
+
|
|
157
|
+
`sailor ui start` spawns a bundled Express server (`server.cjs`) that:
|
|
158
|
+
|
|
159
|
+
- Serves the pre-built React UI as static files on `/`
|
|
160
|
+
- Exposes a local API on `/api` that reads `.sail/` state from the current
|
|
161
|
+
working directory
|
|
162
|
+
|
|
163
|
+
The server PID is written to `.sail/runtime/ui.json` on start. `sailor ui stop`
|
|
164
|
+
reads that file, sends `SIGTERM` to the server process, and removes the file.
|
|
165
|
+
This means you can start the dashboard in one terminal and stop it from another.
|
|
166
|
+
|
|
167
|
+
### Running in the background
|
|
168
|
+
|
|
169
|
+
```bash
|
|
170
|
+
# macOS / Linux
|
|
171
|
+
sailor ui start &
|
|
172
|
+
sailor ui status # ● running http://localhost:3333 (pid 12345)
|
|
173
|
+
sailor ui stop # Stopped Sailor UI (pid 12345).
|
|
174
|
+
|
|
175
|
+
# Windows (PowerShell)
|
|
176
|
+
Start-Job { sailor ui start }
|
|
177
|
+
sailor ui status
|
|
178
|
+
sailor ui stop
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
---
|
|
182
|
+
|
|
183
|
+
## Agent-driven onboarding & custom mandates
|
|
184
|
+
|
|
185
|
+
For chains with a bundled Sail deployment (Base, Base Sepolia, Arbitrum, Unichain — shipped
|
|
186
|
+
in `@sail/sdk`, no `@sail/chains` entry required), an agent can drive the whole
|
|
187
|
+
setup through a browser **signing station**. The station is a local HTTP +
|
|
188
|
+
WebSocket daemon that bridges the CLI and the owner's wallet: the agent never
|
|
189
|
+
holds the owner key — it pushes signing requests, the owner approves them in the
|
|
190
|
+
browser, and the agent submits the transactions it's allowed to.
|
|
191
|
+
|
|
192
|
+
```bash
|
|
193
|
+
sailor keys generate # manager (agent) key
|
|
194
|
+
sailor station start & # signing daemon (serves the UI)
|
|
195
|
+
# owner opens the printed URL once and connects their wallet
|
|
196
|
+
sailor owner connect # detect & persist the owner
|
|
197
|
+
sailor scan # discover the owner's Safes + state
|
|
198
|
+
sailor onboard --new-sma # create an SMA + (optionally) attach a mandate
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
Agents author their own permission contracts and deploy them from the scaffolded
|
|
202
|
+
Foundry workspace (`mandates/`, with `@sail/interfaces/IPermission.sol` vendored
|
|
203
|
+
under `.sail/contracts/`):
|
|
204
|
+
|
|
205
|
+
```bash
|
|
206
|
+
forge build
|
|
207
|
+
sailor mandate deploy --contract MyMandate \
|
|
208
|
+
--args '["0xPermissionSigner", ["0xTarget"]]' \
|
|
209
|
+
--attach --sma 0xSafe
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
`deploy` emits a contract-creation signing request (the owner signs it in the
|
|
213
|
+
browser); the deployed address is read from the receipt and tracked in
|
|
214
|
+
`.sail/state/mandates.json`. `attach` reads the signer nonce, has the owner sign
|
|
215
|
+
a `RegisterPermission` EIP-712 message, then the agent submits
|
|
216
|
+
`kernel.registerPermission` with the exact registration fee. Every command takes
|
|
217
|
+
`--json` for headless agent use; set `SAIL_PASSPHRASE` to unlock the manager key
|
|
218
|
+
non-interactively.
|
|
219
|
+
|
|
220
|
+
---
|
|
221
|
+
|
|
222
|
+
## Architecture
|
|
223
|
+
|
|
224
|
+
```
|
|
225
|
+
┌────────────────────┐ ┌────────────────────┐
|
|
226
|
+
│ Permission Signer │ │ Manager/Agent │
|
|
227
|
+
│ MetaMask / local │ │ .sail/keys/manager │
|
|
228
|
+
└─────────┬──────────┘ └─────────┬──────────┘
|
|
229
|
+
│ │
|
|
230
|
+
│ EIP-712 mandate │ dispatch
|
|
231
|
+
▼ ▼
|
|
232
|
+
┌─────────────────────────────────────────────────────────────────────┐
|
|
233
|
+
│ SailKernel │
|
|
234
|
+
│ (Sail Protocol) │
|
|
235
|
+
└─────────┬───────────────────────┬───────────────────────┬───────────┘
|
|
236
|
+
│ │ │
|
|
237
|
+
│ registration │ execution │ evaluation
|
|
238
|
+
▼ ▼ ▼
|
|
239
|
+
┌────────────────────┐ ┌────────────────────┐ ┌────────────────────┐
|
|
240
|
+
│ MandateFactory │ │ Safe │ │ Permissions │
|
|
241
|
+
│ (register perms) │ │ (custody) │ │ (named, per-call) │
|
|
242
|
+
└────────────────────┘ └────────────────────┘ └────────────────────┘
|
|
243
|
+
|
|
244
|
+
sailor CLI / @sail/sdk drive both signing paths above.
|
|
245
|
+
.sail/ (account · mandate · activity) ──→ sailor-ui (localhost:3333)
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
The CLI and SDK sit between the operator and SailKernel: they build the EIP-712 payloads, submit dispatches, and read kernel state via viem. The permission signer authorizes the mandate — registration runs through MandateFactory — while the manager key signs each dispatch the kernel evaluates against a named permission before executing it through the Safe. All local state — the deployed account, the signed mandate, and the agent's activity log — lives under `.sail/` on disk, which the dashboard reads through a small local server. Sailor never holds the Owner key and runs no hosted backend; the wallet talks to the chain directly.
|
|
249
|
+
|
|
250
|
+
---
|
|
251
|
+
|
|
252
|
+
## Security model
|
|
253
|
+
|
|
254
|
+
- The agent signs dispatches; the kernel evaluates the named permission on every call. A permission returning false or exceeding its gas cap is treated as denial — fail-closed.
|
|
255
|
+
- The Owner key controls the Safe and is never read by Sailor. Mandate signing requires a deliberate action by the permission signer.
|
|
256
|
+
- The manager key is encrypted on disk using geth keystore v3 (scrypt + aes-128-ctr) and is never transmitted.
|
|
257
|
+
- The session can be paused instantly via `sailor session pause` or the dashboard stop button; this does not affect Safe custody.
|
|
258
|
+
|
|
259
|
+
---
|
|
260
|
+
|
|
261
|
+
## State of the project
|
|
262
|
+
|
|
263
|
+
Sailor is functional and published as [`@sail.money/sailor`](https://www.npmjs.com/package/@sail.money/sailor) on npm (v0.0.1). The SDK, CLI, keystore, mandate flows, agent runner, and dashboard are implemented and have been exercised end to end against Base Sepolia.
|
|
264
|
+
|
|
265
|
+
The Sail Protocol trusted core is deployed on Base, Base Sepolia, Arbitrum, and Unichain as staging deployments for testing ahead of a formal launch. All four run the selective dispatch model, with verified deployments bundled in `@sail/sdk`. These deployments are under an ongoing external audit by [Octane Security](https://octane.security) and are not final — do not use them with funds you are not prepared to lose. Permission templates are not yet deployed against the Base, Arbitrum, and Base Sepolia kernels; **Unichain** ships the full template suite (7 shared + 12 standalone, source-verified) and its template registries in `@sail/sdk` are populated. `@sail/chains` and the remaining template registries will be filled in as templates are deployed on the other chains and at mainnet launch.
|
|
266
|
+
|
|
267
|
+
---
|
|
268
|
+
|
|
269
|
+
## Deployments
|
|
270
|
+
|
|
271
|
+
The Sail Protocol trusted core is live on the following chains as **staging deployments** ahead of a formal launch, bundled in `@sail/sdk`. All run the selective dispatch model with zero fees. Permission templates are not yet deployed against the Base, Arbitrum, and Base Sepolia kernels; **Unichain** ships the full template suite (7 shared + 12 standalone, source-verified on uniscan.xyz) and has its onboarding allowlists seeded at genesis.
|
|
272
|
+
|
|
273
|
+
### Base (8453)
|
|
274
|
+
|
|
275
|
+
| Contract | Address |
|
|
276
|
+
|---|---|
|
|
277
|
+
| SailKernel | `0x6319d3dfDDe3804ba93D65752b00c52bFb05a1ab` |
|
|
278
|
+
| SailGovernance | `0x7E897D919872b1587577617ffFC42113679d0C50` |
|
|
279
|
+
| Timelock | `0x8eC3Ca951E193C6E3713A70022454d7A1f083281` |
|
|
280
|
+
| PermissionFactory | `0x7724EACd97C8601d5AC244Aadbf76ad87353Ff31` |
|
|
281
|
+
| StandardFeePolicy | `0x65850a8D5050aeAade68289ff96c4F119a24B82e` |
|
|
282
|
+
| SafeModuleEnabler | `0xC84EdE78f93291A1fab19F51c4c7e938AB302Edf` |
|
|
283
|
+
| Treasury | `0xB01dCE443d052e44b7D13726c0EC9fFB7f5815B6` |
|
|
284
|
+
|
|
285
|
+
### Arbitrum (42161)
|
|
286
|
+
|
|
287
|
+
| Contract | Address |
|
|
288
|
+
|---|---|
|
|
289
|
+
| SailKernel | `0x2716B12832DED0EF5688519c5Fe069EFc0374E02` |
|
|
290
|
+
| SailGovernance | `0xd6AbB7A1036ADc7958Abffec9Da03450c5a2Ec8e` |
|
|
291
|
+
| Timelock | `0x114CB7110C780f7E3a6093AfE0B52463a569857C` |
|
|
292
|
+
| PermissionFactory | `0x23681A8A4C9819D8EaB37E46B858da6F3c85E683` |
|
|
293
|
+
| StandardFeePolicy | `0xAdfB986D48480bC67a7cF3751d30599161632e0D` |
|
|
294
|
+
| SafeModuleEnabler | `0xabe2a6D03F592BC602cA1dBDCD885ba2493274f9` |
|
|
295
|
+
| Treasury | `0xB01dCE443d052e44b7D13726c0EC9fFB7f5815B6` |
|
|
296
|
+
|
|
297
|
+
### Base Sepolia (84532)
|
|
298
|
+
|
|
299
|
+
| Contract | Address |
|
|
300
|
+
|---|---|
|
|
301
|
+
| SailKernel | `0xf1D0F4C9893612627409948BAa9d82a01a373799` |
|
|
302
|
+
| SailGovernance | `0xEaD44bC6999E7b00b9b2E11c1660248DC2a30993` |
|
|
303
|
+
| Timelock | `0x97B863e392C9859336788D5Ec454527d33C95B74` |
|
|
304
|
+
| PermissionFactory | `0xdfF6a2272F667cDf78Af4681b9c88A219998db95` |
|
|
305
|
+
| StandardFeePolicy | `0x05570F7973b46Eb9Ed4518422891EFC26BD58b97` |
|
|
306
|
+
| SafeModuleEnabler | `0xB2C2B52d94412e3472C9fb2B52186eA12a935869` |
|
|
307
|
+
| Treasury | `0xB01dCE443d052e44b7D13726c0EC9fFB7f5815B6` |
|
|
308
|
+
|
|
309
|
+
### Unichain (130)
|
|
310
|
+
|
|
311
|
+
First chain to ship the full permission-template suite (7 shared + 12 standalone, source-verified on [uniscan.xyz](https://uniscan.xyz)). Genesis allowlist bootstrap — onboarding usable without the 48h timelock.
|
|
312
|
+
|
|
313
|
+
| Contract | Address |
|
|
314
|
+
|---|---|
|
|
315
|
+
| SailKernel | `0xD985029960a9B7C2E7E38e102C448b8b8539B156` |
|
|
316
|
+
| SailGovernance | `0xAb5C90ECfF2763f6f20f8E553E3b8778dD9C349A` |
|
|
317
|
+
| Timelock | `0xd44FbBB37f01e235E0EE5386948F216d36D0CEf2` |
|
|
318
|
+
| PermissionFactory | `0x8edDb62Aa49CeB837abf2653be2d93Ad9Fe6777D` |
|
|
319
|
+
| StandardFeePolicy | `0x7bBA8BE3c01c972757aA4a230A00D58aB600A1F1` |
|
|
320
|
+
| SafeModuleEnabler | `0xFE9227A9F2baf704060c604466df354a5A137b9B` |
|
|
321
|
+
| Treasury | `0xB01dCE443d052e44b7D13726c0EC9fFB7f5815B6` |
|
|
322
|
+
|
|
323
|
+
The 19 template addresses are in `@sail/sdk` (`knownTemplates` + `standaloneTemplates` for chain 130).
|
|
324
|
+
|
|
325
|
+
Addresses are sourced from `@sail/sdk` (`packages/sdk/src/deployments.ts`), the canonical registry.
|
|
326
|
+
|
|
327
|
+
---
|
|
328
|
+
|
|
329
|
+
## Contributing
|
|
330
|
+
|
|
331
|
+
Sailor and Sail Protocol are separate repositories with separate concerns. Protocol questions — SailKernel internals, permission templates, MandateFactory, fee policies — belong in the [SailProtocol](../SailProtocol) repository. Sailor questions — the SDK, CLI, dashboard, and agent templates — belong here.
|
|
332
|
+
|
|
333
|
+
---
|
|
334
|
+
|
|
335
|
+
## License
|
|
336
|
+
|
|
337
|
+
MIT
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
# Sail permission model: conjunctive vs selective
|
|
2
|
+
|
|
3
|
+
The deployed SailKernel ships in **two incompatible dispatch models**. Which one a
|
|
4
|
+
chain runs changes how dispatches are signed *and* how permissions must be written.
|
|
5
|
+
Get this wrong and every dispatch reverts with an opaque selector. This is the single
|
|
6
|
+
most important thing to understand before operating an SMA.
|
|
7
|
+
|
|
8
|
+
## TL;DR
|
|
9
|
+
|
|
10
|
+
| | **Conjunctive** (older) | **Selective** (newer) |
|
|
11
|
+
|---|---|---|
|
|
12
|
+
| Chains today (bundled kernels) | None — all bundled kernels moved to selective | Base (8453), Base Sepolia (84532), Arbitrum (42161), Unichain (130) |
|
|
13
|
+
| `dispatch(...)` | `(account, target, value, data, sig, deadline)` — **no `permission`** | `(account, permission, target, value, data, sig, deadline)` |
|
|
14
|
+
| Which permissions are checked | **ALL** registered permissions; **all must return true** | only the **one** permission named in the call |
|
|
15
|
+
| EIP-712 `Dispatch` struct | no `permission` field | includes `permission` |
|
|
16
|
+
| Batch (`dispatchBatch`/`previewBatch`) | **not available** | available |
|
|
17
|
+
| **Permission design rule** | **MUST pass through calls outside its domain** | may return false freely |
|
|
18
|
+
|
|
19
|
+
Don't guess from a version string — **detect it on-chain** (see below).
|
|
20
|
+
|
|
21
|
+
## The conjunctive pass-through rule (the big footgun)
|
|
22
|
+
|
|
23
|
+
On a conjunctive kernel the kernel calls `evaluate(txData, ctx)` on **every**
|
|
24
|
+
registered permission and ANDs the results. A single `false` blocks the whole
|
|
25
|
+
dispatch (`PermissionDenied`).
|
|
26
|
+
|
|
27
|
+
So a permission that only cares about, say, approvals **must still return `true` for
|
|
28
|
+
every call it doesn't govern**:
|
|
29
|
+
|
|
30
|
+
```solidity
|
|
31
|
+
function evaluate(bytes calldata txData, Context calldata ctx) external view returns (bool) {
|
|
32
|
+
// Pass through calls outside this permission's domain (conjunctive model).
|
|
33
|
+
if (ctx.selector != APPROVE) return true; // <-- without this line, this
|
|
34
|
+
// permission bricks swaps,
|
|
35
|
+
// transfers, everything.
|
|
36
|
+
// ...domain-specific checks for approve...
|
|
37
|
+
}
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
A permission that returns `false` (or reverts, or runs out of gas — both treated as
|
|
41
|
+
`false`) on unrelated calls **bricks the entire account**: no dispatch of any kind
|
|
42
|
+
can pass. We hit exactly this during bring-up with permissions that "blocked each
|
|
43
|
+
other." The fix was to redeploy every permission with pass-through semantics.
|
|
44
|
+
|
|
45
|
+
Corollary: on a conjunctive kernel you **cannot** have two permissions that each
|
|
46
|
+
enforce a different token's approve — each would reject the other's token. To support
|
|
47
|
+
approving both DAI and USDC you need **one** approve permission that allows both (see
|
|
48
|
+
`templates/lifi-permissions/`), not two narrow ones.
|
|
49
|
+
|
|
50
|
+
Selective kernels don't have this problem: each dispatch names one permission and
|
|
51
|
+
only that one is consulted.
|
|
52
|
+
|
|
53
|
+
## Detect the model on-chain
|
|
54
|
+
|
|
55
|
+
The SDK reads each kernel's public `DISPATCH_TYPEHASH` constant and matches it
|
|
56
|
+
against the canonical hashes for each model. Never assume.
|
|
57
|
+
|
|
58
|
+
```ts
|
|
59
|
+
const caps = await client.capabilities();
|
|
60
|
+
// caps.dispatchModel: "conjunctive" | "selective"
|
|
61
|
+
// caps.dispatchTypehash, caps.source ("onchain-typehash" | "static-hint")
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Verified typehashes:
|
|
65
|
+
|
|
66
|
+
- conjunctive `DISPATCH_TYPEHASH` = `0x7510c80e…`
|
|
67
|
+
`Dispatch(address account,address target,uint256 value,bytes32 dataHash,uint256 nonce,uint256 deadline)`
|
|
68
|
+
- selective `DISPATCH_TYPEHASH` =
|
|
69
|
+
`Dispatch(address account,address permission,address target,uint256 value,bytes32 dataHash,uint256 nonce,uint256 deadline)`
|
|
70
|
+
|
|
71
|
+
`client.dispatch.single(...)` already signs the correct struct and uses the correct
|
|
72
|
+
ABI for the detected model — you don't sign by hand. `client.dispatch.batch` /
|
|
73
|
+
`preview` throw a clear error on conjunctive kernels (no `dispatchBatch`).
|
|
74
|
+
|
|
75
|
+
## Roles (unchanged across models)
|
|
76
|
+
|
|
77
|
+
| Role | Authority |
|
|
78
|
+
|------|-----------|
|
|
79
|
+
| **Owner** | Holds the Safe; custody anchor. |
|
|
80
|
+
| **Permission Signer** | Authorizes which `IPermission` contracts apply (EIP-712 `RegisterPermissions` / `RevokePermissions`). Signed in the browser signing station — the agent never holds this key. |
|
|
81
|
+
| **Manager** | Executes dispatches within the registered permissions (ECDSA / ERC-1271). The agent's hot key. |
|
|
82
|
+
|
|
83
|
+
## Preflight before spending gas
|
|
84
|
+
|
|
85
|
+
Run `sailor doctor` (read-only, no gas, no keys):
|
|
86
|
+
|
|
87
|
+
- detects the dispatch model,
|
|
88
|
+
- lists registered permissions,
|
|
89
|
+
- on a conjunctive kernel, **probes each permission for pass-through** and flags any
|
|
90
|
+
that would brick dispatch.
|
|
91
|
+
|
|
92
|
+
See [AGENTS.md](../AGENTS.md) for the operational decision tree and the
|
|
93
|
+
revert failure-mode catalog.
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
pragma solidity 0.8.26;
|
|
3
|
+
|
|
4
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
5
|
+
// Protocol : Limitless
|
|
6
|
+
// Version : CTF-based prediction market (on-chain settlement on Base)
|
|
7
|
+
// NOT Polymarket (Polymarket's CLOB matches orders off-chain on Polygon —
|
|
8
|
+
// a permission cannot bound the orders your agent signs off-chain.
|
|
9
|
+
// Limitless settles bets on-chain on Base, so the kernel sees every action.)
|
|
10
|
+
// Chain : Base mainnet
|
|
11
|
+
//
|
|
12
|
+
// ⚠ WARNING — ABI UNVERIFIED ⚠
|
|
13
|
+
// The Limitless exchange contract address and bet-placement function signature
|
|
14
|
+
// below are based on published CTF exchange patterns and public documentation.
|
|
15
|
+
// They have NOT been independently verified against the deployed contracts.
|
|
16
|
+
// YOU MUST verify these before deploying with real funds:
|
|
17
|
+
// 1. Find the Limitless exchange contract address on Basescan.
|
|
18
|
+
// 2. Read its verified ABI and confirm the buy/place function signature.
|
|
19
|
+
// 3. Recompute the selector and update SEL_BUY.
|
|
20
|
+
// 4. Confirm the parameter layout matches BetParams below.
|
|
21
|
+
// Deploying this contract with an unverified ABI may silently PASS or FAIL
|
|
22
|
+
// all dispatches depending on whether the selector matches.
|
|
23
|
+
//
|
|
24
|
+
// ENFORCED ON-CHAIN (assuming verified ABI — see warning above):
|
|
25
|
+
// buy(bytes32 conditionId, uint256 amount, uint256 outcomeIndex)
|
|
26
|
+
// • target must be LIMITLESS_EXCHANGE
|
|
27
|
+
// • conditionId must be in ALLOWED_CONDITIONS
|
|
28
|
+
// • amount ≤ MAX_STAKE
|
|
29
|
+
// • outcomeIndex must be in ALLOWED_OUTCOMES
|
|
30
|
+
//
|
|
31
|
+
// NOT ENFORCED:
|
|
32
|
+
// • Market price / odds (on-chain prediction market prices fluctuate)
|
|
33
|
+
// • Timing / frequency of bets
|
|
34
|
+
//
|
|
35
|
+
// VERIFY BEFORE USE:
|
|
36
|
+
// • Confirm Limitless exchange address on Base (Basescan).
|
|
37
|
+
// • Confirm buy function signature and compute selector:
|
|
38
|
+
// keccak256("buy(bytes32,uint256,uint256)")[0:4] == 0x??? — verify on-chain.
|
|
39
|
+
// • Confirm conditionId encoding matches the deployed market IDs.
|
|
40
|
+
// • Update this contract if the ABI or parameter order differs.
|
|
41
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
42
|
+
|
|
43
|
+
import {IPermission, Context} from "@sail/interfaces/IPermission.sol";
|
|
44
|
+
|
|
45
|
+
contract BoundedBet_Limitless_Base is IPermission {
|
|
46
|
+
bytes32 private constant DISCRIMINATOR = keccak256("BoundedBet_Limitless_Base");
|
|
47
|
+
|
|
48
|
+
/// @dev ⚠ UNVERIFIED — replace with verified Limitless exchange address on Base.
|
|
49
|
+
address public immutable LIMITLESS_EXCHANGE;
|
|
50
|
+
mapping(bytes32 => bool) public isAllowedCondition;
|
|
51
|
+
uint256 public immutable MAX_STAKE;
|
|
52
|
+
mapping(uint256 => bool) public isAllowedOutcome;
|
|
53
|
+
|
|
54
|
+
/// @dev ⚠ UNVERIFIED selector. Compute keccak256("buy(bytes32,uint256,uint256)")[0:4]
|
|
55
|
+
/// and confirm it matches the deployed Limitless exchange contract before use.
|
|
56
|
+
bytes4 private constant SEL_BUY = bytes4(keccak256("buy(bytes32,uint256,uint256)"));
|
|
57
|
+
|
|
58
|
+
/// @param limitlessExchange ⚠ VERIFY — Limitless CTF exchange address on Base
|
|
59
|
+
/// @param allowedConditions conditionIds (bytes32) of markets the agent may bet on
|
|
60
|
+
/// @param maxStake Per-bet stake cap in collateral base units
|
|
61
|
+
/// @param allowedOutcomes Outcome indices the agent may select (e.g. [0] for YES only)
|
|
62
|
+
constructor(
|
|
63
|
+
address limitlessExchange,
|
|
64
|
+
bytes32[] memory allowedConditions,
|
|
65
|
+
uint256 maxStake,
|
|
66
|
+
uint256[] memory allowedOutcomes
|
|
67
|
+
) {
|
|
68
|
+
LIMITLESS_EXCHANGE = limitlessExchange;
|
|
69
|
+
MAX_STAKE = maxStake;
|
|
70
|
+
for (uint256 i = 0; i < allowedConditions.length; i++) {
|
|
71
|
+
isAllowedCondition[allowedConditions[i]] = true;
|
|
72
|
+
}
|
|
73
|
+
for (uint256 i = 0; i < allowedOutcomes.length; i++) {
|
|
74
|
+
isAllowedOutcome[allowedOutcomes[i]] = true;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function evaluate(bytes calldata txData, Context calldata ctx) external view returns (bool) {
|
|
79
|
+
if (ctx.target != LIMITLESS_EXCHANGE) return false;
|
|
80
|
+
if (ctx.selector != SEL_BUY) return false;
|
|
81
|
+
if (txData.length < 4 + 3 * 32) return false;
|
|
82
|
+
|
|
83
|
+
// ⚠ Assumes: buy(bytes32 conditionId, uint256 amount, uint256 outcomeIndex)
|
|
84
|
+
// Verify parameter order against deployed contract ABI before use.
|
|
85
|
+
(bytes32 conditionId, uint256 amount, uint256 outcomeIndex) =
|
|
86
|
+
abi.decode(txData[4:], (bytes32, uint256, uint256));
|
|
87
|
+
|
|
88
|
+
if (!isAllowedCondition[conditionId]) return false;
|
|
89
|
+
if (amount > MAX_STAKE) return false;
|
|
90
|
+
if (!isAllowedOutcome[outcomeIndex]) return false;
|
|
91
|
+
|
|
92
|
+
return true;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function discriminator() external pure returns (bytes32) { return DISCRIMINATOR; }
|
|
96
|
+
}
|