@t2000/sdk 4.0.0 → 4.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/README.md +16 -211
- package/dist/adapters/index.cjs +0 -1
- package/dist/adapters/index.cjs.map +1 -1
- package/dist/adapters/index.js +0 -1
- package/dist/adapters/index.js.map +1 -1
- package/dist/browser.cjs +0 -1
- package/dist/browser.cjs.map +1 -1
- package/dist/browser.d.cts +1 -1
- package/dist/browser.d.ts +1 -1
- package/dist/browser.js +0 -1
- package/dist/browser.js.map +1 -1
- package/dist/index.cjs +54 -14
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +17 -7
- package/dist/index.d.ts +17 -7
- package/dist/index.js +54 -14
- package/dist/index.js.map +1 -1
- package/dist/{types-_U9XXGFR.d.ts → types-B63ogqZZ.d.ts} +1 -1
- package/dist/{types-CqpN8a8R.d.cts → types-CIclvR39.d.cts} +1 -1
- package/package.json +1 -1
package/dist/browser.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/errors.ts","../src/token-registry.ts","../src/wallet/keypairSigner.ts","../src/wallet/zkLoginSigner.ts","../src/browser.ts","../src/constants.ts","../src/utils/sui.ts","../src/wallet/classify.ts","../src/wallet/history.ts","../src/utils/format.ts","../src/utils/base64.ts","../src/protocols/protocolFee.ts","../src/protocols/cetus-swap.ts","../src/safeguards/errors.ts","../src/safeguards/types.ts"],"names":["T2000Error"],"mappings":";;;;;;;;;;;;;;;;;AAAA,IAAA,cAAA,GAAA,EAAA;AAAA,QAAA,CAAA,cAAA,EAAA;AAAA,EAAA,UAAA,EAAA,MAAA,UAAA;AAAA,EAAA,WAAA,EAAA,MAAA,WAAA;AAAA,EAAA,gBAAA,EAAA,MAAA,gBAAA;AAAA,EAAA,cAAA,EAAA,MAAA,cAAA;AAAA,EAAA,qBAAA,EAAA,MAAA;AAAA,CAAA,CAAA;AAiEO,SAAS,eAAe,KAAA,EAA4B;AACzD,EAAA,MAAM,MAAM,KAAA,YAAiB,KAAA,GAAQ,KAAA,CAAM,OAAA,GAAU,OAAO,KAAK,CAAA;AAEjE,EAAA,IAAI,IAAI,QAAA,CAAS,UAAU,KAAK,GAAA,CAAI,QAAA,CAAS,WAAW,CAAA,EAAG;AACzD,IAAA,OAAO,IAAI,UAAA,CAAW,oBAAA,EAAsB,uBAAuB,CAAA;AAAA,EACrE;AACA,EAAA,IAAI,IAAI,QAAA,CAAS,cAAc,KAAK,GAAA,CAAI,QAAA,CAAS,cAAc,CAAA,EAAG;AAChE,IAAA,OAAO,IAAI,UAAA,CAAW,sBAAA,EAAwB,sBAAsB,CAAA;AAAA,EACtE;AAEA,EAAA,OAAO,IAAI,UAAA,CAAW,SAAA,EAAW,GAAA,EAAK,QAAW,IAAI,CAAA;AACvD;AAEO,SAAS,iBAAiB,IAAA,EAAsB;AACrD,EAAA,MAAM,aAAA,GAAwC;AAAA,IAC5C,CAAA,EAAG,gCAAA;AAAA,IACH,CAAA,EAAG,kCAAA;AAAA,IACH,CAAA,EAAG,wBAAA;AAAA,IACH,CAAA,EAAG,0BAAA;AAAA,IACH,CAAA,EAAG,+BAAA;AAAA,IACH,CAAA,EAAG,gBAAA;AAAA,IACH,CAAA,EAAG,kDAAA;AAAA,IACH,CAAA,EAAG,2CAAA;AAAA,IACH,CAAA,EAAG,8BAAA;AAAA,IACH,EAAA,EAAI,4BAAA;AAAA;AAAA,IAEJ,IAAA,EAAM,oDAAA;AAAA,IACN,IAAA,EAAM,2FAAA;AAAA,IACN,IAAA,EAAM,gEAAA;AAAA,IACN,IAAA,EAAM,6DAAA;AAAA;AAAA,IAEN,IAAA,EAAO;AAAA,GACT;AACA,EAAA,OAAO,aAAA,CAAc,IAAI,CAAA,IAAK,CAAA,iBAAA,EAAoB,IAAI,CAAA,CAAA;AACxD;AAMO,SAAS,YAAY,GAAA,EAAsB;AAChD,EAAA,OAAO,IAAI,QAAA,CAAS,WAAW,CAAA,IAAK,GAAA,CAAI,SAAS,2BAA2B,CAAA;AAC9E;AAEO,SAAS,sBAAsB,GAAA,EAAqB;AACzD,EAAA,MAAM,aAAa,GAAA,CAAI,KAAA,CAAM,sBAAsB,CAAA,IAAK,GAAA,CAAI,MAAM,yBAAyB,CAAA;AAC3F,EAAA,IAAI,UAAA,EAAY;AACd,IAAA,MAAM,IAAA,GAAO,QAAA,CAAS,UAAA,CAAW,CAAC,GAAG,EAAE,CAAA;AAEvC,IAAA,MAAM,cAAc,GAAA,CAAI,KAAA,CAAM,yBAAyB,CAAA,IAAK,GAAA,CAAI,MAAM,cAAc,CAAA;AACpF,IAAA,MAAM,OAAA,GAAU,GAAA,CAAI,KAAA,CAAM,oCAAoC,CAAA;AAC9D,IAAA,MAAM,OAAA,GAAU,CAAA,EAAG,WAAA,GAAc,CAAC,KAAK,EAAE,CAAA,EAAG,OAAA,GAAU,CAAA,EAAA,EAAK,QAAQ,CAAC,CAAC,CAAA,CAAA,GAAK,EAAE,GAAG,WAAA,EAAY;AAC3F,IAAA,MAAM,MAAA,GAAS,WAAA,GACX,CAAA,EAAA,EAAK,WAAA,CAAY,CAAC,CAAC,CAAA,EAAG,OAAA,GAAU,CAAA,EAAA,EAAK,OAAA,CAAQ,CAAC,CAAC,CAAA,CAAA,GAAK,EAAE,CAAA,CAAA,CAAA,GACtD,EAAA;AAEJ,IAAA,IAAI,OAAA,CAAQ,QAAA,CAAS,UAAU,CAAA,EAAG;AAChC,MAAA,OAAO,wDAAmD,MAAM,CAAA,CAAA;AAAA,IAClE;AACA,IAAA,IAAI,QAAQ,QAAA,CAAS,gBAAgB,KAAK,OAAA,CAAQ,QAAA,CAAS,qBAAqB,CAAA,EAAG;AACjF,MAAA,OAAO,gCAAgC,MAAM,CAAA,CAAA;AAAA,IAC/C;AAEA,IAAA,MAAM,MAAA,GAAS,iBAAiB,IAAI,CAAA;AACpC,IAAA,OAAO,CAAA,EAAG,MAAM,CAAA,EAAG,MAAM,CAAA,CAAA;AAAA,EAC3B;AACA,EAAA,OAAO,GAAA;AACT;AApIA,IA0Ca;AA1Cb,IAAA,WAAA,GAAA,KAAA,CAAA;AAAA,EAAA,eAAA,GAAA;AA0CO,IAAM,UAAA,GAAN,cAAyB,KAAA,CAAM;AAAA,MAC3B,IAAA;AAAA,MACA,IAAA;AAAA,MACA,SAAA;AAAA,MAET,WAAA,CAAY,IAAA,EAAsB,OAAA,EAAiB,IAAA,EAAuB,YAAY,KAAA,EAAO;AAC3F,QAAA,KAAA,CAAM,OAAO,CAAA;AACb,QAAA,IAAA,CAAK,IAAA,GAAO,YAAA;AACZ,QAAA,IAAA,CAAK,IAAA,GAAO,IAAA;AACZ,QAAA,IAAA,CAAK,IAAA,GAAO,IAAA;AACZ,QAAA,IAAA,CAAK,SAAA,GAAY,SAAA;AAAA,MACnB;AAAA,MAEA,MAAA,GAAS;AACP,QAAA,OAAO;AAAA,UACL,OAAO,IAAA,CAAK,IAAA;AAAA,UACZ,SAAS,IAAA,CAAK,OAAA;AAAA,UACd,GAAI,IAAA,CAAK,IAAA,IAAQ,EAAE,IAAA,EAAM,KAAK,IAAA,EAAK;AAAA,UACnC,WAAW,IAAA,CAAK;AAAA,SAClB;AAAA,MACF;AAAA,KACF;AAAA,EAAA;AAAA,CAAA,CAAA;;;ACqBO,SAAS,QAAQ,QAAA,EAA2B;AACjD,EAAA,MAAM,IAAA,GAAO,OAAA,CAAQ,GAAA,CAAI,QAAQ,CAAA;AACjC,EAAA,OAAO,MAAM,IAAA,KAAS,CAAA;AACxB;AAGO,SAAS,QAAQ,QAAA,EAA2B;AACjD,EAAA,MAAM,IAAA,GAAO,OAAA,CAAQ,GAAA,CAAI,QAAQ,CAAA;AACjC,EAAA,OAAO,MAAM,IAAA,KAAS,CAAA;AACxB;AAGO,SAAS,YAAY,QAAA,EAA2B;AACrD,EAAA,MAAM,IAAA,GAAO,OAAA,CAAQ,GAAA,CAAI,QAAQ,CAAA;AACjC,EAAA,OAAO,MAAM,IAAA,KAAS,MAAA;AACxB;AAGO,SAAS,QAAQ,QAAA,EAAqC;AAC3D,EAAA,OAAO,OAAA,CAAQ,GAAA,CAAI,QAAQ,CAAA,EAAG,IAAA;AAChC;AAQO,SAAS,uBAAuB,QAAA,EAA0B;AAC/D,EAAA,MAAM,MAAA,GAAS,OAAA,CAAQ,GAAA,CAAI,QAAQ,CAAA;AACnC,EAAA,IAAI,MAAA,SAAe,MAAA,CAAO,QAAA;AAE1B,EAAA,MAAM,MAAA,GAAS,QAAA,CAAS,KAAA,CAAM,IAAI,CAAA,CAAE,KAAA,CAAM,CAAC,CAAA,CAAE,IAAA,CAAK,IAAI,CAAA,CAAE,WAAA,EAAY;AACpE,EAAA,IAAI,MAAA,EAAQ;AACV,IAAA,KAAA,MAAW,IAAA,IAAQ,OAAA,CAAQ,MAAA,EAAO,EAAG;AACnC,MAAA,MAAM,UAAA,GAAa,IAAA,CAAK,IAAA,CAAK,KAAA,CAAM,IAAI,CAAA,CAAE,KAAA,CAAM,CAAC,CAAA,CAAE,IAAA,CAAK,IAAI,CAAA,CAAE,WAAA,EAAY;AACzE,MAAA,IAAI,UAAA,KAAe,MAAA,EAAQ,OAAO,IAAA,CAAK,QAAA;AAAA,IACzC;AAAA,EACF;AAEA,EAAA,OAAO,CAAA;AACT;AAMO,SAAS,cAAc,QAAA,EAA0B;AACtD,EAAA,MAAM,MAAA,GAAS,OAAA,CAAQ,GAAA,CAAI,QAAQ,CAAA;AACnC,EAAA,IAAI,MAAA,SAAe,MAAA,CAAO,MAAA;AAE1B,EAAA,MAAM,MAAA,GAAS,QAAA,CAAS,KAAA,CAAM,IAAI,CAAA,CAAE,KAAA,CAAM,CAAC,CAAA,CAAE,IAAA,CAAK,IAAI,CAAA,CAAE,WAAA,EAAY;AACpE,EAAA,IAAI,MAAA,EAAQ;AACV,IAAA,KAAA,MAAW,IAAA,IAAQ,OAAA,CAAQ,MAAA,EAAO,EAAG;AACnC,MAAA,MAAM,UAAA,GAAa,IAAA,CAAK,IAAA,CAAK,KAAA,CAAM,IAAI,CAAA,CAAE,KAAA,CAAM,CAAC,CAAA,CAAE,IAAA,CAAK,IAAI,CAAA,CAAE,WAAA,EAAY;AACzE,MAAA,IAAI,UAAA,KAAe,MAAA,EAAQ,OAAO,IAAA,CAAK,MAAA;AAAA,IACzC;AAAA,EACF;AAEA,EAAA,OAAO,QAAA,CAAS,KAAA,CAAM,IAAI,CAAA,CAAE,KAAI,IAAK,QAAA;AACvC;AAoBO,SAAS,iBAAiB,UAAA,EAAmC;AAClE,EAAA,IAAI,UAAA,CAAW,QAAA,CAAS,IAAI,CAAA,EAAG,OAAO,UAAA;AACtC,EAAA,OAAO,UAAU,UAAU,CAAA,IAAK,UAAU,UAAA,CAAW,WAAA,EAAa,CAAA,IAAK,IAAA;AACzE;AAvKA,IAwBa,aAAA,CAAA,CA4BP,OAAA,CAAA,CAkGO,SAAA,CAAA,CAoBA,QAAA,CAAA,CACA,SAAA,CAAA,CACA,SAAA,CAAA,CACA,WAAA,CAAA,CACA,SAAA,CAAA,CACA,QAAA,CAAA,CACA,SAAA,CAAA,CACA,QAAA,CAAA,CACA,SAAA,CAAA,CACA,UACA,SAAA,CAAA,CACA;AArLb,IAAA,mBAAA,GAAA,KAAA,CAAA;AAAA,EAAA,uBAAA,GAAA;AAwBO,IAAM,aAAA,GAA0C;AAAA;AAAA,MAErD,IAAA,EAAU,EAAE,IAAA,EAAM,gFAAA,EAAkF,UAAU,CAAA,EAAG,MAAA,EAAQ,MAAA,EAAQ,IAAA,EAAM,CAAA,EAAE;AAAA;AAAA,MAGzI,GAAA,EAAU,EAAE,IAAA,EAAM,eAAA,EAAiB,UAAU,CAAA,EAAG,MAAA,EAAQ,KAAA,EAAO,IAAA,EAAM,CAAA,EAAE;AAAA,MACvE,IAAA,EAAU,EAAE,IAAA,EAAM,gFAAA,EAAkF,UAAU,CAAA,EAAG,MAAA,EAAQ,MAAA,EAAQ,IAAA,EAAM,CAAA,EAAE;AAAA,MACzI,GAAA,EAAU,EAAE,IAAA,EAAM,8EAAA,EAAgF,UAAU,CAAA,EAAG,MAAA,EAAQ,KAAA,EAAO,IAAA,EAAM,CAAA,EAAE;AAAA,MACtI,IAAA,EAAU,EAAE,IAAA,EAAM,gFAAA,EAAkF,UAAU,CAAA,EAAG,MAAA,EAAQ,MAAA,EAAQ,IAAA,EAAM,CAAA,EAAE;AAAA,MACzI,IAAA,EAAU,EAAE,IAAA,EAAM,gFAAA,EAAkF,UAAU,CAAA,EAAG,MAAA,EAAQ,MAAA,EAAQ,IAAA,EAAM,CAAA,EAAE;AAAA,MACzI,GAAA,EAAU,EAAE,IAAA,EAAM,8EAAA,EAAgF,UAAU,CAAA,EAAG,MAAA,EAAQ,KAAA,EAAO,IAAA,EAAM,CAAA,EAAE;AAAA,MACtI,EAAA,EAAU,EAAE,IAAA,EAAM,4EAAA,EAA8E,UAAU,CAAA,EAAG,MAAA,EAAQ,IAAA,EAAM,IAAA,EAAM,CAAA,EAAE;AAAA,MACnI,GAAA,EAAU,EAAE,IAAA,EAAM,8EAAA,EAAgF,UAAU,CAAA,EAAG,MAAA,EAAQ,KAAA,EAAO,IAAA,EAAM,CAAA,EAAE;AAAA,MACtI,KAAA,EAAU,EAAE,IAAA,EAAM,kFAAA,EAAoF,UAAU,CAAA,EAAG,MAAA,EAAQ,OAAA,EAAS,IAAA,EAAM,CAAA,EAAE;AAAA,MAC5I,IAAA,EAAU,EAAE,IAAA,EAAM,gFAAA,EAAkF,UAAU,CAAA,EAAG,MAAA,EAAQ,MAAA,EAAQ,IAAA,EAAM,CAAA,EAAE;AAAA,MACzI,IAAA,EAAU,EAAE,IAAA,EAAM,gFAAA,EAAkF,UAAU,CAAA,EAAG,MAAA,EAAQ,MAAA,EAAQ,IAAA,EAAM,CAAA,EAAE;AAAA,MACzI,KAAA,EAAU,EAAE,IAAA,EAAM,kFAAA,EAAoF,UAAU,CAAA,EAAG,MAAA,EAAQ,OAAA,EAAS,IAAA,EAAM,CAAA,EAAE;AAAA,MAC5I,KAAA,EAAU,EAAE,IAAA,EAAM,kFAAA,EAAoF,UAAU,CAAA,EAAG,MAAA,EAAQ,OAAA,EAAS,IAAA,EAAM,CAAA,EAAE;AAAA,MAC5I,IAAA,EAAU,EAAE,IAAA,EAAM,gFAAA,EAAkF,UAAU,CAAA,EAAG,MAAA,EAAQ,MAAA,EAAQ,IAAA,EAAM,CAAA,EAAE;AAAA,MACzI,QAAA,EAAU,EAAE,IAAA,EAAM,wFAAA,EAA0F,UAAU,CAAA,EAAG,MAAA,EAAQ,UAAA,EAAY,IAAA,EAAM,CAAA,EAAE;AAAA;AAAA,MAGrJ,MAAU,EAAE,IAAA,EAAM,kFAAkF,QAAA,EAAU,CAAA,EAAG,QAAQ,MAAA,EAAO;AAAA,MAChI,MAAU,EAAE,IAAA,EAAM,0FAA0F,QAAA,EAAU,CAAA,EAAG,QAAQ,MAAA,EAAO;AAAA,MACxI,QAAU,EAAE,IAAA,EAAM,sFAAsF,QAAA,EAAU,CAAA,EAAG,QAAQ,QAAA;AAAS,KACxI;AAGA,IAAM,OAAA,uBAAc,GAAA,EAAsB;AAC1C,IAAA,KAAA,MAAW,IAAA,IAAQ,MAAA,CAAO,MAAA,CAAO,aAAa,CAAA,EAAG;AAC/C,MAAA,OAAA,CAAQ,GAAA,CAAI,IAAA,CAAK,IAAA,EAAM,IAAI,CAAA;AAAA,IAC7B;AA+FO,IAAM,aAAqC,MAAM;AACtD,MAAA,MAAM,MAA8B,EAAC;AACrC,MAAA,KAAA,MAAW,CAAC,IAAA,EAAM,IAAI,KAAK,MAAA,CAAO,OAAA,CAAQ,aAAa,CAAA,EAAG;AACxD,QAAA,GAAA,CAAI,IAAI,IAAI,IAAA,CAAK,IAAA;AACjB,QAAA,GAAA,CAAI,IAAA,CAAK,WAAA,EAAa,CAAA,GAAI,IAAA,CAAK,IAAA;AAAA,MACjC;AACA,MAAA,OAAO,GAAA;AAAA,IACT,CAAA,GAAG;AAaI,IAAM,QAAA,GAAW,cAAc,GAAA,CAAI,IAAA;AACnC,IAAM,SAAA,GAAY,cAAc,IAAA,CAAK,IAAA;AACrC,IAAM,SAAA,GAAY,cAAc,IAAA,CAAK,IAAA;AACrC,IAAM,WAAA,GAAc,cAAc,MAAA,CAAO,IAAA;AACzC,IAAM,SAAA,GAAY,cAAc,IAAA,CAAK,IAAA;AACrC,IAAM,QAAA,GAAW,cAAc,GAAA,CAAI,IAAA;AACnC,IAAM,SAAA,GAAY,cAAc,IAAA,CAAK,IAAA;AACrC,IAAM,QAAA,GAAW,cAAc,GAAA,CAAI,IAAA;AACnC,IAAM,SAAA,GAAY,cAAc,IAAA,CAAK,IAAA;AACrC,IAAM,QAAA,GAAW,cAAc,GAAA,CAAI,IAAA;AACnC,IAAM,SAAA,GAAY,cAAc,IAAA,CAAK,IAAA;AACrC,IAAM,aAAA,GAAgB,cAAc,QAAA,CAAS,IAAA;AAAA,EAAA;AAAA,CAAA,CAAA;;;AClL7C,IAAM,gBAAN,MAAiD;AAAA,EACtD,YAA6B,OAAA,EAAyB;AAAzB,IAAA,IAAA,CAAA,OAAA,GAAA,OAAA;AAAA,EAA0B;AAAA,EAEvD,UAAA,GAAqB;AACnB,IAAA,OAAO,IAAA,CAAK,OAAA,CAAQ,YAAA,EAAa,CAAE,YAAA,EAAa;AAAA,EAClD;AAAA,EAEA,MAAM,gBAAgB,OAAA,EAAqD;AACzE,IAAA,OAAO,IAAA,CAAK,OAAA,CAAQ,eAAA,CAAgB,OAAO,CAAA;AAAA,EAC7C;AAAA,EAEA,MAAM,oBAAoB,YAAA,EAAyE;AACjG,IAAA,OAAO,IAAA,CAAK,OAAA,CAAQ,mBAAA,CAAoB,YAAY,CAAA;AAAA,EACtD;AAAA;AAAA,EAGA,UAAA,GAA6B;AAC3B,IAAA,OAAO,IAAA,CAAK,OAAA;AAAA,EACd;AACF;;;ACLO,IAAM,gBAAN,MAAiD;AAAA,EACtD,WAAA,CACmB,gBAAA,EACA,OAAA,EACA,WAAA,EACA,QAAA,EACjB;AAJiB,IAAA,IAAA,CAAA,gBAAA,GAAA,gBAAA;AACA,IAAA,IAAA,CAAA,OAAA,GAAA,OAAA;AACA,IAAA,IAAA,CAAA,WAAA,GAAA,WAAA;AACA,IAAA,IAAA,CAAA,QAAA,GAAA,QAAA;AAAA,EAChB;AAAA,EAEH,UAAA,GAAqB;AACnB,IAAA,OAAO,IAAA,CAAK,WAAA;AAAA,EACd;AAAA,EAEA,MAAM,gBAAgB,OAAA,EAAqD;AACzE,IAAA,MAAM,EAAE,mBAAA,EAAoB,GAAI,MAAM,OAAO,iBAAiB,CAAA;AAC9D,IAAA,MAAM,MAAA,GAAS,MAAM,IAAA,CAAK,gBAAA,CAAiB,gBAAgB,OAAO,CAAA;AAClE,IAAA,OAAO;AAAA,MACL,WAAW,mBAAA,CAAoB;AAAA,QAC7B,QAAQ,IAAA,CAAK,OAAA;AAAA,QACb,UAAU,IAAA,CAAK,QAAA;AAAA,QACf,eAAe,MAAA,CAAO;AAAA,OACvB;AAAA,KACH;AAAA,EACF;AAAA,EAEA,MAAM,oBAAoB,aAAA,EAA0E;AAKlG,IAAA,MAAM,IAAI,MAAM,gJAAgJ,CAAA;AAAA,EAClK;AAAA,EAEA,UAAU,YAAA,EAA+B;AACvC,IAAA,OAAO,gBAAgB,IAAA,CAAK,QAAA;AAAA,EAC9B;AACF;;;ACnCA,WAAA,EAAA;;;ACjBA,WAAA,EAAA;AAEO,IAAM,YAAA,GAAe;AACrB,IAAM,YAAA,GAAe;AACrB,IAAM,aAAA,GAAgB;AAEtB,IAAM,eAAA,GAAkB;AAKxB,IAAM,YAAA,GAAe;AACrB,IAAM,cAAA,GAAiB;AAEvB,IAAM,QAAA,GAAW;AAEjB,IAAM,gBAAA,GAAmB;AAAA,EAC9B,IAAA,EAAM;AAAA,IACJ,IAAA,EAAM,gFAAA;AAAA,IACN,QAAA,EAAU,CAAA;AAAA,IACV,MAAA,EAAQ,MAAA;AAAA,IACR,WAAA,EAAa;AAAA,GACf;AAAA,EACA,IAAA,EAAM;AAAA,IACJ,IAAA,EAAM,gFAAA;AAAA,IACN,QAAA,EAAU,CAAA;AAAA,IACV,MAAA,EAAQ,MAAA;AAAA,IACR,WAAA,EAAa;AAAA,GACf;AAAA,EACA,IAAA,EAAM;AAAA,IACJ,IAAA,EAAM,wFAAA;AAAA,IACN,QAAA,EAAU,CAAA;AAAA,IACV,MAAA,EAAQ,MAAA;AAAA,IACR,WAAA,EAAa;AAAA,GACf;AAAA,EACA,MAAA,EAAQ;AAAA,IACN,IAAA,EAAM,oFAAA;AAAA,IACN,QAAA,EAAU,CAAA;AAAA,IACV,MAAA,EAAQ,QAAA;AAAA,IACR,WAAA,EAAa;AAAA,GACf;AAAA,EACA,GAAA,EAAK;AAAA,IACH,IAAA,EAAM,eAAA;AAAA,IACN,QAAA,EAAU,CAAA;AAAA,IACV,MAAA,EAAQ,KAAA;AAAA,IACR,WAAA,EAAa;AAAA,GACf;AAAA,EACA,GAAA,EAAK;AAAA,IACH,IAAA,EAAM,8EAAA;AAAA,IACN,QAAA,EAAU,CAAA;AAAA,IACV,MAAA,EAAQ,KAAA;AAAA,IACR,WAAA,EAAa;AAAA,GACf;AAAA,EACA,GAAA,EAAK;AAAA,IACH,IAAA,EAAM,8EAAA;AAAA,IACN,QAAA,EAAU,CAAA;AAAA,IACV,MAAA,EAAQ,KAAA;AAAA,IACR,WAAA,EAAa;AAAA,GACf;AAAA,EACA,IAAA,EAAM;AAAA,IACJ,IAAA,EAAM,gFAAA;AAAA,IACN,QAAA,EAAU,CAAA;AAAA,IACV,MAAA,EAAQ,MAAA;AAAA,IACR,WAAA,EAAa;AAAA,GACf;AAAA,EACA,IAAA,EAAM;AAAA,IACJ,IAAA,EAAM,gFAAA;AAAA,IACN,QAAA,EAAU,CAAA;AAAA,IACV,MAAA,EAAQ,MAAA;AAAA,IACR,WAAA,EAAa;AAAA;AAEjB;AAYO,IAAM,aAAA,GAAwC,CAAC,MAAA,EAAQ,QAAQ;AAW/D,IAAM,eAAA,GAA6C,MAAA,CAAO,IAAA,CAAK,gBAAgB;CAsFf;AAAA,EACrE,IAAA,EAAM,iBAAiB,IAAA,CAAK,IAAA;AAAA,EAC5B,MAAA,EAAQ,iBAAiB,MAAA,CAAO;AAClC;AASO,IAAM,wBAAA,GAA2B,OAAA,CAAQ,GAAA,CAAI,wBAAA,IAC/C;AAEE,IAAM,eAAA,GAAkB;AAgBH,OAAA,CAAQ,GAAA,CAAI,aAAA,IAAiB;AAKlD,IAAM,eAAA,GAAkB;ACpN/B,WAAA,EAAA;AAoFO,SAAS,gBAAgB,OAAA,EAAyB;AACvD,EAAA,MAAM,UAAA,GAAa,oBAAoB,OAAO,CAAA;AAC9C,EAAA,IAAI,CAAC,iBAAA,CAAkB,UAAU,CAAA,EAAG;AAClC,IAAA,MAAM,IAAI,UAAA,CAAW,iBAAA,EAAmB,CAAA,qBAAA,EAAwB,OAAO,CAAA,CAAE,CAAA;AAAA,EAC3E;AACA,EAAA,OAAO,UAAA;AACT;AAEO,SAAS,gBAAgB,OAAA,EAAyB;AACvD,EAAA,IAAI,OAAA,CAAQ,MAAA,IAAU,EAAA,EAAI,OAAO,OAAA;AACjC,EAAA,OAAO,CAAA,EAAG,OAAA,CAAQ,KAAA,CAAM,CAAA,EAAG,CAAC,CAAC,CAAA,GAAA,EAAM,OAAA,CAAQ,KAAA,CAAM,EAAE,CAAC,CAAA,CAAA;AACtD;;;ACxFA,mBAAA,EAAA;AAYO,IAAM,aAAA,GAA6C;AAAA,EACxD,CAAC,0BAA0B,SAAS,CAAA;AAAA,EACpC,CAAC,uDAAuD,SAAS,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQjE,CAAC,sTAAsT,MAAM,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAS7T,CAAC,6GAA6G,MAAM,CAAA;AAAA,EACpH,CAAC,+BAA+B,MAAM;AACxC;AAYO,IAAM,cAAA,GAA8C;AAAA,EACzD,CAAC,8DAA8D,cAAc,CAAA;AAAA,EAC7E,CAAC,gCAAgC,SAAS,CAAA;AAAA,EAC1C,CAAC,qCAAqC,SAAS,CAAA;AAAA,EAC/C,CAAC,wCAAwC,UAAU,CAAA;AAAA,EACnD,CAAC,YAAY,QAAQ,CAAA;AAAA,EACrB,CAAC,WAAW,OAAO,CAAA;AAAA,EACnB,CAAC,8CAA8C,OAAO,CAAA;AAAA,EACtD,CAAC,WAAW,OAAO,CAAA;AAAA,EACnB,CAAC,sBAAsB,SAAS,CAAA;AAAA,EAChC,CAAC,eAAe,WAAW;AAC7B;AAQA,SAAS,aAAa,KAAA,EAAsD;AAC1E,EAAA,IAAI,OAAO,KAAA,KAAU,QAAA,IAAY,KAAA,CAAM,YAAA,SAAqB,KAAA,CAAM,YAAA;AAClE,EAAA,IAAI,OAAO,KAAA,KAAU,QAAA,EAAU,OAAO,KAAA;AACtC,EAAA,OAAO,IAAA;AACT;AAEO,SAAS,cAAA,CAAe,SAAmB,YAAA,EAAgC;AAChF,EAAA,KAAA,MAAW,UAAU,OAAA,EAAS;AAC5B,IAAA,KAAA,MAAW,CAAC,OAAA,EAAS,KAAK,CAAA,IAAK,aAAA,EAAe;AAC5C,MAAA,IAAI,OAAA,CAAQ,IAAA,CAAK,MAAM,CAAA,EAAG,OAAO,KAAA;AAAA,IACnC;AAAA,EACF;AACA,EAAA,IAAI,YAAA,CAAa,SAAS,iBAAiB,CAAA,IAAK,CAAC,YAAA,CAAa,QAAA,CAAS,UAAU,CAAA,EAAG,OAAO,MAAA;AAC3F,EAAA,OAAO,aAAA;AACT;AAaO,SAAS,cAAc,OAAA,EAA2B;AACvD,EAAA,IAAI,CAAC,OAAA,CAAQ,MAAA,EAAQ,OAAO,UAAA;AAC5B,EAAA,MAAM,KAAA,GAAQ,QAAQ,CAAC,CAAA;AACvB,EAAA,MAAM,KAAA,GAAQ,KAAA,CAAM,KAAA,CAAM,IAAI,CAAA;AAC9B,EAAA,IAAI,KAAA,CAAM,MAAA,IAAU,CAAA,IAAK,KAAA,CAAM,CAAC,GAAG,OAAO,KAAA,CAAM,CAAC,CAAA,CAAE,WAAA,EAAY;AAC/D,EAAA,OAAO,UAAA;AACT;AAgBO,SAAS,aAAA,CAAc,SAAmB,YAAA,EAAgC;AAC/E,EAAA,KAAA,MAAW,UAAU,OAAA,EAAS;AAC5B,IAAA,KAAA,MAAW,CAAC,OAAA,EAAS,KAAK,CAAA,IAAK,cAAA,EAAgB;AAC7C,MAAA,IAAI,OAAA,CAAQ,IAAA,CAAK,MAAM,CAAA,EAAG,OAAO,KAAA;AAAA,IACnC;AAAA,EACF;AACA,EAAA,IAAI,YAAA,CAAa,SAAS,iBAAiB,CAAA,IAAK,CAAC,YAAA,CAAa,QAAA,CAAS,UAAU,CAAA,EAAG,OAAO,MAAA;AAC3F,EAAA,MAAM,MAAA,GAAS,cAAA,CAAe,OAAA,EAAS,YAAY,CAAA;AACnD,EAAA,IAAI,MAAA,KAAW,eAAe,OAAO,MAAA;AACrC,EAAA,OAAO,cAAc,OAAO,CAAA;AAC9B;AAmBO,SAAS,kBAAA,CACd,aAAA,EACA,YAAA,EACA,eAAA,EACA,SACA,OAAA,EACQ;AACR,EAAA,IAAI,aAAA,KAAkB,WAAW,OAAO,YAAA;AACxC,EAAA,MAAM,uBAAuB,cAAA,CAAe,IAAA;AAAA,IAAK,CAAC,CAAC,CAAC,CAAA,KAClD,eAAA,CAAgB,IAAA,CAAK,CAAC,CAAA,KAAM,CAAA,CAAE,IAAA,CAAK,CAAC,CAAC;AAAA,GACvC;AACA,EAAA,IAAI,sBAAsB,OAAO,YAAA;AAEjC,EAAA,MAAM,oBAAoB,OAAA,CAAQ,IAAA;AAAA,IAChC,CAAC,CAAA,KAAM,YAAA,CAAa,CAAA,CAAE,KAAK,CAAA,KAAM,OAAA,IAAW,CAAA,CAAE,QAAA,KAAa,QAAA,IAAY,MAAA,CAAO,CAAA,CAAE,MAAM,CAAA,GAAI;AAAA,GAC5F;AACA,EAAA,IAAI,mBAAmB,OAAO,SAAA;AAE9B,EAAA,MAAM,mBAAmB,OAAA,CAAQ,IAAA;AAAA,IAC/B,CAAC,CAAA,KAAM,YAAA,CAAa,CAAA,CAAE,KAAK,CAAA,KAAM,OAAA,IAAW,CAAA,CAAE,QAAA,KAAa,QAAA,IAAY,MAAA,CAAO,CAAA,CAAE,MAAM,CAAA,GAAI;AAAA,GAC5F;AACA,EAAA,IAAI,kBAAkB,OAAO,UAAA;AAE7B,EAAA,OAAO,YAAA;AACT;AAOO,SAAS,mBAAA,CACd,eAAA,EACA,YAAA,EACA,cAAA,EACA,OAAA,EACgB;AAChB,EAAA,MAAM,MAAA,GAAS,cAAA,CAAe,eAAA,EAAiB,YAAY,CAAA;AAC3D,EAAA,MAAM,SAAA,GAAY,aAAA,CAAc,eAAA,EAAiB,YAAY,CAAA;AAC7D,EAAA,MAAM,QAAQ,kBAAA,CAAmB,MAAA,EAAQ,SAAA,EAAW,eAAA,EAAiB,gBAAgB,OAAO,CAAA;AAC5F,EAAA,OAAO,EAAE,QAAQ,KAAA,EAAM;AACzB;AA2CO,SAAS,sBAAA,CACd,SACA,MAAA,EACmB;AACnB,EAAA,IAAI,CAAC,OAAA,IAAW,OAAA,CAAQ,MAAA,KAAW,CAAA,SAAU,EAAC;AAE9C,EAAA,MAAM,WAAA,GAAc,QAAQ,MAAA,CAAO,CAAC,MAAM,YAAA,CAAa,CAAA,CAAE,KAAK,CAAA,KAAM,MAAM,CAAA;AAC1E,EAAA,IAAI,WAAA,CAAY,MAAA,KAAW,CAAA,EAAG,OAAO,EAAC;AAEtC,EAAA,MAAM,aAAa,WAAA,CAAY,MAAA,CAAO,CAAC,CAAA,KAAM,CAAA,CAAE,aAAa,QAAQ,CAAA;AACpE,EAAA,MAAM,IAAA,GAAO,UAAA,CAAW,MAAA,GAAS,CAAA,GAAI,UAAA,GAAa,WAAA;AAElD,EAAA,IAAI,OAAA,GAAU,KAAK,CAAC,CAAA;AACpB,EAAA,IAAI,UAAA,GAAa,SAAA,CAAU,MAAA,CAAO,OAAA,CAAQ,MAAM,CAAC,CAAA;AACjD,EAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,IAAA,CAAK,QAAQ,CAAA,EAAA,EAAK;AACpC,IAAA,MAAM,MAAM,SAAA,CAAU,MAAA,CAAO,KAAK,CAAC,CAAA,CAAE,MAAM,CAAC,CAAA;AAC5C,IAAA,IAAI,MAAM,UAAA,EAAY;AACpB,MAAA,OAAA,GAAU,KAAK,CAAC,CAAA;AAChB,MAAA,UAAA,GAAa,GAAA;AAAA,IACf;AAAA,EACF;AAEA,EAAA,MAAM,GAAA,GAAM,MAAA,CAAO,OAAA,CAAQ,MAAM,CAAA;AACjC,EAAA,IAAI,GAAA,KAAQ,EAAA,EAAI,OAAO,EAAC;AAExB,EAAA,MAAM,QAAA,GAAW,sBAAA,CAAuB,OAAA,CAAQ,QAAQ,CAAA;AACxD,EAAA,MAAM,MAAA,GAAS,MAAA,CAAO,UAAU,CAAA,GAAI,EAAA,IAAM,QAAA;AAC1C,EAAA,MAAM,KAAA,GAAQ,aAAA,CAAc,OAAA,CAAQ,QAAQ,CAAA;AAC5C,EAAA,MAAM,SAAA,GAAyB,GAAA,GAAM,EAAA,GAAK,KAAA,GAAQ,IAAA;AAElD,EAAA,IAAI,SAAA;AACJ,EAAA,IAAI,cAAc,KAAA,EAAO;AACvB,IAAA,MAAM,kBAAkB,OAAA,CAAQ,IAAA;AAAA,MAC9B,CAAC,CAAA,KACC,YAAA,CAAa,CAAA,CAAE,KAAK,CAAA,KAAM,MAAA,IAC1B,CAAA,CAAE,QAAA,KAAa,OAAA,CAAQ,QAAA,IACvB,MAAA,CAAO,CAAA,CAAE,MAAM,CAAA,GAAI;AAAA,KACvB;AACA,IAAA,SAAA,GAAY,eAAA,GAAkB,YAAA,CAAa,eAAA,CAAgB,KAAK,KAAK,MAAA,GAAY,MAAA;AAAA,EACnF;AAEA,EAAA,OAAO,EAAE,MAAA,EAAQ,KAAA,EAAO,SAAA,EAAW,SAAA,EAAU;AAC/C;AAEA,SAAS,UAAU,CAAA,EAAmB;AACpC,EAAA,OAAO,CAAA,GAAI,EAAA,GAAK,CAAC,CAAA,GAAI,CAAA;AACvB;AAmBO,SAAS,kBAAA,CACd,SACA,MAAA,EACwC;AACxC,EAAA,IAAI,CAAC,OAAA,IAAW,OAAA,CAAQ,MAAA,KAAW,CAAA,SAAU,EAAC;AAE9C,EAAA,MAAM,OAA+C,EAAC;AACtD,EAAA,KAAA,MAAW,KAAK,OAAA,EAAS;AACvB,IAAA,IAAI,YAAA,CAAa,CAAA,CAAE,KAAK,CAAA,KAAM,MAAA,EAAQ;AACtC,IAAA,MAAM,GAAA,GAAM,MAAA,CAAO,CAAA,CAAE,MAAM,CAAA;AAC3B,IAAA,IAAI,QAAQ,EAAA,EAAI;AAChB,IAAA,MAAM,QAAA,GAAW,sBAAA,CAAuB,CAAA,CAAE,QAAQ,CAAA;AAClD,IAAA,MAAM,SAAA,GAAY,UAAU,GAAG,CAAA;AAC/B,IAAA,IAAA,CAAK,IAAA,CAAK;AAAA,MACR,UAAU,CAAA,CAAE,QAAA;AAAA,MACZ,KAAA,EAAO,aAAA,CAAc,CAAA,CAAE,QAAQ,CAAA;AAAA,MAC/B,QAAA;AAAA,MACA,MAAA,EAAQ,MAAA,CAAO,SAAS,CAAA,GAAI,EAAA,IAAM,QAAA;AAAA,MAClC,SAAA,EAAW,IAAI,QAAA,EAAS;AAAA,MACxB,SAAA,EAAW,GAAA,GAAM,EAAA,GAAK,KAAA,GAAQ;AAAA,KAC/B,CAAA;AAAA,EACH;AAEA,EAAA,OAAO,IAAA;AACT;;;ACrQO,SAAS,aAAA,CAAc,IAAmB,OAAA,EAAoC;AACnF,EAAA,OAAO,aAAA,CAAc,IAAI,OAAO,CAAA;AAClC;AAMO,SAAS,gBAAgB,OAAA,EAAiC;AAC/D,EAAA,IAAI;AACF,IAAA,IAAI,CAAC,OAAA,IAAW,OAAO,OAAA,KAAY,UAAU,OAAO,IAAA;AACpD,IAAA,MAAM,IAAA,GAAO,MAAA,IAAU,OAAA,GAAW,OAAA,CAAoC,IAAA,GAAO,KAAA,CAAA;AAC7E,IAAA,IAAI,CAAC,IAAA,IAAQ,OAAO,IAAA,KAAS,UAAU,OAAO,IAAA;AAC9C,IAAA,OAAS,KAAiC,MAAA,IAAqB,IAAA;AAAA,EACjE,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,IAAA;AAAA,EACT;AACF;AASO,SAAS,kBAAkB,OAAA,EAGhC;AACA,EAAA,OAAO,gBAAgB,OAAO,CAAA;AAChC;AAEA,SAAS,aAAA,CAAc,IAAmB,OAAA,EAAoC;AAC5E,EAAA,MAAM,OAAA,GAAU,GAAG,OAAA,EAAS,OAAA;AAC5B,EAAA,MAAM,OAAA,GAAU,OAAA,GAAA,CACX,MAAA,CAAO,OAAA,CAAQ,eAAe,CAAA,GAC7B,MAAA,CAAO,OAAA,CAAQ,WAAW,CAAA,GAC1B,MAAA,CAAO,OAAA,CAAQ,aAAa,KAC9B,GAAA,GACA,MAAA;AAEJ,EAAA,MAAM,EAAE,eAAA,EAAiB,YAAA,EAAa,GAAI,eAAA,CAAgB,GAAG,WAAW,CAAA;AACxE,EAAA,MAAM,cAAA,GAAiB,EAAA,CAAG,cAAA,IAAkB,EAAC;AAC7C,EAAA,MAAM,IAAA,GAAO,kBAAA,CAAmB,cAAA,EAAgB,OAAO,CAAA;AACvD,EAAA,MAAM,EAAE,QAAQ,KAAA,EAAO,SAAA,EAAW,WAAU,GAAI,sBAAA,CAAuB,gBAAgB,OAAO,CAAA;AAC9F,EAAA,MAAM,EAAE,MAAA,EAAQ,KAAA,EAAM,GAAI,mBAAA;AAAA,IACxB,eAAA;AAAA,IACA,YAAA;AAAA,IACA,cAAA;AAAA,IACA;AAAA,GACF;AAEA,EAAA,OAAO;AAAA,IACL,QAAQ,EAAA,CAAG,MAAA;AAAA,IACX,MAAA;AAAA,IACA,KAAA;AAAA,IACA,IAAA;AAAA,IACA,MAAA;AAAA,IACA,KAAA;AAAA,IACA,SAAA;AAAA,IACA,SAAA;AAAA,IACA,SAAA,EAAW,MAAA,CAAO,EAAA,CAAG,WAAA,IAAe,CAAC,CAAA;AAAA,IACrC;AAAA,GACF;AACF;AAOA,SAAS,gBAAgB,OAAA,EAA+B;AACtD,EAAA,MAAM,SAAsB,EAAE,eAAA,EAAiB,EAAC,EAAG,YAAA,EAAc,EAAC,EAAE;AACpE,EAAA,IAAI;AACF,IAAA,IAAI,CAAC,OAAA,IAAW,OAAO,OAAA,KAAY,UAAU,OAAO,MAAA;AACpD,IAAA,MAAM,IAAA,GAAO,MAAA,IAAU,OAAA,GAAW,OAAA,CAAoC,IAAA,GAAO,KAAA,CAAA;AAC7E,IAAA,IAAI,CAAC,IAAA,IAAQ,OAAO,IAAA,KAAS,UAAU,OAAO,MAAA;AAC9C,IAAA,MAAM,KAAA,GAAQ,aAAA,IAAkB,IAAA,GAC3B,IAAA,CAAiC,WAAA,GAClC,KAAA,CAAA;AACJ,IAAA,IAAI,CAAC,KAAA,IAAS,OAAO,KAAA,KAAU,UAAU,OAAO,MAAA;AAChD,IAAA,MAAM,QAAA,GAAW,cAAe,KAAA,GAC3B,KAAA,CAAkC,WACnC,cAAA,IAAmB,KAAA,GAChB,MAAkC,YAAA,GACnC,KAAA,CAAA;AACN,IAAA,IAAI,CAAC,KAAA,CAAM,OAAA,CAAQ,QAAQ,GAAG,OAAO,MAAA;AAErC,IAAA,KAAA,MAAW,OAAO,QAAA,EAAuC;AACvD,MAAA,IAAI,IAAI,QAAA,EAAU;AAChB,QAAA,MAAM,KAAK,GAAA,CAAI,QAAA;AACf,QAAA,MAAA,CAAO,eAAA,CAAgB,IAAA,CAAK,CAAA,EAAG,EAAA,CAAG,OAAO,CAAA,EAAA,EAAK,EAAA,CAAG,MAAM,CAAA,EAAA,EAAK,EAAA,CAAG,QAAQ,CAAA,CAAE,CAAA;AACzE,QAAA,MAAA,CAAO,YAAA,CAAa,KAAK,UAAU,CAAA;AAAA,MACrC,CAAA,MAAA,IAAW,IAAI,eAAA,EAAiB;AAC9B,QAAA,MAAA,CAAO,YAAA,CAAa,KAAK,iBAAiB,CAAA;AAAA,MAC5C;AAAA,IACF;AAAA,EACF,CAAA,CAAA,MAAQ;AAAA,EAAoB;AAC5B,EAAA,OAAO,MAAA;AACT;;;AClKO,SAAS,UAAU,IAAA,EAAsB;AAC9C,EAAA,OAAO,MAAA,CAAO,IAAI,CAAA,GAAI,MAAA,CAAO,YAAY,CAAA;AAC3C;AAEO,SAAS,UAAU,GAAA,EAAqB;AAC7C,EAAA,OAAO,OAAO,IAAA,CAAK,KAAA,CAAM,MAAM,MAAA,CAAO,YAAY,CAAC,CAAC,CAAA;AACtD;AAEO,SAAS,UAAU,MAAA,EAAwB;AAChD,EAAA,OAAO,OAAO,IAAA,CAAK,KAAA,CAAM,MAAA,GAAS,EAAA,IAAM,aAAa,CAAC,CAAA;AACxD;AAEO,SAAS,UAAU,GAAA,EAAqB;AAC7C,EAAA,OAAO,MAAA,CAAO,GAAG,CAAA,GAAI,EAAA,IAAM,aAAA;AAC7B;AAEO,SAAS,WAAA,CAAY,QAAgB,QAAA,EAA0B;AACpE,EAAA,OAAO,OAAO,IAAA,CAAK,KAAA,CAAM,MAAA,GAAS,EAAA,IAAM,QAAQ,CAAC,CAAA;AACnD;AAEO,SAAS,WAAA,CAAY,KAAa,QAAA,EAA0B;AACjE,EAAA,OAAO,MAAA,CAAO,GAAG,CAAA,GAAI,EAAA,IAAM,QAAA;AAC7B;AAEO,SAAS,YAAY,KAAA,EAA+B;AACzD,EAAA,OAAO,gBAAA,CAAiB,KAAK,CAAA,CAAE,QAAA;AACjC;AAcO,SAAS,UAAU,MAAA,EAAwB;AAChD,EAAA,OAAO,CAAA,CAAA,EAAI,MAAA,CAAO,OAAA,CAAQ,CAAC,CAAC,CAAA,CAAA;AAC9B;AAEO,SAAS,UAAU,MAAA,EAAwB;AAChD,EAAA,IAAI,SAAS,IAAA,EAAO,OAAO,GAAG,MAAA,CAAO,OAAA,CAAQ,CAAC,CAAC,CAAA,IAAA,CAAA;AAC/C,EAAA,OAAO,CAAA,EAAG,MAAA,CAAO,OAAA,CAAQ,CAAC,CAAC,CAAA,IAAA,CAAA;AAC7B;AAQO,SAAS,iBAAA,CAAkB,QAAgB,KAAA,EAAuB;AACvE,EAAA,IAAI,KAAA,KAAU,KAAA,EAAO,OAAO,MAAA,CAAO,QAAQ,CAAC,CAAA;AAC5C,EAAA,IAAI,KAAA,KAAU,MAAA,EAAQ,OAAO,MAAA,CAAO,QAAQ,CAAC,CAAA;AAC7C,EAAA,IAAI,KAAA,KAAU,KAAA,EAAO,OAAO,MAAA,CAAO,QAAQ,CAAC,CAAA;AAC5C,EAAA,OAAO,MAAA,CAAO,QAAQ,CAAC,CAAA;AACzB;AAEA,IAAM,YAAA,uBAAwC,GAAA,EAAI;AAClD,KAAA,MAAW,CAAC,GAAA,EAAK,IAAI,KAAK,MAAA,CAAO,OAAA,CAAQ,gBAAgB,CAAA,EAAG;AAC1D,EAAA,YAAA,CAAa,GAAA,CAAI,GAAA,CAAI,WAAA,EAAY,EAAG,GAAG,CAAA;AACvC,EAAA,IAAI,IAAA,CAAK,eAAe,IAAA,CAAK,WAAA,CAAY,aAAY,KAAM,GAAA,CAAI,aAAY,EAAG;AAC5E,IAAA,YAAA,CAAa,GAAA,CAAI,IAAA,CAAK,WAAA,CAAY,WAAA,IAAe,GAAG,CAAA;AAAA,EACtD;AACF;;;ACrEO,SAAS,SAAS,KAAA,EAA2B;AAClD,EAAA,IAAI,MAAA,GAAS,EAAA;AACb,EAAA,KAAA,MAAW,IAAA,IAAQ,KAAA,EAAO,MAAA,IAAU,MAAA,CAAO,aAAa,IAAI,CAAA;AAC5D,EAAA,OAAO,KAAK,MAAM,CAAA;AACpB;AAEO,SAAS,WAAW,GAAA,EAAyB;AAClD,EAAA,MAAM,MAAA,GAAS,KAAK,GAAG,CAAA;AACvB,EAAA,MAAM,KAAA,GAAQ,IAAI,UAAA,CAAW,MAAA,CAAO,MAAM,CAAA;AAC1C,EAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,MAAA,CAAO,MAAA,EAAQ,CAAA,EAAA,EAAK,KAAA,CAAM,CAAC,CAAA,GAAI,MAAA,CAAO,UAAA,CAAW,CAAC,CAAA;AACtE,EAAA,OAAO,KAAA;AACT;;;ACiBA,IAAM,SAAA,GAA0C;AAAA,EAC9C,IAAA,EAAM,YAAA;AAAA,EACN,MAAA,EAAQ,cAAA;AAAA;AAAA;AAAA;AAAA,EAIR,IAAA,EAAM;AAAA;AACR,CAAA;AAMO,SAAS,YAAA,CAAa,WAAyB,MAAA,EAAiC;AACrF,EAAA,MAAM,GAAA,GAAM,UAAU,SAAS,CAAA;AAC/B,EAAA,MAAM,YAAY,MAAA,GAAS,MAAA,CAAO,GAAG,CAAA,GAAI,OAAO,eAAe,CAAA;AAC/D,EAAA,MAAM,SAAA,GAAY,WAAA,CAAY,SAAA,EAAW,aAAa,CAAA;AAEtD,EAAA,OAAO;AAAA,IACL,MAAA,EAAQ,SAAA;AAAA,IACR,KAAA,EAAO,MAAA;AAAA,IACP,IAAA,EAAM,MAAA,CAAO,GAAG,CAAA,GAAI,OAAO,eAAe,CAAA;AAAA,IAC1C;AAAA,GACF;AACF;AA2BO,SAAS,eACd,EAAA,EACA,WAAA,EACA,QACA,QAAA,EACA,MAAA,EACA,WAAmB,aAAA,EACb;AACN,EAAA,IAAI,UAAU,EAAA,EAAI;AAClB,EAAA,IAAI,UAAU,CAAA,EAAG;AAEjB,EAAA,MAAM,YAAY,MAAA,GAAS,MAAA,CAAO,MAAM,CAAA,GAAI,OAAO,eAAe,CAAA;AAClE,EAAA,MAAM,MAAA,GAAS,WAAA,CAAY,SAAA,EAAW,QAAQ,CAAA;AAC9C,EAAA,IAAI,UAAU,EAAA,EAAI;AAElB,EAAA,MAAM,CAAC,OAAO,CAAA,GAAI,EAAA,CAAG,UAAA,CAAW,WAAA,EAAa,CAAC,EAAA,CAAG,IAAA,CAAK,GAAA,CAAI,MAAM,CAAC,CAAC,CAAA;AAClE,EAAA,EAAA,CAAG,eAAA,CAAgB,CAAC,OAAO,CAAA,EAAG,GAAG,IAAA,CAAK,OAAA,CAAQ,QAAQ,CAAC,CAAA;AACzD;;;AC9EA,mBAAA,EAAA;AA8mBA,mBAAA,EAAA;AArZO,IAAM,gBAAA,GAAmB;AAOhC,IAAM,WAAA,uBAAkB,GAAA,EAA8B;AAEtD,SAAS,SAAA,CAAU,eAAuB,UAAA,EAAiD;AACzF,EAAA,MAAM,IAAA,GAAO,YAAY,IAAA,IAAQ,CAAA;AACjC,EAAA,MAAM,QAAA,GAAW,YAAY,QAAA,IAAY,EAAA;AACzC,EAAA,MAAM,MAAM,CAAA,EAAG,aAAa,CAAA,CAAA,EAAI,IAAI,IAAI,QAAQ,CAAA,CAAA;AAEhD,EAAA,MAAM,MAAA,GAAS,WAAA,CAAY,GAAA,CAAI,GAAG,CAAA;AAClC,EAAA,IAAI,QAAQ,OAAO,MAAA;AAEnB,EAAA,MAAM,MAAA,GAAS,IAAI,gBAAA,CAAiB;AAAA,IAClC,MAAA,EAAQ,aAAA;AAAA,IACR,KAAK,GAAA,CAAI,OAAA;AAAA,IACT,GAAI,IAAA,GAAO,CAAA,IAAK,QAAA,GACZ,EAAE,gBAAgB,IAAA,EAAM,kBAAA,EAAoB,QAAA,EAAS,GACrD;AAAC,GACN,CAAA;AACD,EAAA,WAAA,CAAY,GAAA,CAAI,KAAK,MAAM,CAAA;AAC3B,EAAA,OAAO,MAAA;AACT;AAoCA,eAAsB,cAAc,MAAA,EAiBA;AAClC,EAAA,MAAM,MAAA,GAAS,SAAA,CAAU,MAAA,CAAO,aAAA,EAAe,OAAO,UAAU,CAAA;AAEhE,EAAA,MAAM,UAAA,GAA+B;AAAA,IACnC,MAAM,MAAA,CAAO,IAAA;AAAA,IACb,QAAQ,MAAA,CAAO,EAAA;AAAA,IACf,MAAA,EAAQ,MAAA,CAAO,MAAA,CAAO,QAAA,EAAS;AAAA,IAC/B,YAAY,MAAA,CAAO,UAAA;AAAA,IACnB,GAAI,OAAO,SAAA,GAAY,EAAE,WAAW,MAAA,CAAO,SAAA,KAAc;AAAC,GAC5D;AAEA,EAAA,MAAM,UAAA,GAAa,MAAM,MAAA,CAAO,WAAA,CAAY,UAAU,CAAA;AACtD,EAAA,IAAI,CAAC,YAAY,OAAO,IAAA;AAExB,EAAA,IAAI,WAAW,qBAAA,EAAuB;AACpC,IAAA,OAAO;AAAA,MACL,UAAA;AAAA,MACA,QAAA,EAAU,UAAA,CAAW,QAAA,CAAS,QAAA,EAAS;AAAA,MACvC,SAAA,EAAW,UAAA,CAAW,SAAA,CAAU,QAAA,EAAS;AAAA,MACzC,YAAY,MAAA,CAAO,UAAA;AAAA,MACnB,WAAA,EAAa,oBAAA,CAAqB,UAAA,CAAW,cAAc,CAAA;AAAA,MAC3D,qBAAA,EAAuB;AAAA,KACzB;AAAA,EACF;AAEA,EAAA,IAAI,WAAW,KAAA,EAAO;AACpB,IAAA,MAAM,EAAE,UAAA,EAAAA,WAAAA,EAAW,GAAI,MAAM,OAAA,CAAA,OAAA,EAAA,CAAA,IAAA,CAAA,OAAA,WAAA,EAAA,EAAA,cAAA,CAAA,CAAA;AAC7B,IAAA,MAAM,IAAIA,WAAAA,CAAW,aAAA,EAAe,CAAA,qBAAA,EAAwB,UAAA,CAAW,KAAA,CAAM,GAAG,CAAA,OAAA,EAAU,UAAA,CAAW,KAAA,CAAM,IAAI,CAAA,CAAA,CAAG,CAAA;AAAA,EACpH;AAEA,EAAA,OAAO;AAAA,IACL,UAAA;AAAA,IACA,QAAA,EAAU,UAAA,CAAW,QAAA,CAAS,QAAA,EAAS;AAAA,IACvC,SAAA,EAAW,UAAA,CAAW,SAAA,CAAU,QAAA,EAAS;AAAA,IACzC,YAAY,MAAA,CAAO,UAAA;AAAA,IACnB,WAAA,EAAa,oBAAA,CAAqB,UAAA,CAAW,cAAc,CAAA;AAAA,IAC3D,qBAAA,EAAuB;AAAA,GACzB;AACF;AAUA,SAAS,qBAAqB,KAAA,EAAwB;AACpD,EAAA,MAAM,IAAI,OAAO,KAAA,KAAU,QAAA,GAAW,KAAA,GAAQ,OAAO,KAAK,CAAA;AAC1D,EAAA,OAAO,MAAA,CAAO,QAAA,CAAS,CAAC,CAAA,GAAI,CAAA,GAAI,CAAA;AAClC;AAWA,eAAsB,YAAY,MAAA,EAOK;AACrC,EAAA,MAAM,MAAA,GAAS,SAAA,CAAU,MAAA,CAAO,aAAA,EAAe,OAAO,UAAU,CAAA;AAChE,EAAA,MAAM,eAAA,GAAkB,KAAK,GAAA,CAAI,IAAA,EAAO,KAAK,GAAA,CAAI,MAAA,CAAO,QAAA,EAAU,IAAI,CAAC,CAAA;AAEvE,EAAA,MAAM,UAAA,GAAa,MAAM,MAAA,CAAO,UAAA,CAAW;AAAA,IACzC,MAAA,EAAQ,OAAO,KAAA,CAAM,UAAA;AAAA,IACrB,WAAW,MAAA,CAAO,SAAA;AAAA,IAClB,QAAA,EAAU,eAAA;AAAA,IACV,KAAK,MAAA,CAAO;AAAA,GACb,CAAA;AAED,EAAA,OAAO,UAAA;AACT;;;AC7YA,WAAA,EAAA;AAUO,IAAM,cAAA,GAAN,cAA6B,UAAA,CAAW;AAAA,EACpC,IAAA;AAAA,EACA,OAAA;AAAA,EAET,WAAA,CAAY,IAAA,EAAqB,OAAA,EAAgC,OAAA,EAAkB;AACjF,IAAA,MAAM,GAAA,GAAM,OAAA,IAAW,YAAA,CAAa,IAAA,EAAM,OAAO,CAAA;AACjD,IAAA,KAAA,CAAM,qBAA4B,GAAA,EAAK,EAAE,IAAA,EAAM,GAAG,SAAS,CAAA;AAC3D,IAAA,IAAA,CAAK,IAAA,GAAO,gBAAA;AACZ,IAAA,IAAA,CAAK,IAAA,GAAO,IAAA;AACZ,IAAA,IAAA,CAAK,OAAA,GAAU,OAAA;AAAA,EACjB;AAAA,EAES,MAAA,GAAS;AAChB,IAAA,OAAO;AAAA,MACL,KAAA,EAAO,mBAAA;AAAA,MACP,SAAS,IAAA,CAAK,OAAA;AAAA,MACd,WAAW,IAAA,CAAK,SAAA;AAAA,MAChB,MAAM,EAAE,IAAA,EAAM,KAAK,IAAA,EAAM,GAAG,KAAK,OAAA;AAAQ,KAC3C;AAAA,EACF;AACF;AAEA,SAAS,YAAA,CAAa,MAAqB,OAAA,EAAwC;AACjF,EAAA,QAAQ,IAAA;AAAM,IACZ,KAAK,QAAA;AACH,MAAA,OAAO,6CAAA;AAAA,IACT,KAAK,UAAA;AACH,MAAA,OAAO,CAAA,QAAA,EAAA,CAAY,OAAA,CAAQ,SAAA,IAAa,CAAA,EAAG,OAAA,CAAQ,CAAC,CAAC,CAAA,iCAAA,EAAA,CAAqC,OAAA,CAAQ,KAAA,IAAS,CAAA,EAAG,OAAA,CAAQ,CAAC,CAAC,CAAA,CAAA,CAAA;AAAA,IAC1H,KAAK,cAAA;AACH,MAAA,OAAO,CAAA,2BAAA,EAAA,CAA+B,OAAA,CAAQ,OAAA,IAAW,CAAA,EAAG,OAAA,CAAQ,CAAC,CAAC,CAAA,EAAA,EAAA,CAAM,OAAA,CAAQ,KAAA,IAAS,CAAA,EAAG,OAAA,CAAQ,CAAC,CAAC,CAAA,YAAA,CAAA;AAAA;AAEhH;;;ACpBO,IAAM,YAAA,uBAAmB,GAAA,CAA6B;AAAA,EAC3D,MAAA;AAAA,EACA;AACF,CAAC;AAEM,IAAM,wBAAA,GAA4C;AAAA,EACvD,MAAA,EAAQ,KAAA;AAAA,EACR,QAAA,EAAU,CAAA;AAAA,EACV,YAAA,EAAc,CAAA;AAAA,EACd,SAAA,EAAW,CAAA;AAAA,EACX,cAAA,EAAgB;AAClB;;;AVqGA,mBAAA,EAAA","file":"browser.js","sourcesContent":["export type T2000ErrorCode =\n | 'INSUFFICIENT_BALANCE'\n | 'INSUFFICIENT_GAS'\n | 'INVALID_ADDRESS'\n | 'INVALID_AMOUNT'\n | 'WALLET_NOT_FOUND'\n | 'WALLET_LOCKED'\n | 'WALLET_EXISTS'\n | 'WALLET_CORRUPT'\n | 'INVALID_KEY'\n | 'SIMULATION_FAILED'\n | 'TRANSACTION_FAILED'\n | 'ASSET_NOT_SUPPORTED'\n | 'INVALID_ASSET'\n | 'HEALTH_FACTOR_TOO_LOW'\n | 'WITHDRAW_WOULD_LIQUIDATE'\n | 'WITHDRAW_FAILED'\n | 'NO_COLLATERAL'\n | 'PROTOCOL_PAUSED'\n | 'PROTOCOL_UNAVAILABLE'\n | 'RPC_ERROR'\n | 'RPC_UNREACHABLE'\n | 'PRICE_EXCEEDS_LIMIT'\n | 'UNSUPPORTED_NETWORK'\n | 'PAYMENT_EXPIRED'\n | 'DUPLICATE_PAYMENT'\n | 'FACILITATOR_REJECTION'\n | 'CONTACT_NOT_FOUND'\n | 'INVALID_CONTACT_NAME'\n | 'SUINS_NOT_REGISTERED'\n | 'FACILITATOR_TIMEOUT'\n | 'SAFEGUARD_BLOCKED'\n | 'SWAP_NO_ROUTE'\n | 'SWAP_FAILED'\n | 'CHAIN_MODE_INVALID'\n | 'UNKNOWN';\n\nexport interface T2000ErrorData {\n reason?: string;\n [key: string]: unknown;\n}\n\nexport class T2000Error extends Error {\n readonly code: T2000ErrorCode;\n readonly data?: T2000ErrorData;\n readonly retryable: boolean;\n\n constructor(code: T2000ErrorCode, message: string, data?: T2000ErrorData, retryable = false) {\n super(message);\n this.name = 'T2000Error';\n this.code = code;\n this.data = data;\n this.retryable = retryable;\n }\n\n toJSON() {\n return {\n error: this.code,\n message: this.message,\n ...(this.data && { data: this.data }),\n retryable: this.retryable,\n };\n }\n}\n\nexport function mapWalletError(error: unknown): T2000Error {\n const msg = error instanceof Error ? error.message : String(error);\n\n if (msg.includes('rejected') || msg.includes('cancelled')) {\n return new T2000Error('TRANSACTION_FAILED', 'Transaction cancelled');\n }\n if (msg.includes('Insufficient') || msg.includes('insufficient')) {\n return new T2000Error('INSUFFICIENT_BALANCE', 'Insufficient balance');\n }\n\n return new T2000Error('UNKNOWN', msg, undefined, true);\n}\n\nexport function mapMoveAbortCode(code: number): string {\n const abortMessages: Record<number, string> = {\n 1: 'Protocol is temporarily paused',\n 2: 'Amount must be greater than zero',\n 3: 'Invalid operation type',\n 4: 'Fee rate exceeds maximum',\n 5: 'Insufficient treasury balance',\n 6: 'Not authorized',\n 7: 'Package version mismatch — upgrade required',\n 8: 'Timelock is active — wait for expiry',\n 9: 'No pending change to execute',\n 10: 'Already at current version',\n // NAVI Protocol abort codes\n 1502: 'Oracle price is stale — try again in a moment',\n 1503: 'Withdrawal amount is invalid (zero or dust) — try a specific amount instead of \"all\"',\n 1600: 'Health factor too low — withdrawal would risk liquidation',\n 1605: 'Asset borrowing is disabled or at capacity on this protocol',\n // NAVI utils abort codes\n 46000: 'Insufficient balance to repay — withdraw some savings first to get cash',\n };\n return abortMessages[code] ?? `Move abort code: ${code}`;\n}\n\n/**\n * Check if an error message contains a MoveAbort — these are on-chain\n * failures that will fail no matter how many times you retry.\n */\nexport function isMoveAbort(msg: string): boolean {\n return msg.includes('MoveAbort') || msg.includes('MovePrimitiveRuntimeError');\n}\n\nexport function parseMoveAbortMessage(msg: string): string {\n const abortMatch = msg.match(/abort code:\\s*(\\d+)/i) ?? msg.match(/MoveAbort[^,]*,\\s*(\\d+)/);\n if (abortMatch) {\n const code = parseInt(abortMatch[1], 10);\n\n const moduleMatch = msg.match(/Identifier\\(\"([^\"]+)\"\\)/) ?? msg.match(/in '([^']+)'/);\n const fnMatch = msg.match(/function_name:\\s*Some\\(\"([^\"]+)\"\\)/);\n const context = `${moduleMatch?.[1] ?? ''}${fnMatch ? `::${fnMatch[1]}` : ''}`.toLowerCase();\n const suffix = moduleMatch\n ? ` [${moduleMatch[1]}${fnMatch ? `::${fnMatch[1]}` : ''}]`\n : '';\n\n if (context.includes('slippage')) {\n return `Slippage too high — price moved during execution${suffix}`;\n }\n if (context.includes('balance::split') || context.includes('balance::ENotEnough')) {\n return `Insufficient on-chain balance${suffix}`;\n }\n\n const mapped = mapMoveAbortCode(code);\n return `${mapped}${suffix}`;\n }\n return msg;\n}\n","/**\n * Unified token registry — single source of truth for coin types, decimals, symbols, and tiers.\n *\n * ZERO heavy dependencies. Safe to import from any context (server, browser, Edge).\n *\n * Tier 1: USDC — the financial layer (save, borrow, receive, yield, allowances, marketplace, MPP).\n * Tier 2: 15 curated swap assets — hold, trade, and send only.\n * No tier: Legacy tokens kept for display accuracy (existing NAVI positions). No new operations.\n *\n * To add a new token: add ONE entry to COIN_REGISTRY below. Everything else derives from it.\n * Gate for Tier 2 addition: confirmed deep Cetus liquidity + clear user need.\n */\n\nexport interface CoinMeta {\n type: string;\n decimals: number;\n symbol: string;\n tier?: 1 | 2;\n}\n\n/**\n * Canonical coin registry.\n * Key = user-friendly name (used in swap_execute, CLI, prompts).\n */\nexport const COIN_REGISTRY: Record<string, CoinMeta> = {\n // ── Tier 1 — Financial layer ──────────────────────────────────────────\n USDC: { type: '0xdba34672e30cb065b1f93e3ab55318768fd6fef66c15942c9f7cb846e2f900e7::usdc::USDC', decimals: 6, symbol: 'USDC', tier: 1 },\n\n // ── Tier 2 — Swap assets (15 tokens) ──────────────────────────────────\n SUI: { type: '0x2::sui::SUI', decimals: 9, symbol: 'SUI', tier: 2 },\n wBTC: { type: '0x0041f9f9344cac094454cd574e333c4fdb132d7bcc9379bcd4aab485b2a63942::wbtc::WBTC', decimals: 8, symbol: 'wBTC', tier: 2 },\n ETH: { type: '0xd0e89b2af5e4910726fbcd8b8dd37bb79b29e5f83f7491bca830e94f7f226d29::eth::ETH', decimals: 8, symbol: 'ETH', tier: 2 },\n GOLD: { type: '0x9d297676e7a4b771ab023291377b2adfaa4938fb9080b8d12430e4b108b836a9::xaum::XAUM', decimals: 9, symbol: 'GOLD', tier: 2 },\n DEEP: { type: '0xdeeb7a4662eec9f2f3def03fb937a663dddaa2e215b8078a284d026b7946c270::deep::DEEP', decimals: 6, symbol: 'DEEP', tier: 2 },\n WAL: { type: '0x356a26eb9e012a68958082340d4c4116e7f55615cf27affcff209cf0ae544f59::wal::WAL', decimals: 9, symbol: 'WAL', tier: 2 },\n NS: { type: '0x5145494a5f5100e645e4b0aa950fa6b68f614e8c59e17bc5ded3495123a79178::ns::NS', decimals: 6, symbol: 'NS', tier: 2 },\n IKA: { type: '0x7262fb2f7a3a14c888c438a3cd9b912469a58cf60f367352c46584262e8299aa::ika::IKA', decimals: 9, symbol: 'IKA', tier: 2 },\n CETUS: { type: '0x06864a6f921804860930db6ddbe2e16acdf8504495ea7481637a1c8b9a8fe54b::cetus::CETUS', decimals: 9, symbol: 'CETUS', tier: 2 },\n NAVX: { type: '0xa99b8952d4f7d947ea77fe0ecdcc9e5fc0bcab2841d6e2a5aa00c3044e5544b5::navx::NAVX', decimals: 9, symbol: 'NAVX', tier: 2 },\n vSUI: { type: '0x549e8b69270defbfafd4f94e17ec44cdbdd99820b33bda2278dea3b9a32d3f55::cert::CERT', decimals: 9, symbol: 'vSUI', tier: 2 },\n haSUI: { type: '0xbde4ba4c2e274a60ce15c1cfff9e5c42e41654ac8b6d906a57efa4bd3c29f47d::hasui::HASUI', decimals: 9, symbol: 'haSUI', tier: 2 },\n afSUI: { type: '0xf325ce1300e8dac124071d3152c5c5ee6174914f8bc2161e88329cf579246efc::afsui::AFSUI', decimals: 9, symbol: 'afSUI', tier: 2 },\n LOFI: { type: '0xf22da9a24ad027cccb5f2d496cbe91de953d363513db08a3a734d361c7c17503::LOFI::LOFI', decimals: 9, symbol: 'LOFI', tier: 2 },\n MANIFEST: { type: '0xc466c28d87b3d5cd34f3d5c088751532d71a38d93a8aae4551dd56272cfb4355::manifest::MANIFEST', decimals: 9, symbol: 'MANIFEST', tier: 2 },\n\n // ── Legacy — no tier, kept for display accuracy on existing positions ──\n USDT: { type: '0x375f70cf2ae4c00bf37117d0c85a2c71545e6ee05c4a5c7d282cd66a4504b068::usdt::USDT', decimals: 6, symbol: 'USDT' },\n USDe: { type: '0x41d587e5336f1c86cad50d38a7136db99333bb9bda91cea4ba69115defeb1402::sui_usde::SUI_USDE', decimals: 6, symbol: 'USDe' },\n USDSUI: { type: '0x44f838219cf67b058f3b37907b655f226153c18e33dfcd0da559a844fea9b1c1::usdsui::USDSUI', decimals: 6, symbol: 'USDsui' },\n};\n\n/** Reverse lookup: coin type → CoinMeta. Built once at import time. */\nconst BY_TYPE = new Map<string, CoinMeta>();\nfor (const meta of Object.values(COIN_REGISTRY)) {\n BY_TYPE.set(meta.type, meta);\n}\n\n// ── Lookup helpers ───────────────────────────────────────────────────────\n\n/**\n * Returns the registry metadata for a coin type, or `undefined` if the coin\n * is not in the registry. Use this when you need to distinguish \"known coin\"\n * from \"supported coin\" — `isSupported` only flags tiered (active) coins,\n * but legacy coins like USDsui / USDe / USDT are in the registry without a\n * tier and still need canonical-symbol resolution.\n */\nexport function getCoinMeta(coinType: string): CoinMeta | undefined {\n return BY_TYPE.get(coinType);\n}\n\n/**\n * Returns true if the coin type appears anywhere in COIN_REGISTRY (tier 1, 2,\n * OR legacy/no-tier). Different from `isSupported`, which excludes legacy\n * entries. The blockvision-prices canonical-symbol gate uses this looser\n * check so that USDsui (legacy/no-tier today, but with a registry-canonical\n * mixed-case symbol) still wins over BlockVision's uppercase 'USDSUI'.\n */\nexport function isInRegistry(coinType: string): boolean {\n return BY_TYPE.has(coinType);\n}\n\n// ── Tier helpers ─────────────────────────────────────────────────────────\n\n/** Returns true if the coin type is Tier 1 (USDC — the financial layer). */\nexport function isTier1(coinType: string): boolean {\n const meta = BY_TYPE.get(coinType);\n return meta?.tier === 1;\n}\n\n/** Returns true if the coin type is Tier 2 (curated swap asset). */\nexport function isTier2(coinType: string): boolean {\n const meta = BY_TYPE.get(coinType);\n return meta?.tier === 2;\n}\n\n/** Returns true if the coin type is actively supported (Tier 1 or Tier 2). */\nexport function isSupported(coinType: string): boolean {\n const meta = BY_TYPE.get(coinType);\n return meta?.tier !== undefined;\n}\n\n/** Returns the tier for a coin type, or undefined if legacy/unknown. */\nexport function getTier(coinType: string): 1 | 2 | undefined {\n return BY_TYPE.get(coinType)?.tier;\n}\n\n// ── Lookup helpers ───────────────────────────────────────────────────────\n\n/**\n * Get decimals for any coin type. Checks full type match, then suffix match, then defaults to 9.\n * Works for both tiered and legacy tokens.\n */\nexport function getDecimalsForCoinType(coinType: string): number {\n const direct = BY_TYPE.get(coinType);\n if (direct) return direct.decimals;\n\n const suffix = coinType.split('::').slice(1).join('::').toUpperCase();\n if (suffix) {\n for (const meta of BY_TYPE.values()) {\n const metaSuffix = meta.type.split('::').slice(1).join('::').toUpperCase();\n if (metaSuffix === suffix) return meta.decimals;\n }\n }\n\n return 9;\n}\n\n/**\n * Resolve a full coin type to a user-friendly symbol.\n * Returns the last `::` segment if not in the registry.\n */\nexport function resolveSymbol(coinType: string): string {\n const direct = BY_TYPE.get(coinType);\n if (direct) return direct.symbol;\n\n const suffix = coinType.split('::').slice(1).join('::').toUpperCase();\n if (suffix) {\n for (const meta of BY_TYPE.values()) {\n const metaSuffix = meta.type.split('::').slice(1).join('::').toUpperCase();\n if (metaSuffix === suffix) return meta.symbol;\n }\n }\n\n return coinType.split('::').pop() ?? coinType;\n}\n\n/**\n * Name → type map for swap resolution. Derived from COIN_REGISTRY.\n * Contains BOTH original-case and UPPERCASE keys for case-insensitive lookup.\n */\nexport const TOKEN_MAP: Record<string, string> = (() => {\n const map: Record<string, string> = {};\n for (const [name, meta] of Object.entries(COIN_REGISTRY)) {\n map[name] = meta.type;\n map[name.toUpperCase()] = meta.type;\n }\n return map;\n})();\n\n/**\n * Resolve a user-friendly token name to its full coin type.\n * Returns the input unchanged if already a full coin type (contains \"::\").\n * Case-insensitive: 'usde', 'USDe', 'USDE' all resolve correctly.\n */\nexport function resolveTokenType(nameOrType: string): string | null {\n if (nameOrType.includes('::')) return nameOrType;\n return TOKEN_MAP[nameOrType] ?? TOKEN_MAP[nameOrType.toUpperCase()] ?? null;\n}\n\n/** Common type constants for direct import. */\nexport const SUI_TYPE = COIN_REGISTRY.SUI.type;\nexport const USDC_TYPE = COIN_REGISTRY.USDC.type;\nexport const USDT_TYPE = COIN_REGISTRY.USDT.type;\nexport const USDSUI_TYPE = COIN_REGISTRY.USDSUI.type;\nexport const USDE_TYPE = COIN_REGISTRY.USDe.type;\nexport const ETH_TYPE = COIN_REGISTRY.ETH.type;\nexport const WBTC_TYPE = COIN_REGISTRY.wBTC.type;\nexport const WAL_TYPE = COIN_REGISTRY.WAL.type;\nexport const NAVX_TYPE = COIN_REGISTRY.NAVX.type;\nexport const IKA_TYPE = COIN_REGISTRY.IKA.type;\nexport const LOFI_TYPE = COIN_REGISTRY.LOFI.type;\nexport const MANIFEST_TYPE = COIN_REGISTRY.MANIFEST.type;\n","import type { Ed25519Keypair } from '@mysten/sui/keypairs/ed25519';\nimport type { TransactionSigner } from '../signer.js';\n\nexport class KeypairSigner implements TransactionSigner {\n constructor(private readonly keypair: Ed25519Keypair) {}\n\n getAddress(): string {\n return this.keypair.getPublicKey().toSuiAddress();\n }\n\n async signTransaction(txBytes: Uint8Array): Promise<{ signature: string }> {\n return this.keypair.signTransaction(txBytes);\n }\n\n async signPersonalMessage(messageBytes: Uint8Array): Promise<{ signature: string; bytes: string }> {\n return this.keypair.signPersonalMessage(messageBytes);\n }\n\n /** Access the underlying keypair for APIs that still require it directly. */\n getKeypair(): Ed25519Keypair {\n return this.keypair;\n }\n}\n","import type { Ed25519Keypair } from '@mysten/sui/keypairs/ed25519';\nimport type { TransactionSigner } from '../signer.js';\n\nexport interface ZkLoginProof {\n proofPoints: {\n a: string[];\n b: string[][];\n c: string[];\n };\n issBase64Details: {\n indexMod4: number;\n value: string;\n };\n headerBase64: string;\n addressSeed: string;\n}\n\nexport class ZkLoginSigner implements TransactionSigner {\n constructor(\n private readonly ephemeralKeypair: Ed25519Keypair,\n private readonly zkProof: ZkLoginProof,\n private readonly userAddress: string,\n private readonly maxEpoch: number,\n ) {}\n\n getAddress(): string {\n return this.userAddress;\n }\n\n async signTransaction(txBytes: Uint8Array): Promise<{ signature: string }> {\n const { getZkLoginSignature } = await import('@mysten/zklogin');\n const ephSig = await this.ephemeralKeypair.signTransaction(txBytes);\n return {\n signature: getZkLoginSignature({\n inputs: this.zkProof,\n maxEpoch: this.maxEpoch,\n userSignature: ephSig.signature,\n }),\n };\n }\n\n async signPersonalMessage(_messageBytes: Uint8Array): Promise<{ signature: string; bytes: string }> {\n // zkLogin personal-message signing for `@suimpp/mpp` 0.7+ grief protection\n // is not yet wired here. Audric (the only zkLogin consumer today) uses the\n // sponsored-tx flow which does not call `sdk.pay()`. Implement when audric\n // needs to drive MPP payments directly from the SDK.\n throw new Error('ZkLoginSigner.signPersonalMessage is not yet implemented. Use KeypairSigner for sdk.pay() until grief-protection signing is wired for zkLogin.');\n }\n\n isExpired(currentEpoch: number): boolean {\n return currentEpoch >= this.maxEpoch;\n }\n}\n","/**\n * Browser-safe entry point for @t2000/sdk.\n *\n * Exports everything the web app needs WITHOUT Node-only modules:\n * - keyManager (fs-based wallet encryption)\n * - ContactManager (file-based contacts)\n *\n * Protocol adapters are NOT statically exported here — import them\n * via dynamic import() in the web app to keep the initial bundle small.\n */\n\n// Signer abstraction\nexport type { TransactionSigner } from './signer.js';\nexport { KeypairSigner } from './wallet/keypairSigner.js';\nexport { ZkLoginSigner, type ZkLoginProof } from './wallet/zkLoginSigner.js';\n\n// Error handling\nexport { T2000Error, mapWalletError, mapMoveAbortCode } from './errors.js';\nexport type { T2000ErrorCode, T2000ErrorData } from './errors.js';\n\n// Constants\nexport {\n MIST_PER_SUI,\n SUI_DECIMALS,\n USDC_DECIMALS,\n BPS_DENOMINATOR,\n SAVE_FEE_BPS,\n BORROW_FEE_BPS,\n T2000_OVERLAY_FEE_WALLET,\n SUPPORTED_ASSETS,\n CLOCK_ID,\n DEFAULT_NETWORK,\n} from './constants.js';\nexport type { SupportedAsset, StableAsset } from './constants.js';\nexport {\n STABLE_ASSETS,\n ALL_NAVI_ASSETS,\n GAS_RESERVE_MIN,\n} from './constants.js';\n\n// Utilities\nexport { validateAddress, truncateAddress } from './utils/sui.js';\nexport {\n KNOWN_TARGETS,\n LABEL_PATTERNS,\n classifyAction,\n classifyLabel,\n fallbackLabel,\n refineLendingLabel,\n classifyTransaction,\n extractTransferDetails,\n extractAllUserLegs,\n} from './wallet/classify.js';\nexport type {\n ClassifyBalanceChange,\n ClassifyResult,\n ExtractedTransfer,\n TxDirection,\n} from './wallet/classify.js';\n/**\n * RPC tx parsing helpers. Safe in the browser — they only do shape\n * inspection / classification and do not import any Node-only modules.\n * `queryHistory` and `queryTransaction` are not re-exported here\n * because they take a Node `SuiJsonRpcClient`; consumers can build\n * the same flow with `parseSuiRpcTx` + their own RPC fetch.\n */\nexport {\n parseSuiRpcTx,\n extractTxSender,\n extractTxCommands,\n} from './wallet/history.js';\nexport type { SuiRpcTxBlock } from './wallet/history.js';\nexport {\n mistToSui,\n suiToMist,\n usdcToRaw,\n rawToUsdc,\n stableToRaw,\n rawToStable,\n getDecimals,\n formatUsd,\n formatSui,\n formatAssetAmount,\n} from './utils/format.js';\nexport { toBase64, fromBase64 } from './utils/base64.js';\n\n// Simulation — use dynamic import() to avoid Buffer dependency in browser bundles\n// import { simulateTransaction } from '@t2000/sdk' (main entry) for Node usage\nexport type { SimulationResult } from './utils/simulate.js';\n\n// Protocol fee\nexport { calculateFee, addFeeTransfer } from './protocols/protocolFee.js';\nexport type { ProtocolFeeInfo, FeeOperation } from './protocols/protocolFee.js';\n\n// Cetus aggregator helpers — Audric prepare/route.ts uses these directly to\n// build swap PTBs with overlay fees (per-call, not module-global).\nexport { findSwapRoute, buildSwapTx, OVERLAY_FEE_RATE } from './protocols/cetus-swap.js';\nexport type { SwapRouteResult, OverlayFeeConfig } from './protocols/cetus-swap.js';\n\n// Safeguards — only browser-safe exports (SafeguardEnforcer uses node:fs)\nexport { SafeguardError } from './safeguards/errors.js';\nexport type { SafeguardRule, SafeguardErrorDetails } from './safeguards/errors.js';\nexport type { SafeguardConfig, TxMetadata } from './safeguards/types.js';\nexport { OUTBOUND_OPS, DEFAULT_SAFEGUARD_CONFIG } from './safeguards/types.js';\n\n// Types\nexport type {\n BalanceResponse,\n GasReserve,\n SendResult,\n SaveResult,\n WithdrawResult,\n BorrowResult,\n RepayResult,\n HealthFactorResult,\n MaxWithdrawResult,\n MaxBorrowResult,\n AssetRates,\n RatesResult,\n PositionEntry,\n PositionsResult,\n EarningsResult,\n FundStatusResult,\n DepositInfo,\n TransactionRecord,\n TransactionLeg,\n ClaimRewardsResult,\n PendingReward,\n PayOptions,\n PayResult,\n} from './types.js';\n\n// Token registry — zero Node.js deps, safe for client-side use\nexport {\n COIN_REGISTRY,\n TOKEN_MAP,\n resolveTokenType,\n resolveSymbol,\n getDecimalsForCoinType,\n isTier1,\n isTier2,\n isSupported,\n getTier,\n SUI_TYPE,\n USDC_TYPE,\n USDT_TYPE,\n USDSUI_TYPE,\n USDE_TYPE,\n ETH_TYPE,\n WBTC_TYPE,\n WAL_TYPE,\n NAVX_TYPE,\n IKA_TYPE,\n LOFI_TYPE,\n MANIFEST_TYPE,\n} from './token-registry.js';\nexport type { CoinMeta } from './token-registry.js';\n","import { T2000Error } from './errors.js';\n\nexport const MIST_PER_SUI = 1_000_000_000n;\nexport const SUI_DECIMALS = 9;\nexport const USDC_DECIMALS = 6;\n\nexport const BPS_DENOMINATOR = 10_000n;\nexport const PRECISION = 1_000_000_000_000_000_000n;\n\nexport const MIN_DEPOSIT = 1_000_000n; // 1 USDC (6 decimals)\n\nexport const SAVE_FEE_BPS = 10n; // 0.1%\nexport const BORROW_FEE_BPS = 5n; // 0.05%\n\nexport const CLOCK_ID = '0x6';\n\nexport const SUPPORTED_ASSETS = {\n USDC: {\n type: '0xdba34672e30cb065b1f93e3ab55318768fd6fef66c15942c9f7cb846e2f900e7::usdc::USDC',\n decimals: 6,\n symbol: 'USDC',\n displayName: 'USDC',\n },\n USDT: {\n type: '0x375f70cf2ae4c00bf37117d0c85a2c71545e6ee05c4a5c7d282cd66a4504b068::usdt::USDT',\n decimals: 6,\n symbol: 'USDT',\n displayName: 'suiUSDT',\n },\n USDe: {\n type: '0x41d587e5336f1c86cad50d38a7136db99333bb9bda91cea4ba69115defeb1402::sui_usde::SUI_USDE',\n decimals: 6,\n symbol: 'USDe',\n displayName: 'suiUSDe',\n },\n USDsui: {\n type: '0x44f838219cf67b058f3b37907b655f226153c18e33dfcd0da559a844fea9b1c1::usdsui::USDSUI',\n decimals: 6,\n symbol: 'USDsui',\n displayName: 'USDsui',\n },\n SUI: {\n type: '0x2::sui::SUI',\n decimals: 9,\n symbol: 'SUI',\n displayName: 'SUI',\n },\n WAL: {\n type: '0x356a26eb9e012a68958082340d4c4116e7f55615cf27affcff209cf0ae544f59::wal::WAL',\n decimals: 9,\n symbol: 'WAL',\n displayName: 'WAL',\n },\n ETH: {\n type: '0xd0e89b2af5e4910726fbcd8b8dd37bb79b29e5f83f7491bca830e94f7f226d29::eth::ETH',\n decimals: 8,\n symbol: 'ETH',\n displayName: 'suiETH',\n },\n NAVX: {\n type: '0xa99b8952d4f7d947ea77fe0ecdcc9e5fc0bcab2841d6e2a5aa00c3044e5544b5::navx::NAVX',\n decimals: 9,\n symbol: 'NAVX',\n displayName: 'NAVX',\n },\n GOLD: {\n type: '0x9d297676e7a4b771ab023291377b2adfaa4938fb9080b8d12430e4b108b836a9::xaum::XAUM',\n decimals: 6,\n symbol: 'GOLD',\n displayName: 'XAUM',\n },\n} as const;\n\nexport type SupportedAsset = keyof typeof SUPPORTED_ASSETS;\n\n// [SPEC_AGENTIC_STACK P1 / SDK F3 — 2026-05-25]\n// `StableAsset` = \"what we treat as worth $1 for wallet pricing and balance roll-up\".\n// Pre-Phase 1: USDC only — left USDsui wallet holdings invisible to balance.ts.\n// Phase 1: widened to USDC + USDsui (both are NAVI-native stables with $1 peg).\n// USDT / USDe stay OUT of this set deliberately — they are stables, but the\n// codebase has never priced them at $1, and adding them here would require\n// auditing balance.ts callers downstream. Keep the carve minimal.\nexport type StableAsset = 'USDC' | 'USDsui';\nexport const STABLE_ASSETS: readonly StableAsset[] = ['USDC', 'USDsui'] as const;\n\n// [SPEC_AGENTIC_STACK P1 / SDK F4 — 2026-05-25]\n// `SaveableAsset` = \"what you can deposit into a NAVI lending pool to earn yield\".\n// Semantically distinct from STABLE_ASSETS even though the sets are identical today:\n// if USDe-on-NAVI lands in the future, USDe would join STABLE_ASSETS but NOT\n// SAVEABLE_ASSETS until the NAVI USDe pool is verified live.\n// See `.cursor/rules/savings-usdc-only.mdc` for the rule that gates additions.\nexport type SaveableAsset = 'USDC' | 'USDsui';\nexport const SAVEABLE_ASSETS: readonly SaveableAsset[] = ['USDC', 'USDsui'] as const;\n\nexport const ALL_NAVI_ASSETS: readonly SupportedAsset[] = Object.keys(SUPPORTED_ASSETS) as SupportedAsset[];\n\n// ---------------------------------------------------------------------------\n// Operation → allowed asset rules (single source of truth)\n// ---------------------------------------------------------------------------\n\n// [v0.51.0] Saveable/borrowable set: USDC + USDsui.\n// USDC is the canonical default; USDsui is a strategic exception backed by an\n// existing NAVI pool. See `.cursor/rules/savings-usdc-only.mdc` for the\n// rationale and the rule that gates additional stables (don't add more here\n// without updating that file).\n//\n// [v4.0 Phase A Day 2 — 2026-05-26] `send` constrained from `'*'` (any) to\n// `['USDC', 'USDsui', 'SUI']`. Rationale (SPEC_AGENT_WALLET_GREENFIELD §A):\n// - USDC + USDsui are gasless via `0x2::balance::send_funds` (Sui mainnet\n// protocol allowlist) — the two foundation stables.\n// - SUI is the only non-stable kept on the allowlist so users with no\n// stablecoin balance can still pay gas-native SUI transfers.\n// - USDT, USDe, WAL, ETH, NAVX, GOLD are NOT sendable — users must swap to\n// USDC/USDsui first (one-step) or hold SUI and use a manual Move call.\n// - Tracking the full Sui gasless allowlist (suiUSDe, USDY, FDUSD, AUSD, USDB)\n// is intentionally deferred to follow-up SPEC; minimal allowlist now.\nexport const OPERATION_ASSETS = {\n save: ['USDC', 'USDsui'],\n borrow: ['USDC', 'USDsui'],\n withdraw: '*',\n repay: '*',\n send: ['USDC', 'USDsui', 'SUI'],\n swap: '*',\n} as const;\n\nexport type Operation = keyof typeof OPERATION_ASSETS;\n\nexport function isAllowedAsset(op: Operation, asset: string): boolean {\n const allowed = OPERATION_ASSETS[op];\n if (allowed === '*') return true;\n // [v0.51.0] Mixed-case canonical keys (USDsui, suiUSDT) need case-insensitive\n // membership. Pre-v0.51 we only had USDC ↔ USDC (uppercase identity), so\n // a one-sided uppercase compare looked correct. Now that USDsui is in the\n // set, normalize both sides.\n const target = asset.toLowerCase();\n return (allowed as readonly string[]).some((a) => a.toLowerCase() === target);\n}\n\n/**\n * Throws if the asset is not permitted for the given operation.\n *\n * [v4.0 Phase A Day 2] Pre-v4 this allowed `undefined` as a silent default\n * to USDC. Removed because every write path now requires explicit asset\n * (see `T2000.send` + `buildSendTx` + `composeTx.send_transfer`). Save /\n * borrow / repay still call this with `params.asset` (which may be\n * undefined when the caller relies on the per-method `?? 'USDC'` default\n * before this assertion fires), so the `undefined → no-op` branch stays\n * for back-compat; the `send_transfer` flow validates non-undefined.\n */\nexport function assertAllowedAsset(op: Operation, asset: string | undefined): void {\n if (!asset) return;\n if (!isAllowedAsset(op, asset)) {\n const allowed = OPERATION_ASSETS[op];\n const list = Array.isArray(allowed) ? allowed.join(', ') : 'any';\n const swapHint =\n op === 'save' ? ' Swap to USDC or USDsui first.'\n : op === 'send' ? ' Swap to USDC or USDsui first, or send SUI.'\n : '';\n throw new T2000Error(\n 'INVALID_ASSET',\n `${op} only supports ${list}. Cannot use ${asset}.${swapHint}`,\n );\n }\n}\n\n/**\n * [v4.0 Phase A Day 2] Narrow type alias for assets sendable through the\n * Agent Wallet. Matches `OPERATION_ASSETS.send` exactly. Exported so the\n * CLI / SDK / composeTx can share one type without re-declaring it.\n */\nexport type SendableAsset = 'USDC' | 'USDsui' | 'SUI';\nexport const SENDABLE_ASSETS: readonly SendableAsset[] = ['USDC', 'USDsui', 'SUI'] as const;\n\n/**\n * [v4.0 Phase A Day 2] Coin types for the two gasless-allowlisted stables.\n * Used by `wallet/send.ts` + `composeTx.send_transfer` to construct the\n * `0x2::balance::send_funds` Move call's `typeArguments`. SUI is excluded\n * because SUI transfers are NOT gasless (gas-native, uses `tx.gas` split +\n * `transferObjects` per the existing path).\n */\nexport const GASLESS_STABLE_TYPES: Record<'USDC' | 'USDsui', string> = {\n USDC: SUPPORTED_ASSETS.USDC.type,\n USDsui: SUPPORTED_ASSETS.USDsui.type,\n};\n\n// All protocol fees route here as a regular USDC wallet transfer. Audric's\n// prepare/route.ts adds `addFeeTransfer(...)` inline for save/borrow and passes\n// `overlayFee.receiver = T2000_OVERLAY_FEE_WALLET` for swaps. The CLI/SDK never\n// charge fees — this constant is exported for consumer apps only.\n//\n// Address corresponds to the treasury admin wallet. Override via env for local dev /\n// testnet only — production must use the canonical mainnet address below.\nexport const T2000_OVERLAY_FEE_WALLET = process.env.T2000_OVERLAY_FEE_WALLET\n ?? '0x5366efbf2b4fe5767fe2e78eb197aa5f5d138d88ac3333fbf3f80a1927da473a';\n\nexport const DEFAULT_NETWORK = 'mainnet' as const;\nexport const DEFAULT_RPC_URL = 'https://fullnode.mainnet.sui.io:443';\n// [v4.0 Phase A Day 2] gRPC fullnode endpoint used by `getSuiGrpcClient()` for\n// gasless stablecoin transfer detection (T2000.send + composeTx send_transfer).\n// Reads stay JSON-RPC; only write paths that need gasless eligibility detection\n// build via gRPC. Override with T2000_GRPC_URL for local dev / testnet.\nexport const DEFAULT_GRPC_URL = 'https://fullnode.mainnet.sui.io:443';\nexport const DEFAULT_KEY_PATH = '~/.t2000/wallet.key';\nexport const DEFAULT_CONFIG_PATH = '~/.t2000/config.json';\n\n// [v4.0 Phase A Day 2] Minimum stablecoin amount for protocol-level gasless\n// transfers via `0x2::balance::send_funds`. The Sui mainnet allowlist enforces\n// this floor at the protocol level to prevent dust spam; we surface a clear\n// error before signing rather than letting the tx revert on-chain.\nexport const GASLESS_MIN_STABLE_AMOUNT = 0.01;\n\nexport const API_BASE_URL = process.env.T2000_API_URL ?? 'https://api.t2000.ai';\n\n// Cetus USDC/SUI pool — read-only for SUI price oracle (no SDK dependency)\nexport const CETUS_USDC_SUI_POOL = '0x51e883ba7c0b566a26cbc8a94cd33eb0abd418a77cc1e60ad22fd9b1f29cd2ab';\n\nexport const GAS_RESERVE_MIN = 0.05; // minimum SUI to keep for gas\n","import { SuiJsonRpcClient, getJsonRpcFullnodeUrl } from '@mysten/sui/jsonRpc';\nimport { SuiGrpcClient } from '@mysten/sui/grpc';\nimport { isValidSuiAddress, normalizeSuiAddress } from '@mysten/sui/utils';\nimport { DEFAULT_GRPC_URL, DEFAULT_RPC_URL } from '../constants.js';\nimport { T2000Error } from '../errors.js';\n\n/**\n * Resolve the effective JSON-RPC URL: explicit arg > env var > default.\n * `T2000_RPC_URL` is an OPTIONAL override per the Greenfield SPEC's env\n * contract — no required vars, so we read inline (allowed by\n * `env-validation-gate.mdc` carve-out for packages with zero required\n * env vars).\n */\nfunction resolveRpcUrl(rpcUrl?: string): string {\n if (rpcUrl) return rpcUrl;\n const envUrl = process.env.T2000_RPC_URL?.trim();\n if (envUrl) return envUrl;\n return DEFAULT_RPC_URL;\n}\n\n/**\n * Same shape as `resolveRpcUrl` for the gRPC endpoint.\n */\nfunction resolveGrpcUrl(grpcUrl?: string): string {\n if (grpcUrl) return grpcUrl;\n const envUrl = process.env.T2000_GRPC_URL?.trim();\n if (envUrl) return envUrl;\n return DEFAULT_GRPC_URL;\n}\n\n/**\n * JSON-RPC client cache, keyed by URL. The earlier impl cached\n * unconditionally and ignored URL changes after the first call —\n * brittle for testnet smokes and custom-RPC test setups.\n */\nconst rpcClientCache = new Map<string, SuiJsonRpcClient>();\n\nexport function getSuiClient(rpcUrl?: string): SuiJsonRpcClient {\n const url = resolveRpcUrl(rpcUrl);\n const cached = rpcClientCache.get(url);\n if (cached) return cached;\n const client = new SuiJsonRpcClient({ url, network: 'mainnet' });\n rpcClientCache.set(url, client);\n return client;\n}\n\nexport function createSuiClient(network: 'mainnet' | 'testnet' = 'mainnet'): SuiJsonRpcClient {\n return new SuiJsonRpcClient({ url: getJsonRpcFullnodeUrl(network), network });\n}\n\n/**\n * gRPC client cache, keyed by URL. Same rationale as the JSON-RPC cache:\n * different URLs must produce different clients.\n */\nconst grpcClientCache = new Map<string, SuiGrpcClient>();\n\n/**\n * Cached `SuiGrpcClient` for gasless stablecoin transfer builds.\n *\n * [v4.0 Phase A Day 2 — SPEC_AGENT_WALLET_GREENFIELD §A]\n *\n * Why this exists: Sui mainnet's protocol-level gasless stablecoin transfers\n * (`0x2::balance::send_funds` on the USDC + USDsui allowlist) are detected\n * ONLY when the transaction is built through a `SuiGrpcClient`. The gRPC\n * client's build resolver inspects the PTB at `tx.build()` time and, if it\n * matches the gasless pattern, sets `gasPrice=0` + `gasBudget=0` automatically.\n * Building the SAME PTB through `SuiJsonRpcClient` produces the same bytes\n * but with non-zero gas — the tx still works, but the user pays SUI gas.\n *\n * Execution stays on JSON-RPC (`SuiJsonRpcClient.executeTransactionBlock`)\n * because (a) the rest of the SDK expects JSON-RPC and (b) Sui's docs\n * explicitly support a \"build via gRPC, execute via JSON-RPC\" hybrid:\n * https://docs.sui.io/develop/transaction-payment/gasless-stablecoin-transfers\n *\n * Override the endpoint with the `T2000_GRPC_URL` env var or the\n * `grpcUrl` arg. Cache is keyed by URL so multiple endpoints can\n * co-exist (e.g., the rare testnet smoke + production usage from the\n * same process).\n */\nexport function getSuiGrpcClient(grpcUrl?: string): SuiGrpcClient {\n const baseUrl = resolveGrpcUrl(grpcUrl);\n const cached = grpcClientCache.get(baseUrl);\n if (cached) return cached;\n const client = new SuiGrpcClient({ baseUrl, network: 'mainnet' });\n grpcClientCache.set(baseUrl, client);\n return client;\n}\n\nexport function validateAddress(address: string): string {\n const normalized = normalizeSuiAddress(address);\n if (!isValidSuiAddress(normalized)) {\n throw new T2000Error('INVALID_ADDRESS', `Invalid Sui address: ${address}`);\n }\n return normalized;\n}\n\nexport function truncateAddress(address: string): string {\n if (address.length <= 10) return address;\n return `${address.slice(0, 6)}...${address.slice(-4)}`;\n}\n\n/**\n * Normalize a Sui coin type to its canonical long-form 64-hex address.\n * `0x2::sui::SUI` → `0x0000…0002::sui::SUI`. Idempotent on already-long\n * forms. Returns the input unchanged if it doesn't look like a coin type\n * (`<address>::<module>::<name>`) so callers can pass arbitrary strings\n * without crashing.\n *\n * Why this exists: BlockVision's `/v2/sui/coin/price/list` endpoint\n * silently returns an empty `prices` map for short-form coin types\n * (notably `0x2::sui::SUI` — the native gas coin). Internal callers must\n * pass the long form, but external callers (LLM tool args, cached\n * coin-type strings, audit logs) commonly use the short form. Normalize\n * before the network call, denormalize back to the caller's input shape\n * after, and short/long become interchangeable.\n */\nexport function normalizeCoinType(coinType: string): string {\n const parts = coinType.split('::');\n if (parts.length !== 3) return coinType;\n const [addr, mod, name] = parts;\n if (!addr.startsWith('0x')) return coinType;\n return `${normalizeSuiAddress(addr)}::${mod}::${name}`;\n}\n","/**\n * Shared transaction classifier.\n *\n * Consumed by both the SDK's `parseTxRecord` (production agent path) and\n * the engine's `transaction_history` tool (cold-start RPC path). Keeping\n * a single source of truth here prevents the two paths from drifting —\n * see v1.5.3 regression where the SDK path was emitting `action:\n * 'transaction'` (rendered as \"On-chain\") while the engine path was\n * already producing fine-grained labels.\n */\n\nimport { getDecimalsForCoinType, resolveSymbol, SUI_TYPE } from '../token-registry.js';\n\n/**\n * Coarse action bucket — one of `'send' | 'lending' | 'swap' |\n * 'transaction'`. Used by the ACI `action` filter on the\n * `transaction_history` tool. STABLE: downstream queries depend on\n * exactly these values.\n *\n * Order matters: more specific buckets first. Lending patterns precede\n * swap patterns so a NAVI `::swap` helper (if one ever existed) would\n * still bucket as lending.\n */\nexport const KNOWN_TARGETS: readonly [RegExp, string][] = [\n [/::suilend|::obligation/, 'lending'],\n [/::navi|::lending_core|::incentive_v\\d+|::oracle_pro/, 'lending'],\n /**\n * DEX modules — both direct calls and aggregator legs. The Cetus\n * aggregator dispatches through a per-DEX module (e.g.\n * `cetus::swap`, `flowx_amm::swap`, `aftermath::swap`, …) plus\n * router glue functions. We list every DEX module the aggregator\n * supports today so a single-DEX call still classifies cleanly.\n */\n [/::cetus(?:_dlmm)?::|::pool::|::deepbook|::flowx_(?:amm|clmm)::|::kriya_(?:amm|clmm)::|::turbos::|::aftermath::|::afsui::|::bluefin::|::bluemove::|::ferra_(?:clmm|dlmm)::|::haedal_hmm::|::hasui::|::hawal::|::magma::|::momentum::|::obric::|::springsui::|::steamm_cpmm::|::fullsail::|::alphafi::|::volo_swap::/, 'swap'],\n /**\n * Cetus aggregator router glue. These are the swap-context and\n * balance-handling helpers the aggregator emits around per-DEX\n * legs. Without this entry a tx that ONLY had router calls\n * (theoretically possible for setup/cleanup) would slip through;\n * in practice these always coexist with a DEX leg, but the entry\n * is cheap insurance.\n */\n [/::router::(?:new_swap_context(?:_v)?|confirm_swap|transfer_balance|take_balance|transfer_or_destroy_coin)/, 'swap'],\n [/::transfer::public_transfer/, 'send'],\n];\n\n/**\n * Finer-grained display labels — derived from MoveCall function names.\n * The card renders `label ?? action`, so when this map matches we get\n * \"Deposit\" / \"Withdraw\" / \"Borrow\" / \"Repay\" / \"Payment link\" instead\n * of the generic \"Lending\" or \"Transaction\".\n *\n * Order matters: more specific patterns first. Each entry is\n * (regex, label) where the regex is matched against the\n * fully-qualified MoveCall target `pkg::module::function`.\n */\nexport const LABEL_PATTERNS: readonly [RegExp, string][] = [\n [/::pay(?:ment_kit|_kit)?::|::create_payment_link|::pay_link/, 'payment_link'],\n [/::create_invoice|::invoice::/, 'invoice'],\n [/::deposit|::supply|::mint_ctokens/, 'deposit'],\n [/::withdraw|::redeem|::redeem_ctokens/, 'withdraw'],\n [/::borrow/, 'borrow'],\n [/::repay/, 'repay'],\n [/::claim_reward|::claim::|::claim_incentive/, 'claim'],\n [/::stake/, 'stake'],\n [/::unstake|::burn::/, 'unstake'],\n [/::liquidate/, 'liquidate'],\n];\n\nexport interface ClassifyBalanceChange {\n owner: { AddressOwner?: string } | string;\n coinType: string;\n amount: string;\n}\n\nfunction resolveOwner(owner: ClassifyBalanceChange['owner']): string | null {\n if (typeof owner === 'object' && owner.AddressOwner) return owner.AddressOwner;\n if (typeof owner === 'string') return owner;\n return null;\n}\n\nexport function classifyAction(targets: string[], commandTypes: string[]): string {\n for (const target of targets) {\n for (const [pattern, label] of KNOWN_TARGETS) {\n if (pattern.test(target)) return label;\n }\n }\n if (commandTypes.includes('TransferObjects') && !commandTypes.includes('MoveCall')) return 'send';\n return 'transaction';\n}\n\n/**\n * Last-resort fallback when neither `LABEL_PATTERNS` nor the action\n * bucket produces something useful.\n *\n * Returns the first MoveCall's *module* name (e.g. \"navi\", \"spam\") so\n * the card shows something better than the literal word \"transaction\".\n * When no MoveCall exists, returns 'on-chain'.\n *\n * Note: callers should prefer `classifyLabel` which now layers\n * pattern-match → coarse action → module name (see commentary there).\n */\nexport function fallbackLabel(targets: string[]): string {\n if (!targets.length) return 'on-chain';\n const first = targets[0];\n const parts = first.split('::');\n if (parts.length >= 2 && parts[1]) return parts[1].toLowerCase();\n return 'on-chain';\n}\n\n/**\n * Three-tier label resolution for the transaction history card:\n * 1. Specific keyword match in `LABEL_PATTERNS` (\"deposit\",\n * \"payment_link\", …).\n * 2. Coarse action bucket from `classifyAction` (\"swap\", \"send\",\n * \"lending\") — prevents leaking opaque internal module names like\n * \"router\" (Cetus aggregator) or \"cross_swap\" (third-party DEX\n * aggregators) for txs that we already classified as a swap.\n * 3. Module name from the first MoveCall (`fallbackLabel`) — only\n * used when the action bucket itself is the generic \"transaction\".\n *\n * Pre-v0.46.2 we skipped tier 2, so swaps showed labels like \"router\",\n * \"cross_swap\", \"scallop_router\", etc. instead of the clean \"swap\".\n */\nexport function classifyLabel(targets: string[], commandTypes: string[]): string {\n for (const target of targets) {\n for (const [pattern, label] of LABEL_PATTERNS) {\n if (pattern.test(target)) return label;\n }\n }\n if (commandTypes.includes('TransferObjects') && !commandTypes.includes('MoveCall')) return 'send';\n const action = classifyAction(targets, commandTypes);\n if (action !== 'transaction') return action;\n return fallbackLabel(targets);\n}\n\n/**\n * Balance-direction tiebreaker for ambiguous lending calls.\n *\n * Many lending modules expose generic entry points (NAVI's bundled\n * flash actions, `lending_core::*::entry_*`, etc.) that don't carry\n * a `deposit`/`withdraw`/`borrow`/`repay` keyword in the function\n * name. When `classifyLabel` falls back to a bare module name like\n * `\"lending\"` for a known lending tx, infer direction from the user's\n * non-SUI balance change:\n * - net outflow of the supplied asset → deposit (also covers repay,\n * but repay-without-keyword is essentially never emitted).\n * - net inflow of the supplied asset → withdraw (also covers borrow).\n * SUI is excluded so gas-only transactions don't get mislabeled.\n *\n * If `LABEL_PATTERNS` matched a specific keyword, the existing label is\n * returned unchanged.\n */\nexport function refineLendingLabel(\n currentAction: string,\n currentLabel: string,\n moveCallTargets: string[],\n changes: ClassifyBalanceChange[],\n address: string,\n): string {\n if (currentAction !== 'lending') return currentLabel;\n const labelMatchedSpecific = LABEL_PATTERNS.some(([p]) =>\n moveCallTargets.some((t) => p.test(t)),\n );\n if (labelMatchedSpecific) return currentLabel;\n\n const userNonSuiOutflow = changes.find(\n (c) => resolveOwner(c.owner) === address && c.coinType !== SUI_TYPE && BigInt(c.amount) < 0n,\n );\n if (userNonSuiOutflow) return 'deposit';\n\n const userNonSuiInflow = changes.find(\n (c) => resolveOwner(c.owner) === address && c.coinType !== SUI_TYPE && BigInt(c.amount) > 0n,\n );\n if (userNonSuiInflow) return 'withdraw';\n\n return currentLabel;\n}\n\nexport interface ClassifyResult {\n action: string;\n label: string;\n}\n\nexport function classifyTransaction(\n moveCallTargets: string[],\n commandTypes: string[],\n balanceChanges: ClassifyBalanceChange[],\n address: string,\n): ClassifyResult {\n const action = classifyAction(moveCallTargets, commandTypes);\n const baseLabel = classifyLabel(moveCallTargets, commandTypes);\n const label = refineLendingLabel(action, baseLabel, moveCallTargets, balanceChanges, address);\n return { action, label };\n}\n\n/**\n * Direction of the user's net non-gas movement for this transaction.\n *\n * - `'out'` — the user spent the asset (sends, deposits, repays,\n * swap-in, payment-link payouts).\n * - `'in'` — the user received the asset (withdraws, borrows,\n * swap-out, claims, deposits credited from another wallet).\n *\n * Used by the `TransactionHistoryCard` to choose the `+`/`−` sign and\n * color. Direction is computed from the actual on-chain balance change\n * — never from the textual label — so opaque action types (`'router'`,\n * `'cross_swap'`, …) still render the correct sign.\n */\nexport type TxDirection = 'in' | 'out';\n\nexport interface ExtractedTransfer {\n amount?: number;\n asset?: string;\n recipient?: string;\n direction?: TxDirection;\n}\n\n/**\n * Extracts the principal amount/asset/direction for a transaction\n * from its `balanceChanges`.\n *\n * Algorithm:\n * 1. Restrict to the user's *own* balance changes.\n * 2. Prefer non-SUI changes (gas-only SUI deltas are noise).\n * 3. Pick the change with the largest absolute value — the \"principal\".\n * 4. If no non-SUI change exists, fall back to the largest SUI change\n * so pure-SUI transfers (stake/unstake/native send) still render.\n * 5. Direction follows the sign of the principal.\n * 6. Recipient is set only on outflows, by finding a matching inflow\n * on a *non-user* address with the same coinType.\n *\n * Pre-v0.46.2 this function only inspected outflows, so withdraws,\n * borrows, claims, swap-receives and payment-link receives all\n * rendered with no amount on the rich card (and with a wrong sign,\n * because the card guessed direction from the label string).\n */\nexport function extractTransferDetails(\n changes: ClassifyBalanceChange[] | undefined,\n sender: string,\n): ExtractedTransfer {\n if (!changes || changes.length === 0) return {};\n\n const userChanges = changes.filter((c) => resolveOwner(c.owner) === sender);\n if (userChanges.length === 0) return {};\n\n const userNonSui = userChanges.filter((c) => c.coinType !== SUI_TYPE);\n const pool = userNonSui.length > 0 ? userNonSui : userChanges;\n\n let primary = pool[0];\n let primaryAbs = bigintAbs(BigInt(primary.amount));\n for (let i = 1; i < pool.length; i++) {\n const abs = bigintAbs(BigInt(pool[i].amount));\n if (abs > primaryAbs) {\n primary = pool[i];\n primaryAbs = abs;\n }\n }\n\n const raw = BigInt(primary.amount);\n if (raw === 0n) return {};\n\n const decimals = getDecimalsForCoinType(primary.coinType);\n const amount = Number(primaryAbs) / 10 ** decimals;\n const asset = resolveSymbol(primary.coinType);\n const direction: TxDirection = raw < 0n ? 'out' : 'in';\n\n let recipient: string | undefined;\n if (direction === 'out') {\n const recipientChange = changes.find(\n (c) =>\n resolveOwner(c.owner) !== sender &&\n c.coinType === primary.coinType &&\n BigInt(c.amount) > 0n,\n );\n recipient = recipientChange ? resolveOwner(recipientChange.owner) ?? undefined : undefined;\n }\n\n return { amount, asset, recipient, direction };\n}\n\nfunction bigintAbs(n: bigint): bigint {\n return n < 0n ? -n : n;\n}\n\n/**\n * Extract every non-zero user balance leg for a transaction — not\n * just the largest one. Order is RPC order; callers responsible for\n * any sorting (e.g. audric sorts by USD value once it's priced).\n *\n * Sui collapses balance changes by coin type, so a 3-step bundle\n * touching USDC three times surfaces as ONE leg of net USDC delta.\n * Distinguishing per-step legs would require parsing the PTB's\n * commands; this helper deliberately stops at the balance-change\n * granularity because that's what's reliably available across all\n * Sui RPC versions.\n *\n * Pre-v1.27.2 the only public API was `extractTransferDetails`,\n * which returned a single \"primary\" leg and made swap rows\n * unrenderable (showed `Swapped 987.60 MANIFEST` because MANIFEST\n * was the largest raw delta even though USDC was the value side).\n */\nexport function extractAllUserLegs(\n changes: ClassifyBalanceChange[] | undefined,\n sender: string,\n): import('../types.js').TransactionLeg[] {\n if (!changes || changes.length === 0) return [];\n\n const legs: import('../types.js').TransactionLeg[] = [];\n for (const c of changes) {\n if (resolveOwner(c.owner) !== sender) continue;\n const raw = BigInt(c.amount);\n if (raw === 0n) continue;\n const decimals = getDecimalsForCoinType(c.coinType);\n const absAmount = bigintAbs(raw);\n legs.push({\n coinType: c.coinType,\n asset: resolveSymbol(c.coinType),\n decimals,\n amount: Number(absAmount) / 10 ** decimals,\n rawAmount: raw.toString(),\n direction: raw < 0n ? 'out' : 'in',\n });\n }\n\n return legs;\n}\n","import type { SuiJsonRpcClient } from '@mysten/sui/jsonRpc';\nimport type { TransactionRecord } from '../types.js';\nimport {\n classifyTransaction,\n extractAllUserLegs,\n extractTransferDetails,\n type ClassifyBalanceChange,\n} from './classify.js';\n\nexport async function queryHistory(\n client: SuiJsonRpcClient,\n address: string,\n limit = 20,\n): Promise<TransactionRecord[]> {\n const txns = await client.queryTransactionBlocks({\n filter: { FromAddress: address },\n options: { showEffects: true, showInput: true, showBalanceChanges: true },\n limit,\n order: 'descending',\n });\n\n return txns.data.map((tx) => parseTxRecord(tx as unknown as SuiRpcTxBlock, address));\n}\n\nexport async function queryTransaction(\n client: SuiJsonRpcClient,\n digest: string,\n senderAddress: string,\n): Promise<TransactionRecord | null> {\n try {\n const tx = await client.getTransactionBlock({\n digest,\n options: { showEffects: true, showInput: true, showBalanceChanges: true },\n });\n return parseTxRecord(tx as unknown as SuiRpcTxBlock, senderAddress);\n } catch {\n return null;\n }\n}\n\n/**\n * Shape of a transaction block as returned by `suix_queryTransactionBlocks`\n * with `showEffects | showInput | showBalanceChanges` enabled. Exported so\n * downstream consumers (audric dashboard `/api/history`, `/api/activity`,\n * etc.) can type their RPC calls without redeclaring the structure.\n */\nexport interface SuiRpcTxBlock {\n digest: string;\n timestampMs?: string;\n transaction?: unknown;\n effects?: { gasUsed?: { computationCost: string; storageCost: string; storageRebate: string } };\n balanceChanges?: ClassifyBalanceChange[];\n}\n\n/**\n * Convert a single Sui RPC transaction block to a {@link TransactionRecord}\n * using the canonical (shared) classifier and balance-change extractor.\n *\n * This is the single source of truth for transaction parsing across the\n * agent-tool path AND the dashboard-API path. Use it instead of writing\n * a bespoke parser per surface.\n *\n * @param tx Raw RPC tx block (must include `effects`, `input`, `balanceChanges`).\n * @param address Wallet address whose perspective we're parsing from.\n */\nexport function parseSuiRpcTx(tx: SuiRpcTxBlock, address: string): TransactionRecord {\n return parseTxRecord(tx, address);\n}\n\n/**\n * Extract the sender (signer) address from a raw RPC tx block.\n * Returns `null` if the block shape is unexpected.\n */\nexport function extractTxSender(txBlock: unknown): string | null {\n try {\n if (!txBlock || typeof txBlock !== 'object') return null;\n const data = 'data' in txBlock ? (txBlock as Record<string, unknown>).data : undefined;\n if (!data || typeof data !== 'object') return null;\n return ((data as Record<string, unknown>).sender as string) ?? null;\n } catch {\n return null;\n }\n}\n\n/**\n * Extract MoveCall targets (`<pkg>::<module>::<function>`) and the\n * sequence of programmable-transaction command types (e.g. `MoveCall`,\n * `TransferObjects`) from a raw RPC tx block. Tolerates both the\n * legacy `inner.transactions` field and the newer `inner.commands`\n * field.\n */\nexport function extractTxCommands(txBlock: unknown): {\n moveCallTargets: string[];\n commandTypes: string[];\n} {\n return extractCommands(txBlock);\n}\n\nfunction parseTxRecord(tx: SuiRpcTxBlock, address: string): TransactionRecord {\n const gasUsed = tx.effects?.gasUsed;\n const gasCost = gasUsed\n ? (Number(gasUsed.computationCost) +\n Number(gasUsed.storageCost) -\n Number(gasUsed.storageRebate)) /\n 1e9\n : undefined;\n\n const { moveCallTargets, commandTypes } = extractCommands(tx.transaction);\n const balanceChanges = tx.balanceChanges ?? [];\n const legs = extractAllUserLegs(balanceChanges, address);\n const { amount, asset, recipient, direction } = extractTransferDetails(balanceChanges, address);\n const { action, label } = classifyTransaction(\n moveCallTargets,\n commandTypes,\n balanceChanges,\n address,\n );\n\n return {\n digest: tx.digest,\n action,\n label,\n legs,\n amount,\n asset,\n recipient,\n direction,\n timestamp: Number(tx.timestampMs ?? 0),\n gasCost,\n };\n}\n\ninterface CommandInfo {\n moveCallTargets: string[];\n commandTypes: string[];\n}\n\nfunction extractCommands(txBlock: unknown): CommandInfo {\n const result: CommandInfo = { moveCallTargets: [], commandTypes: [] };\n try {\n if (!txBlock || typeof txBlock !== 'object') return result;\n const data = 'data' in txBlock ? (txBlock as Record<string, unknown>).data : undefined;\n if (!data || typeof data !== 'object') return result;\n const inner = 'transaction' in (data as Record<string, unknown>)\n ? (data as Record<string, unknown>).transaction\n : undefined;\n if (!inner || typeof inner !== 'object') return result;\n const commands = 'commands' in (inner as Record<string, unknown>)\n ? (inner as Record<string, unknown>).commands\n : 'transactions' in (inner as Record<string, unknown>)\n ? (inner as Record<string, unknown>).transactions\n : undefined;\n if (!Array.isArray(commands)) return result;\n\n for (const cmd of commands as Record<string, unknown>[]) {\n if (cmd.MoveCall) {\n const mc = cmd.MoveCall as { package: string; module: string; function: string };\n result.moveCallTargets.push(`${mc.package}::${mc.module}::${mc.function}`);\n result.commandTypes.push('MoveCall');\n } else if (cmd.TransferObjects) {\n result.commandTypes.push('TransferObjects');\n }\n }\n } catch { /* best effort */ }\n return result;\n}\n","import { MIST_PER_SUI, BPS_DENOMINATOR, USDC_DECIMALS, SUPPORTED_ASSETS } from '../constants.js';\nimport type { SupportedAsset } from '../constants.js';\n\nexport function mistToSui(mist: bigint): number {\n return Number(mist) / Number(MIST_PER_SUI);\n}\n\nexport function suiToMist(sui: number): bigint {\n return BigInt(Math.round(sui * Number(MIST_PER_SUI)));\n}\n\nexport function usdcToRaw(amount: number): bigint {\n return BigInt(Math.round(amount * 10 ** USDC_DECIMALS));\n}\n\nexport function rawToUsdc(raw: bigint): number {\n return Number(raw) / 10 ** USDC_DECIMALS;\n}\n\nexport function stableToRaw(amount: number, decimals: number): bigint {\n return BigInt(Math.round(amount * 10 ** decimals));\n}\n\nexport function rawToStable(raw: bigint, decimals: number): number {\n return Number(raw) / 10 ** decimals;\n}\n\nexport function getDecimals(asset: SupportedAsset): number {\n return SUPPORTED_ASSETS[asset].decimals;\n}\n\nexport function rawToDisplay(raw: bigint, decimals: number): number {\n return Number(raw) / 10 ** decimals;\n}\n\nexport function displayToRaw(amount: number, decimals: number): bigint {\n return BigInt(Math.round(amount * 10 ** decimals));\n}\n\nexport function bpsToPercent(bps: bigint): number {\n return Number(bps) / Number(BPS_DENOMINATOR) * 100;\n}\n\nexport function formatUsd(amount: number): string {\n return `$${amount.toFixed(2)}`;\n}\n\nexport function formatSui(amount: number): string {\n if (amount < 0.001) return `${amount.toFixed(6)} SUI`;\n return `${amount.toFixed(3)} SUI`;\n}\n\nexport function formatLargeNumber(n: number): string {\n if (n >= 1_000_000) return `${(n / 1_000_000).toFixed(1)}M`;\n if (n >= 1_000) return `${(n / 1_000).toFixed(1)}K`;\n return n.toFixed(2);\n}\n\nexport function formatAssetAmount(amount: number, asset: string): string {\n if (asset === 'BTC') return amount.toFixed(8);\n if (asset === 'GOLD') return amount.toFixed(6);\n if (asset === 'ETH') return amount.toFixed(6);\n return amount.toFixed(4);\n}\n\nconst ASSET_LOOKUP: Map<string, string> = new Map();\nfor (const [key, info] of Object.entries(SUPPORTED_ASSETS)) {\n ASSET_LOOKUP.set(key.toUpperCase(), key);\n if (info.displayName && info.displayName.toUpperCase() !== key.toUpperCase()) {\n ASSET_LOOKUP.set(info.displayName.toUpperCase(), key);\n }\n}\n\n/**\n * Case-insensitive lookup against SUPPORTED_ASSETS keys AND display names.\n * 'usde' → 'USDe', 'suiusde' → 'USDe', 'suiusdt' → 'USDT', 'usdsui' → 'USDsui'.\n * Returns the original input if not found so downstream validation can reject it.\n */\nexport function normalizeAsset(input: string): string {\n return ASSET_LOOKUP.get(input.toUpperCase()) ?? input;\n}\n","/** Cross-platform (Node + browser) base64 helpers. */\n\nexport function toBase64(bytes: Uint8Array): string {\n let binary = '';\n for (const byte of bytes) binary += String.fromCharCode(byte);\n return btoa(binary);\n}\n\nexport function fromBase64(b64: string): Uint8Array {\n const binary = atob(b64);\n const bytes = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);\n return bytes;\n}\n","/**\n * Protocol fee primitives — wallet-direct transfer model.\n *\n * Fees are collected by splitting from the payment coin and transferring directly\n * to the treasury wallet inside the same PTB. Atomic with the operation (PTB\n * semantics); the wallet IS the ledger; the server-side indexer reads\n * `balanceChanges` and writes a `ProtocolFeeLedger` row tagged with the operation\n * classified from the tx's moveCall targets.\n *\n * The SDK / CLI never call this helper — they're fee-free by design (t2000 = infra\n * brand, no opinion on fees). Audric's `prepare/route.ts` is the canonical caller.\n */\nimport { Transaction, type TransactionObjectArgument } from '@mysten/sui/transactions';\nimport {\n SAVE_FEE_BPS,\n BORROW_FEE_BPS,\n BPS_DENOMINATOR,\n USDC_DECIMALS,\n} from '../constants.js';\nimport { stableToRaw } from '../utils/format.js';\n\nexport type FeeOperation = 'save' | 'borrow' | 'swap';\n\nexport interface ProtocolFeeInfo {\n amount: number;\n asset: string;\n rate: number;\n rawAmount: bigint;\n}\n\nconst FEE_RATES: Record<FeeOperation, bigint> = {\n save: SAVE_FEE_BPS,\n borrow: BORROW_FEE_BPS,\n // Swap uses Cetus's overlay-fee mechanism (taken from output by the aggregator\n // and transferred to `overlayFee.receiver`). We list the rate here for display\n // / quote calculations only — `addFeeTransfer` is NOT called for swaps.\n swap: 10n, // 0.1%\n};\n\n/**\n * Compute the fee amount for a given operation against a USD-denominated input.\n * Used pre-tx for receipt display + quote math. Does not modify any tx.\n */\nexport function calculateFee(operation: FeeOperation, amount: number): ProtocolFeeInfo {\n const bps = FEE_RATES[operation];\n const feeAmount = amount * Number(bps) / Number(BPS_DENOMINATOR);\n const rawAmount = stableToRaw(feeAmount, USDC_DECIMALS);\n\n return {\n amount: feeAmount,\n asset: 'USDC',\n rate: Number(bps) / Number(BPS_DENOMINATOR),\n rawAmount,\n };\n}\n\n/**\n * Split a fee from `paymentCoin` and transfer it to `receiver` inside the given PTB.\n *\n * **Order is load-bearing.** Call this BEFORE the protocol operation that consumes\n * `paymentCoin` (e.g. NAVI deposit). `splitCoins` mutates the source coin in place,\n * leaving the remainder for the protocol step. If you split AFTER the deposit,\n * the deposit will have consumed the coin and the split will fail.\n *\n * Atomicity: `splitCoins` + `transferObjects` are PTB ops; if anything later in\n * the PTB reverts, the fee transfer reverts too.\n *\n * @param tx Active PTB\n * @param paymentCoin Coin to split the fee from (mutated in place)\n * @param feeBps Fee rate in basis points (e.g. `SAVE_FEE_BPS = 10n` = 0.1%)\n * @param receiver Treasury wallet address (typically `T2000_OVERLAY_FEE_WALLET`)\n * @param amount Display-units input amount (matches what was passed to the\n * protocol operation; used to compute the raw fee amount)\n * @param decimals Coin decimals for raw conversion. Defaults to USDC_DECIMALS\n * (6). Pass the actual coin decimals when skimming a fee\n * from a non-USDC coin (e.g. USDsui = 6, GOLD = 6, ETH = 8,\n * SUI = 9). Backward-compatible: existing USDC callers can\n * omit. Wrong decimals → wrong raw amount → either fee\n * too small (silent loss) or too large (PTB revert from\n * insufficient coin balance).\n */\nexport function addFeeTransfer(\n tx: Transaction,\n paymentCoin: TransactionObjectArgument,\n feeBps: bigint,\n receiver: string,\n amount: number,\n decimals: number = USDC_DECIMALS,\n): void {\n if (feeBps <= 0n) return;\n if (amount <= 0) return;\n\n const feeAmount = amount * Number(feeBps) / Number(BPS_DENOMINATOR);\n const rawFee = stableToRaw(feeAmount, decimals);\n if (rawFee <= 0n) return;\n\n const [feeCoin] = tx.splitCoins(paymentCoin, [tx.pure.u64(rawFee)]);\n tx.transferObjects([feeCoin], tx.pure.address(receiver));\n}\n","/**\n * Cetus Aggregator V3 SDK wrapper — the ONLY file that imports @cetusprotocol/aggregator-sdk.\n * Documented CLAUDE.md exception: multi-DEX routing cannot be feasibly replaced by thin tx builders.\n *\n * [B5 v2 / @t2000/sdk@1.1.0 / 2026-04-30]\n * Overlay fee config is now per-call instead of a module-level singleton. CLI / direct\n * SDK callers (`T2000.swap()`) DON'T pass `overlayFee` → fee-free swap. Audric's\n * prepare/route.ts ALWAYS passes `overlayFee = { rate: OVERLAY_FEE_RATE, receiver:\n * T2000_OVERLAY_FEE_WALLET }` → fee charged. Structural inclusion (Audric's code can't\n * forget to pass it because it IS the code), not a toggle that defaults to safe.\n *\n * Pre-1.1.0: a module-level `OVERLAY_FEE_RECEIVER` constant defaulted to a Move object\n * ID. USDC sent there became OwnedObjects keyed to the object and was inaccessible.\n * Fixed by making the receiver a regular wallet address (T2000_OVERLAY_FEE_WALLET) AND\n * by removing the singleton pattern that hid the misconfig.\n */\nimport { AggregatorClient, Env, type FindRouterParams, type RouterDataV3 } from '@cetusprotocol/aggregator-sdk';\nimport { Transaction, type TransactionObjectArgument } from '@mysten/sui/transactions';\nimport type { SuiJsonRpcClient } from '@mysten/sui/jsonRpc';\nimport BN from 'bn.js';\nimport { resolveTokenType, getDecimalsForCoinType } from '../token-registry.js';\n\nexport interface OverlayFeeConfig {\n /** Fee rate as a fraction (e.g. 0.001 = 0.1%). Pass 0 to disable. */\n rate: number;\n /** Wallet address that receives the overlay fee. */\n receiver: string;\n}\n\nexport interface SwapRouteResult {\n routerData: RouterDataV3;\n amountIn: string;\n amountOut: string;\n byAmountIn: boolean;\n priceImpact: number;\n insufficientLiquidity: boolean;\n}\n\n// [SPEC 20.2 / D-1 (a)] Typed JSON-friendly representation of a Cetus\n// `RouterDataV3` for cross-process / cross-network transport. The native\n// shape contains `BN` instances (`bn.js`) and a `Map<string, string>`\n// (`packages`) that don't survive JSON.stringify / JSON.parse cleanly:\n// - `BN.toJSON()` returns the internal `{negative,words,length,red}` blob\n// - `Map.toJSON()` returns `{}`\n// Round-tripping via `serializeCetusRoute` + `deserializeCetusRoute`\n// converts BN ↔ decimal string and Map ↔ Record. Engine + audric both\n// reference fields by path (`route.routerData.paths[i].provider`) without\n// needing to know about the underlying BN/Map types.\nexport interface SerializedCetusRoutePath {\n id: string;\n direction: boolean;\n provider: string;\n from: string;\n target: string;\n feeRate: number;\n amountIn: string;\n amountOut: string;\n version?: string;\n publishedAt?: string;\n extendedDetails?: Record<string, unknown>;\n}\n\nexport interface SerializedRouterDataV3 {\n quoteID?: string;\n /** RouterDataV3.amountIn (BN) → decimal string */\n amountIn: string;\n /** RouterDataV3.amountOut (BN) → decimal string */\n amountOut: string;\n byAmountIn: boolean;\n paths: SerializedCetusRoutePath[];\n insufficientLiquidity: boolean;\n deviationRatio: number;\n /** RouterDataV3.packages (Map) → Record */\n packages?: Record<string, string>;\n totalDeepFee?: number;\n error?: { code: number; msg: string };\n overlayFee?: number;\n}\n\nexport interface SerializedCetusRoute {\n routerData: SerializedRouterDataV3;\n amountIn: string;\n amountOut: string;\n byAmountIn: boolean;\n priceImpact: number;\n insufficientLiquidity: boolean;\n /**\n * Wall-clock timestamp (ms since epoch) at which the route was discovered.\n * Used by audric's prepare-route for SPEC 20.2 D-3 TTL re-validation: if\n * the route is older than the threshold AND price impact has shifted\n * beyond tolerance, fall back to a fresh `findSwapRoute()` call.\n */\n discoveredAt: number;\n /**\n * Snapshot of the input/output coin types the route was discovered for.\n * SPEC 20.2 D-2 (b) structural verification: prepare-route asserts\n * input/output coins match before using the fast-path; mismatch falls\n * back to fresh discovery (defense against client-side tampering and\n * against legitimate token-type drift in the request).\n */\n fromCoinType: string;\n toCoinType: string;\n}\n\nexport function serializeCetusRoute(\n route: SwapRouteResult,\n context: { fromCoinType: string; toCoinType: string },\n): SerializedCetusRoute {\n return {\n routerData: serializeRouterDataV3(route.routerData),\n amountIn: route.amountIn,\n amountOut: route.amountOut,\n byAmountIn: route.byAmountIn,\n priceImpact: route.priceImpact,\n insufficientLiquidity: route.insufficientLiquidity,\n discoveredAt: Date.now(),\n fromCoinType: context.fromCoinType,\n toCoinType: context.toCoinType,\n };\n}\n\nexport function deserializeCetusRoute(serialized: SerializedCetusRoute): SwapRouteResult {\n return {\n routerData: deserializeRouterDataV3(serialized.routerData),\n amountIn: serialized.amountIn,\n amountOut: serialized.amountOut,\n byAmountIn: serialized.byAmountIn,\n priceImpact: serialized.priceImpact,\n insufficientLiquidity: serialized.insufficientLiquidity,\n };\n}\n\nfunction serializeRouterDataV3(rd: RouterDataV3): SerializedRouterDataV3 {\n const out: SerializedRouterDataV3 = {\n amountIn: rd.amountIn.toString(),\n amountOut: rd.amountOut.toString(),\n byAmountIn: rd.byAmountIn,\n paths: rd.paths.map(serializeCetusRoutePath),\n insufficientLiquidity: rd.insufficientLiquidity,\n deviationRatio: rd.deviationRatio,\n };\n if (rd.quoteID !== undefined) out.quoteID = rd.quoteID;\n if (rd.packages) {\n const obj: Record<string, string> = {};\n for (const [k, v] of rd.packages) obj[k] = v;\n out.packages = obj;\n }\n if (rd.totalDeepFee !== undefined) out.totalDeepFee = rd.totalDeepFee;\n if (rd.error) out.error = { code: rd.error.code, msg: rd.error.msg };\n if (rd.overlayFee !== undefined) out.overlayFee = rd.overlayFee;\n return out;\n}\n\nfunction deserializeRouterDataV3(s: SerializedRouterDataV3): RouterDataV3 {\n const out: RouterDataV3 = {\n amountIn: new BN(s.amountIn),\n amountOut: new BN(s.amountOut),\n byAmountIn: s.byAmountIn,\n paths: s.paths.map(deserializeCetusRoutePath),\n insufficientLiquidity: s.insufficientLiquidity,\n deviationRatio: s.deviationRatio,\n };\n if (s.quoteID !== undefined) out.quoteID = s.quoteID;\n if (s.packages) out.packages = new Map(Object.entries(s.packages));\n if (s.totalDeepFee !== undefined) out.totalDeepFee = s.totalDeepFee;\n if (s.error) out.error = { code: s.error.code, msg: s.error.msg };\n if (s.overlayFee !== undefined) out.overlayFee = s.overlayFee;\n return out;\n}\n\nfunction serializeCetusRoutePath(p: RouterDataV3['paths'][number]): SerializedCetusRoutePath {\n const out: SerializedCetusRoutePath = {\n id: p.id,\n direction: p.direction,\n provider: p.provider,\n from: p.from,\n target: p.target,\n feeRate: p.feeRate,\n amountIn: p.amountIn,\n amountOut: p.amountOut,\n };\n if (p.version !== undefined) out.version = p.version;\n if (p.publishedAt !== undefined) out.publishedAt = p.publishedAt;\n if (p.extendedDetails) out.extendedDetails = { ...p.extendedDetails };\n return out;\n}\n\nfunction deserializeCetusRoutePath(p: SerializedCetusRoutePath): RouterDataV3['paths'][number] {\n const out: RouterDataV3['paths'][number] = {\n id: p.id,\n direction: p.direction,\n provider: p.provider,\n from: p.from,\n target: p.target,\n feeRate: p.feeRate,\n amountIn: p.amountIn,\n amountOut: p.amountOut,\n };\n if (p.version !== undefined) out.version = p.version;\n if (p.publishedAt !== undefined) out.publishedAt = p.publishedAt;\n if (p.extendedDetails) out.extendedDetails = { ...p.extendedDetails };\n return out;\n}\n\n/**\n * SPEC 20.2 D-2 (b) structural verification helper. Returns true when the\n * serialized route matches the requested coin types (i.e. it's safe to use\n * as the prepare-route fast-path), false otherwise (tampered, or input\n * mismatch from a legitimate but stale pending action). Caller falls back\n * to a fresh `findSwapRoute()` call when verification fails.\n */\nexport function verifyCetusRouteCoinMatch(\n serialized: SerializedCetusRoute,\n expected: { fromCoinType: string; toCoinType: string },\n): boolean {\n return serialized.fromCoinType === expected.fromCoinType && serialized.toCoinType === expected.toCoinType;\n}\n\n/**\n * SPEC 20.2 D-3 (b) TTL helper. Returns true when the serialized route is\n * fresh enough to use as the fast-path (< `maxAgeMs` old). Returns false\n * for stale routes — caller falls back to fresh `findSwapRoute()` to pick\n * up any pool-price drift since route discovery.\n *\n * Default 30s aligns with the existing quote-freshness contract surfaced\n * to users via `pending_action.quoteAge` (the PermissionCard \"QUOTE Ns OLD\"\n * badge starts warning the user past 30s).\n */\nexport function isCetusRouteFresh(serialized: SerializedCetusRoute, maxAgeMs: number = 30_000): boolean {\n return Date.now() - serialized.discoveredAt < maxAgeMs;\n}\n\n/**\n * Default Audric swap overlay fee — 0.1%. Exported for consumers that want to use\n * the canonical Audric rate (the Audric prepare-route does this). Changing this\n * rate requires a coordinated SDK + audric release.\n */\nexport const OVERLAY_FEE_RATE = 0.001;\n\n/**\n * Cache `AggregatorClient` instances by `(signer + overlay rate + overlay receiver)`.\n * Per-call instantiation is cheap (the client is mostly config), but caching avoids\n * pointless re-allocation when the same caller swaps multiple times in a loop.\n */\nconst clientCache = new Map<string, AggregatorClient>();\n\nfunction getClient(walletAddress: string, overlayFee?: OverlayFeeConfig): AggregatorClient {\n const rate = overlayFee?.rate ?? 0;\n const receiver = overlayFee?.receiver ?? '';\n const key = `${walletAddress}|${rate}|${receiver}`;\n\n const cached = clientCache.get(key);\n if (cached) return cached;\n\n const client = new AggregatorClient({\n signer: walletAddress,\n env: Env.Mainnet,\n ...(rate > 0 && receiver\n ? { overlayFeeRate: rate, overlayFeeReceiver: receiver }\n : {}),\n });\n clientCache.set(key, client);\n return client;\n}\n\n/**\n * [Bug A defense-in-depth / 2026-05-10] Returns true when every path\n * provider in `route.routerData.paths` is present in the active\n * `providers` allow-list. Cetus's `getProvidersExcluding(...)` returns\n * an inclusion list (the complement of the exclusion), so when a caller\n * passes `providers`, every walked provider must be IN that list to be\n * compatible.\n *\n * When `providers` is undefined (non-sponsored caller, e.g. CLI) every\n * route is compatible — same semantics as `findSwapRoute` itself.\n *\n * Why per-path: a Cetus aggregator route can split across multiple DEXes\n * (e.g. 60% Cetus + 40% Bluefin). A single excluded provider in any path\n * triggers `tx.gas` usage in `routerSwap`. Reject the whole route if any\n * leg is excluded.\n */\nexport function isPrecomputedRouteCompatibleWithProviders(\n route: SwapRouteResult,\n providers: string[] | undefined,\n): boolean {\n if (!providers || providers.length === 0) return true;\n const allowed = new Set(providers);\n for (const path of route.routerData.paths) {\n if (!allowed.has(path.provider)) return false;\n }\n return true;\n}\n\n/**\n * Find the optimal swap route via Cetus Aggregator REST API.\n *\n * Pass `overlayFee` to charge an overlay fee on the output (Audric's pattern).\n * Omit it for a fee-free swap (CLI / direct SDK pattern).\n */\nexport async function findSwapRoute(params: {\n walletAddress: string;\n from: string;\n to: string;\n amount: bigint;\n byAmountIn: boolean;\n overlayFee?: OverlayFeeConfig;\n /**\n * Optional Cetus provider allow-list. When omitted, all 30+ DEXes\n * are eligible. Sponsored flows (Enoki) MUST pass an exclusion list\n * computed via `getProvidersExcluding([...])` from the Cetus SDK to\n * remove Pyth-dependent providers (HAEDALPMM, METASTABLE, OBRIC,\n * STEAMM_OMM, STEAMM_OMM_V2, SEVENK, HAEDALHMMV2) — those reference\n * `tx.gas` for oracle fees, which Enoki rejects in sponsored txs.\n * Non-sponsored callers (CLI, direct SDK) leave this undefined.\n */\n providers?: string[];\n}): Promise<SwapRouteResult | null> {\n const client = getClient(params.walletAddress, params.overlayFee);\n\n const findParams: FindRouterParams = {\n from: params.from,\n target: params.to,\n amount: params.amount.toString(),\n byAmountIn: params.byAmountIn,\n ...(params.providers ? { providers: params.providers } : {}),\n };\n\n const routerData = await client.findRouters(findParams);\n if (!routerData) return null;\n\n if (routerData.insufficientLiquidity) {\n return {\n routerData,\n amountIn: routerData.amountIn.toString(),\n amountOut: routerData.amountOut.toString(),\n byAmountIn: params.byAmountIn,\n priceImpact: normalizePriceImpact(routerData.deviationRatio),\n insufficientLiquidity: true,\n };\n }\n\n if (routerData.error) {\n const { T2000Error } = await import('../errors.js');\n throw new T2000Error('SWAP_FAILED', `Cetus routing error: ${routerData.error.msg} (code ${routerData.error.code})`);\n }\n\n return {\n routerData,\n amountIn: routerData.amountIn.toString(),\n amountOut: routerData.amountOut.toString(),\n byAmountIn: params.byAmountIn,\n priceImpact: normalizePriceImpact(routerData.deviationRatio),\n insufficientLiquidity: false,\n };\n}\n\n/**\n * Cetus' aggregator types `deviationRatio` as `number`, but in some routes\n * the router actually returns a string (\"0.001234\"). The SDK type lies, so we\n * always coerce to a finite number here (NaN/null/undefined → 0). Without\n * this every downstream consumer that calls `priceImpact.toFixed(...)` will\n * crash at runtime — including the Audric SwapQuoteCard, which takes the\n * whole chat UI down through its error boundary.\n */\nfunction normalizePriceImpact(value: unknown): number {\n const n = typeof value === 'number' ? value : Number(value);\n return Number.isFinite(n) ? n : 0;\n}\n\n/**\n * Build a swap PTB from a route result. The caller must provide an input coin\n * obtained by splitting/merging wallet coins.\n *\n * **Important:** Cetus's `routerSwap` reads the overlay-fee config from the\n * AggregatorClient instance. The `overlayFee` param here MUST match the one\n * passed to `findSwapRoute` for the same swap (otherwise you'll hit the cache\n * boundary and get a different client with different overlay config).\n */\nexport async function buildSwapTx(params: {\n walletAddress: string;\n route: SwapRouteResult;\n tx: Transaction;\n inputCoin: TransactionObjectArgument;\n slippage: number;\n overlayFee?: OverlayFeeConfig;\n}): Promise<TransactionObjectArgument> {\n const client = getClient(params.walletAddress, params.overlayFee);\n const clampedSlippage = Math.max(0.001, Math.min(params.slippage, 0.05));\n\n const outputCoin = await client.routerSwap({\n router: params.route.routerData,\n inputCoin: params.inputCoin,\n slippage: clampedSlippage,\n txb: params.tx,\n });\n\n return outputCoin;\n}\n\n/**\n * Append a swap fragment to an existing PTB. SPEC 7 § \"Layer 1\" Cetus\n * appender. Two modes, dispatched by the presence of `input.inputCoin`:\n *\n * - **Wallet mode** (`inputCoin` omitted) — sources `from`-asset funds\n * via `coinWithBalance({ type, balance })` (resolves coin objects +\n * address balance at build time), runs the swap. Mirrors the audric\n * host's `transactions/prepare/route.ts` swap branch (P2.2c will\n * retire that branch in favor of this appender via `composeTx`).\n *\n * - **Chain mode** (`inputCoin` provided) — consumes the passed-in coin\n * reference (typically produced by an upstream appender like\n * `addWithdrawToTx`) directly, no wallet fetch / no merge / no\n * split. This is the SPEC 7 multi-write enabler (\"withdraw → swap →\n * save\" without intermediate wallet materialization).\n *\n * **SUI in wallet mode:** ALWAYS sources through `selectSuiCoin` (which\n * routes via `coinWithBalance({ type: SUI, useGasCoin: false })` under\n * sponsored flows, OR `tx.splitCoins(tx.gas, ...)` under self-funded\n * flows). The caller MUST set `sponsoredContext` correctly — otherwise\n * sponsored swaps with SUI source fail with `Cannot use GasCoin as a\n * transaction argument` (Enoki owns `tx.gas`, the PTB body referencing\n * it as an argument is invalid for sponsorship). 2.14.0 shipped without\n * this branch and broke audric/web-v2 SUI→USDC swaps; restored in 2.14.1\n * (S.260). For non-sponsored flows (CLI), `T2000.swap()` pre-builds the\n * inputCoin via `tx.splitCoins(tx.gas, [rawAmount])[0]` and uses chain\n * mode, sidestepping wallet-mode entirely — this branch is a defensive\n * safety net for future direct SDK users who pass SUI in wallet mode.\n *\n * **`swapAll` semantics (wallet mode):** if the requested raw amount\n * is >= the wallet's total `from` balance, the appender consumes the\n * entire merged primary coin (not a split), matching audric's host\n * route's `swapAll` clipping. The returned `effectiveAmountIn` reflects\n * the actual consumed amount in display units.\n *\n * **Slippage:** clamped to [0.001, 0.05] (0.1% – 5%). Defaults to 0.01.\n *\n * @returns\n * - `coin` — output coin reference, ready for downstream consumption\n * (e.g. `addSaveToTx`) or wallet transfer (`tx.transferObjects`).\n * - `effectiveAmountIn` — display-units input amount the swap actually\n * consumes (handles `swapAll` clipping in wallet mode; in chain mode\n * echoes the requested `input.amount`).\n * - `expectedAmountOut` — display-units output amount per the route\n * quote. Actual on-chain output may differ within slippage.\n * - `route` — raw `SwapRouteResult` for downstream telemetry / logging.\n */\nexport async function addSwapToTx(\n tx: Transaction,\n client: SuiJsonRpcClient,\n address: string,\n input: {\n from: string;\n to: string;\n amount: number;\n slippage?: number;\n byAmountIn?: boolean;\n overlayFee?: OverlayFeeConfig;\n inputCoin?: TransactionObjectArgument;\n /**\n * Optional Cetus provider allow-list. Forwarded to `findSwapRoute`.\n * Sponsored flows (Enoki) MUST pass `getProvidersExcluding([...])`\n * to remove Pyth-dependent providers — see `findSwapRoute`'s JSDoc\n * for the exclusion list. Non-sponsored callers omit this.\n */\n providers?: string[];\n /**\n * [SPEC 20.2 D-3 (b)] Precomputed route from a prior `findSwapRoute()`\n * call (typically captured by `swap_quote` and threaded through\n * `pending_action.cetusRoute`). When present AND not stale (per\n * `isCetusRouteFresh`) AND the input/output coins match, this skips\n * the ~400-500ms `findSwapRoute()` discovery call. Stale routes are\n * silently ignored (caller falls back to fresh discovery).\n *\n * Caller responsibility: pass the SAME `overlayFee` / `providers` /\n * `byAmountIn` that produced the precomputed route. Mismatch will\n * still produce a working swap but may use the wrong overlay-fee\n * config (the route data already encodes the chosen DEX path).\n */\n precomputedRoute?: SwapRouteResult;\n /**\n * Whether this swap is being built inside a sponsored-tx flow (Enoki)\n * vs self-funded (CLI / direct sign). Load-bearing for SUI-source\n * swaps in wallet mode: under sponsored flows, `tx.gas` belongs to\n * the sponsor and CANNOT be referenced as a transaction argument\n * (Sui protocol rejects with `Cannot use GasCoin as a transaction\n * argument`). When `true`, SUI source routes through `selectSuiCoin`\n * with `useGasCoin: false` so the resolver sources from the user's\n * SUI coin objects + address balance instead. Defaults to `false`\n * (back-compat — pre-2.14.1 behavior). Audric/web-v2's compose path\n * threads this through via `composeTx({ sponsoredContext: true })`.\n */\n sponsoredContext?: boolean;\n },\n): Promise<{\n coin: TransactionObjectArgument;\n effectiveAmountIn: number;\n expectedAmountOut: number;\n route: SwapRouteResult;\n /** True when `precomputedRoute` was used (no `findSwapRoute()` call). */\n usedPrecomputedRoute: boolean;\n}> {\n const { T2000Error } = await import('../errors.js');\n\n const fromType = resolveTokenType(input.from);\n const toType = resolveTokenType(input.to);\n if (!fromType) throw new T2000Error('ASSET_NOT_SUPPORTED', `Unknown token: ${input.from}. Provide the symbol (USDC, SUI, ...) or full coin type.`);\n if (!toType) throw new T2000Error('ASSET_NOT_SUPPORTED', `Unknown token: ${input.to}. Provide the symbol (USDC, SUI, ...) or full coin type.`);\n if (fromType === toType) throw new T2000Error('SWAP_FAILED', 'Cannot swap a token to itself');\n if (!Number.isFinite(input.amount) || input.amount <= 0) {\n throw new T2000Error('INVALID_AMOUNT', 'Amount must be greater than zero');\n }\n\n const fromDecimals = getDecimalsForCoinType(fromType);\n const toDecimals = getDecimalsForCoinType(toType);\n const requestedRaw = BigInt(Math.floor(input.amount * 10 ** fromDecimals));\n\n const slippage = Math.max(0.001, Math.min(input.slippage ?? 0.01, 0.05));\n const byAmountIn = input.byAmountIn ?? true;\n\n let inputCoin: TransactionObjectArgument;\n let effectiveRaw: bigint;\n\n if (input.inputCoin) {\n inputCoin = input.inputCoin;\n effectiveRaw = requestedRaw;\n } else if (fromType === '0x2::sui::SUI') {\n // SUI source needs special handling: under sponsored flows (Enoki),\n // referencing `tx.gas` as a transaction argument is forbidden (sponsor\n // owns the gas coin). `selectSuiCoin` does the right thing for both\n // sponsored (uses `coinWithBalance({ useGasCoin: false })`) and\n // self-funded (splits from `tx.gas` directly). The 2.14.0 release\n // shipped without this branch and broke audric/web-v2 SUI→USDC swaps\n // (\"Cannot use GasCoin as a transaction argument\" from Enoki); fixed\n // in 2.14.1 (S.260).\n const { selectSuiCoin } = await import('../wallet/coinSelection.js');\n const result = await selectSuiCoin(\n tx,\n client,\n address,\n requestedRaw,\n input.sponsoredContext ?? false,\n );\n inputCoin = result.coin;\n effectiveRaw = result.effectiveAmount;\n } else {\n // Non-SUI wallet-mode source — delegate to the canonical prelude.\n // Pre-flights against `getBalance().totalBalance` (coins + address\n // balance) and returns a `coinWithBalance({ type, balance })` arg.\n // Multi-write bundles that consume the same input asset across legs\n // (swap+save, swap+send) get correct merge/split dedup automatically\n // because the `@mysten/sui` resolver batches all `coinWithBalance`\n // intents for a given coin type into a single merge at `tx.build()`\n // time. Replaces the per-PTB merge cache that was load-bearing\n // pre-2026-05-22 (when `selectAndSplitCoin` emitted explicit\n // `mergeCoins` itself).\n const { selectAndSplitCoin } = await import('../wallet/coinSelection.js');\n const result = await selectAndSplitCoin(tx, client, address, fromType, requestedRaw);\n inputCoin = result.coin;\n effectiveRaw = result.effectiveAmount;\n }\n\n // [SPEC 20.2 D-3 (b)] Use the precomputed route when available + valid.\n // Validity = same input/output coin types AND the requested raw amount\n // matches what the route was discovered for (mismatch indicates the user\n // edited the amount post-quote, in which case we must re-discover at the\n // new amount because price impact is amount-dependent). The caller\n // (`audric prepare-route`) owns the staleness check (`isCetusRouteFresh`)\n // and only forwards `precomputedRoute` when fresh.\n //\n // [Bug A defense-in-depth / 2026-05-10] Even with the engine fix that\n // makes `swap_quote` discover sponsor-safe routes, this layer also\n // validates the precomputed route against the active providers\n // allow-list. If the route walks any excluded provider (e.g. a stale\n // `pending_action.cetusRoute` from before the engine fix shipped, or a\n // provider list that drifted between quote and execute), fall back to\n // fresh discovery. Better to eat 400ms than to let a Pyth-dependent\n // route reach Enoki and revert with HTTP 400.\n let route: SwapRouteResult | null;\n let usedPrecomputedRoute = false;\n if (\n input.precomputedRoute &&\n input.precomputedRoute.amountIn === effectiveRaw.toString() &&\n input.precomputedRoute.byAmountIn === byAmountIn &&\n isPrecomputedRouteCompatibleWithProviders(input.precomputedRoute, input.providers)\n ) {\n route = input.precomputedRoute;\n usedPrecomputedRoute = true;\n } else {\n route = await findSwapRoute({\n walletAddress: address,\n from: fromType,\n to: toType,\n amount: effectiveRaw,\n byAmountIn,\n overlayFee: input.overlayFee,\n providers: input.providers,\n });\n }\n\n if (!route) {\n throw new T2000Error('SWAP_NO_ROUTE', `No swap route found for ${input.from} → ${input.to}`);\n }\n if (route.insufficientLiquidity) {\n throw new T2000Error('SWAP_NO_ROUTE', `Insufficient liquidity for ${input.from} → ${input.to}`);\n }\n\n const outputCoin = await buildSwapTx({\n walletAddress: address,\n route,\n tx,\n inputCoin,\n slippage,\n overlayFee: input.overlayFee,\n });\n\n return {\n coin: outputCoin,\n effectiveAmountIn: Number(effectiveRaw) / 10 ** fromDecimals,\n expectedAmountOut: Number(route.amountOut) / 10 ** toDecimals,\n route,\n usedPrecomputedRoute,\n };\n}\n\n/**\n * Simulate a swap transaction without executing it.\n */\nexport async function simulateSwap(params: {\n walletAddress: string;\n tx: Transaction;\n overlayFee?: OverlayFeeConfig;\n}): Promise<{ success: boolean; error?: string }> {\n const client = getClient(params.walletAddress, params.overlayFee);\n try {\n await client.devInspectTransactionBlock(params.tx);\n return { success: true };\n } catch (err) {\n return { success: false, error: err instanceof Error ? err.message : String(err) };\n }\n}\n\n// Re-export from the canonical token registry for backward-compat.\nexport { TOKEN_MAP, resolveTokenType } from '../token-registry.js';\n","import { T2000Error } from '../errors.js';\n\nexport type SafeguardRule = 'locked' | 'maxPerTx' | 'maxDailySend';\n\nexport interface SafeguardErrorDetails {\n attempted?: number;\n limit?: number;\n current?: number;\n}\n\nexport class SafeguardError extends T2000Error {\n readonly rule: SafeguardRule;\n readonly details: SafeguardErrorDetails;\n\n constructor(rule: SafeguardRule, details: SafeguardErrorDetails, message?: string) {\n const msg = message ?? buildMessage(rule, details);\n super('SAFEGUARD_BLOCKED' as any, msg, { rule, ...details });\n this.name = 'SafeguardError';\n this.rule = rule;\n this.details = details;\n }\n\n override toJSON() {\n return {\n error: 'SAFEGUARD_BLOCKED' as const,\n message: this.message,\n retryable: this.retryable,\n data: { rule: this.rule, ...this.details },\n };\n }\n}\n\nfunction buildMessage(rule: SafeguardRule, details: SafeguardErrorDetails): string {\n switch (rule) {\n case 'locked':\n return 'Agent is locked. All operations are frozen.';\n case 'maxPerTx':\n return `Amount $${(details.attempted ?? 0).toFixed(2)} exceeds per-transaction limit ($${(details.limit ?? 0).toFixed(2)})`;\n case 'maxDailySend':\n return `Daily send limit reached ($${(details.current ?? 0).toFixed(2)}/$${(details.limit ?? 0).toFixed(2)} used today)`;\n }\n}\n","export interface SafeguardConfig {\n locked: boolean;\n maxPerTx: number;\n maxDailySend: number;\n dailyUsed: number;\n dailyResetDate: string;\n maxLeverage?: number;\n maxPositionSize?: number;\n}\n\nexport interface TxMetadata {\n operation:\n | 'send'\n | 'save'\n | 'withdraw'\n | 'borrow'\n | 'repay'\n | 'pay';\n amount?: number;\n}\n\nexport const OUTBOUND_OPS = new Set<TxMetadata['operation']>([\n 'send',\n 'pay',\n]);\n\nexport const DEFAULT_SAFEGUARD_CONFIG: SafeguardConfig = {\n locked: false,\n maxPerTx: 0,\n maxDailySend: 0,\n dailyUsed: 0,\n dailyResetDate: '',\n};\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/errors.ts","../src/token-registry.ts","../src/wallet/keypairSigner.ts","../src/wallet/zkLoginSigner.ts","../src/browser.ts","../src/constants.ts","../src/utils/sui.ts","../src/wallet/classify.ts","../src/wallet/history.ts","../src/utils/format.ts","../src/utils/base64.ts","../src/protocols/protocolFee.ts","../src/protocols/cetus-swap.ts","../src/safeguards/errors.ts","../src/safeguards/types.ts"],"names":["T2000Error"],"mappings":"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","file":"browser.js","sourcesContent":["export type T2000ErrorCode =\n | 'INSUFFICIENT_BALANCE'\n | 'ADDRESS_BALANCE_UNSPONSORABLE'\n | 'INSUFFICIENT_GAS'\n | 'INVALID_ADDRESS'\n | 'INVALID_AMOUNT'\n | 'WALLET_NOT_FOUND'\n | 'WALLET_LOCKED'\n | 'WALLET_EXISTS'\n | 'WALLET_CORRUPT'\n | 'INVALID_KEY'\n | 'SIMULATION_FAILED'\n | 'TRANSACTION_FAILED'\n | 'ASSET_NOT_SUPPORTED'\n | 'INVALID_ASSET'\n | 'HEALTH_FACTOR_TOO_LOW'\n | 'WITHDRAW_WOULD_LIQUIDATE'\n | 'WITHDRAW_FAILED'\n | 'NO_COLLATERAL'\n | 'PROTOCOL_PAUSED'\n | 'PROTOCOL_UNAVAILABLE'\n | 'RPC_ERROR'\n | 'RPC_UNREACHABLE'\n | 'PRICE_EXCEEDS_LIMIT'\n | 'UNSUPPORTED_NETWORK'\n | 'PAYMENT_EXPIRED'\n | 'DUPLICATE_PAYMENT'\n | 'FACILITATOR_REJECTION'\n | 'CONTACT_NOT_FOUND'\n | 'INVALID_CONTACT_NAME'\n | 'SUINS_NOT_REGISTERED'\n | 'FACILITATOR_TIMEOUT'\n | 'SAFEGUARD_BLOCKED'\n | 'SWAP_NO_ROUTE'\n | 'SWAP_FAILED'\n | 'CHAIN_MODE_INVALID'\n | 'UNKNOWN';\n\nexport interface T2000ErrorData {\n reason?: string;\n [key: string]: unknown;\n}\n\nexport class T2000Error extends Error {\n readonly code: T2000ErrorCode;\n readonly data?: T2000ErrorData;\n readonly retryable: boolean;\n\n constructor(code: T2000ErrorCode, message: string, data?: T2000ErrorData, retryable = false) {\n super(message);\n this.name = 'T2000Error';\n this.code = code;\n this.data = data;\n this.retryable = retryable;\n }\n\n toJSON() {\n return {\n error: this.code,\n message: this.message,\n ...(this.data && { data: this.data }),\n retryable: this.retryable,\n };\n }\n}\n\nexport function mapWalletError(error: unknown): T2000Error {\n const msg = error instanceof Error ? error.message : String(error);\n\n if (msg.includes('rejected') || msg.includes('cancelled')) {\n return new T2000Error('TRANSACTION_FAILED', 'Transaction cancelled');\n }\n if (msg.includes('Insufficient') || msg.includes('insufficient')) {\n return new T2000Error('INSUFFICIENT_BALANCE', 'Insufficient balance');\n }\n\n return new T2000Error('UNKNOWN', msg, undefined, true);\n}\n\nexport function mapMoveAbortCode(code: number): string {\n const abortMessages: Record<number, string> = {\n 1: 'Protocol is temporarily paused',\n 2: 'Amount must be greater than zero',\n 3: 'Invalid operation type',\n 4: 'Fee rate exceeds maximum',\n 5: 'Insufficient treasury balance',\n 6: 'Not authorized',\n 7: 'Package version mismatch — upgrade required',\n 8: 'Timelock is active — wait for expiry',\n 9: 'No pending change to execute',\n 10: 'Already at current version',\n // NAVI Protocol abort codes\n 1502: 'Oracle price is stale — try again in a moment',\n 1503: 'Withdrawal amount is invalid (zero or dust) — try a specific amount instead of \"all\"',\n 1600: 'Health factor too low — withdrawal would risk liquidation',\n 1605: 'Asset borrowing is disabled or at capacity on this protocol',\n // NAVI utils abort codes\n 46000: 'Insufficient balance to repay — withdraw some savings first to get cash',\n };\n return abortMessages[code] ?? `Move abort code: ${code}`;\n}\n\n/**\n * Check if an error message contains a MoveAbort — these are on-chain\n * failures that will fail no matter how many times you retry.\n */\nexport function isMoveAbort(msg: string): boolean {\n return msg.includes('MoveAbort') || msg.includes('MovePrimitiveRuntimeError');\n}\n\nexport function parseMoveAbortMessage(msg: string): string {\n const abortMatch = msg.match(/abort code:\\s*(\\d+)/i) ?? msg.match(/MoveAbort[^,]*,\\s*(\\d+)/);\n if (abortMatch) {\n const code = parseInt(abortMatch[1], 10);\n\n const moduleMatch = msg.match(/Identifier\\(\"([^\"]+)\"\\)/) ?? msg.match(/in '([^']+)'/);\n const fnMatch = msg.match(/function_name:\\s*Some\\(\"([^\"]+)\"\\)/);\n const context = `${moduleMatch?.[1] ?? ''}${fnMatch ? `::${fnMatch[1]}` : ''}`.toLowerCase();\n const suffix = moduleMatch\n ? ` [${moduleMatch[1]}${fnMatch ? `::${fnMatch[1]}` : ''}]`\n : '';\n\n if (context.includes('slippage')) {\n return `Slippage too high — price moved during execution${suffix}`;\n }\n if (context.includes('balance::split') || context.includes('balance::ENotEnough')) {\n return `Insufficient on-chain balance${suffix}`;\n }\n\n const mapped = mapMoveAbortCode(code);\n return `${mapped}${suffix}`;\n }\n return msg;\n}\n","/**\n * Unified token registry — single source of truth for coin types, decimals, symbols, and tiers.\n *\n * ZERO heavy dependencies. Safe to import from any context (server, browser, Edge).\n *\n * Tier 1: USDC — the financial layer (save, borrow, receive, yield, allowances, marketplace, MPP).\n * Tier 2: 15 curated swap assets — hold, trade, and send only.\n * No tier: Legacy tokens kept for display accuracy (existing NAVI positions). No new operations.\n *\n * To add a new token: add ONE entry to COIN_REGISTRY below. Everything else derives from it.\n * Gate for Tier 2 addition: confirmed deep Cetus liquidity + clear user need.\n */\n\nexport interface CoinMeta {\n type: string;\n decimals: number;\n symbol: string;\n tier?: 1 | 2;\n}\n\n/**\n * Canonical coin registry.\n * Key = user-friendly name (used in swap_execute, CLI, prompts).\n */\nexport const COIN_REGISTRY: Record<string, CoinMeta> = {\n // ── Tier 1 — Financial layer ──────────────────────────────────────────\n USDC: { type: '0xdba34672e30cb065b1f93e3ab55318768fd6fef66c15942c9f7cb846e2f900e7::usdc::USDC', decimals: 6, symbol: 'USDC', tier: 1 },\n\n // ── Tier 2 — Swap assets (15 tokens) ──────────────────────────────────\n SUI: { type: '0x2::sui::SUI', decimals: 9, symbol: 'SUI', tier: 2 },\n wBTC: { type: '0x0041f9f9344cac094454cd574e333c4fdb132d7bcc9379bcd4aab485b2a63942::wbtc::WBTC', decimals: 8, symbol: 'wBTC', tier: 2 },\n ETH: { type: '0xd0e89b2af5e4910726fbcd8b8dd37bb79b29e5f83f7491bca830e94f7f226d29::eth::ETH', decimals: 8, symbol: 'ETH', tier: 2 },\n GOLD: { type: '0x9d297676e7a4b771ab023291377b2adfaa4938fb9080b8d12430e4b108b836a9::xaum::XAUM', decimals: 9, symbol: 'GOLD', tier: 2 },\n DEEP: { type: '0xdeeb7a4662eec9f2f3def03fb937a663dddaa2e215b8078a284d026b7946c270::deep::DEEP', decimals: 6, symbol: 'DEEP', tier: 2 },\n WAL: { type: '0x356a26eb9e012a68958082340d4c4116e7f55615cf27affcff209cf0ae544f59::wal::WAL', decimals: 9, symbol: 'WAL', tier: 2 },\n NS: { type: '0x5145494a5f5100e645e4b0aa950fa6b68f614e8c59e17bc5ded3495123a79178::ns::NS', decimals: 6, symbol: 'NS', tier: 2 },\n IKA: { type: '0x7262fb2f7a3a14c888c438a3cd9b912469a58cf60f367352c46584262e8299aa::ika::IKA', decimals: 9, symbol: 'IKA', tier: 2 },\n CETUS: { type: '0x06864a6f921804860930db6ddbe2e16acdf8504495ea7481637a1c8b9a8fe54b::cetus::CETUS', decimals: 9, symbol: 'CETUS', tier: 2 },\n NAVX: { type: '0xa99b8952d4f7d947ea77fe0ecdcc9e5fc0bcab2841d6e2a5aa00c3044e5544b5::navx::NAVX', decimals: 9, symbol: 'NAVX', tier: 2 },\n vSUI: { type: '0x549e8b69270defbfafd4f94e17ec44cdbdd99820b33bda2278dea3b9a32d3f55::cert::CERT', decimals: 9, symbol: 'vSUI', tier: 2 },\n haSUI: { type: '0xbde4ba4c2e274a60ce15c1cfff9e5c42e41654ac8b6d906a57efa4bd3c29f47d::hasui::HASUI', decimals: 9, symbol: 'haSUI', tier: 2 },\n afSUI: { type: '0xf325ce1300e8dac124071d3152c5c5ee6174914f8bc2161e88329cf579246efc::afsui::AFSUI', decimals: 9, symbol: 'afSUI', tier: 2 },\n LOFI: { type: '0xf22da9a24ad027cccb5f2d496cbe91de953d363513db08a3a734d361c7c17503::LOFI::LOFI', decimals: 9, symbol: 'LOFI', tier: 2 },\n MANIFEST: { type: '0xc466c28d87b3d5cd34f3d5c088751532d71a38d93a8aae4551dd56272cfb4355::manifest::MANIFEST', decimals: 9, symbol: 'MANIFEST', tier: 2 },\n\n // ── Legacy — no tier, kept for display accuracy on existing positions ──\n USDT: { type: '0x375f70cf2ae4c00bf37117d0c85a2c71545e6ee05c4a5c7d282cd66a4504b068::usdt::USDT', decimals: 6, symbol: 'USDT' },\n USDe: { type: '0x41d587e5336f1c86cad50d38a7136db99333bb9bda91cea4ba69115defeb1402::sui_usde::SUI_USDE', decimals: 6, symbol: 'USDe' },\n USDSUI: { type: '0x44f838219cf67b058f3b37907b655f226153c18e33dfcd0da559a844fea9b1c1::usdsui::USDSUI', decimals: 6, symbol: 'USDsui' },\n};\n\n/** Reverse lookup: coin type → CoinMeta. Built once at import time. */\nconst BY_TYPE = new Map<string, CoinMeta>();\nfor (const meta of Object.values(COIN_REGISTRY)) {\n BY_TYPE.set(meta.type, meta);\n}\n\n// ── Lookup helpers ───────────────────────────────────────────────────────\n\n/**\n * Returns the registry metadata for a coin type, or `undefined` if the coin\n * is not in the registry. Use this when you need to distinguish \"known coin\"\n * from \"supported coin\" — `isSupported` only flags tiered (active) coins,\n * but legacy coins like USDsui / USDe / USDT are in the registry without a\n * tier and still need canonical-symbol resolution.\n */\nexport function getCoinMeta(coinType: string): CoinMeta | undefined {\n return BY_TYPE.get(coinType);\n}\n\n/**\n * Returns true if the coin type appears anywhere in COIN_REGISTRY (tier 1, 2,\n * OR legacy/no-tier). Different from `isSupported`, which excludes legacy\n * entries. The blockvision-prices canonical-symbol gate uses this looser\n * check so that USDsui (legacy/no-tier today, but with a registry-canonical\n * mixed-case symbol) still wins over BlockVision's uppercase 'USDSUI'.\n */\nexport function isInRegistry(coinType: string): boolean {\n return BY_TYPE.has(coinType);\n}\n\n// ── Tier helpers ─────────────────────────────────────────────────────────\n\n/** Returns true if the coin type is Tier 1 (USDC — the financial layer). */\nexport function isTier1(coinType: string): boolean {\n const meta = BY_TYPE.get(coinType);\n return meta?.tier === 1;\n}\n\n/** Returns true if the coin type is Tier 2 (curated swap asset). */\nexport function isTier2(coinType: string): boolean {\n const meta = BY_TYPE.get(coinType);\n return meta?.tier === 2;\n}\n\n/** Returns true if the coin type is actively supported (Tier 1 or Tier 2). */\nexport function isSupported(coinType: string): boolean {\n const meta = BY_TYPE.get(coinType);\n return meta?.tier !== undefined;\n}\n\n/** Returns the tier for a coin type, or undefined if legacy/unknown. */\nexport function getTier(coinType: string): 1 | 2 | undefined {\n return BY_TYPE.get(coinType)?.tier;\n}\n\n// ── Lookup helpers ───────────────────────────────────────────────────────\n\n/**\n * Get decimals for any coin type. Checks full type match, then suffix match, then defaults to 9.\n * Works for both tiered and legacy tokens.\n */\nexport function getDecimalsForCoinType(coinType: string): number {\n const direct = BY_TYPE.get(coinType);\n if (direct) return direct.decimals;\n\n const suffix = coinType.split('::').slice(1).join('::').toUpperCase();\n if (suffix) {\n for (const meta of BY_TYPE.values()) {\n const metaSuffix = meta.type.split('::').slice(1).join('::').toUpperCase();\n if (metaSuffix === suffix) return meta.decimals;\n }\n }\n\n return 9;\n}\n\n/**\n * Resolve a full coin type to a user-friendly symbol.\n * Returns the last `::` segment if not in the registry.\n */\nexport function resolveSymbol(coinType: string): string {\n const direct = BY_TYPE.get(coinType);\n if (direct) return direct.symbol;\n\n const suffix = coinType.split('::').slice(1).join('::').toUpperCase();\n if (suffix) {\n for (const meta of BY_TYPE.values()) {\n const metaSuffix = meta.type.split('::').slice(1).join('::').toUpperCase();\n if (metaSuffix === suffix) return meta.symbol;\n }\n }\n\n return coinType.split('::').pop() ?? coinType;\n}\n\n/**\n * Name → type map for swap resolution. Derived from COIN_REGISTRY.\n * Contains BOTH original-case and UPPERCASE keys for case-insensitive lookup.\n */\nexport const TOKEN_MAP: Record<string, string> = (() => {\n const map: Record<string, string> = {};\n for (const [name, meta] of Object.entries(COIN_REGISTRY)) {\n map[name] = meta.type;\n map[name.toUpperCase()] = meta.type;\n }\n return map;\n})();\n\n/**\n * Resolve a user-friendly token name to its full coin type.\n * Returns the input unchanged if already a full coin type (contains \"::\").\n * Case-insensitive: 'usde', 'USDe', 'USDE' all resolve correctly.\n */\nexport function resolveTokenType(nameOrType: string): string | null {\n if (nameOrType.includes('::')) return nameOrType;\n return TOKEN_MAP[nameOrType] ?? TOKEN_MAP[nameOrType.toUpperCase()] ?? null;\n}\n\n/** Common type constants for direct import. */\nexport const SUI_TYPE = COIN_REGISTRY.SUI.type;\nexport const USDC_TYPE = COIN_REGISTRY.USDC.type;\nexport const USDT_TYPE = COIN_REGISTRY.USDT.type;\nexport const USDSUI_TYPE = COIN_REGISTRY.USDSUI.type;\nexport const USDE_TYPE = COIN_REGISTRY.USDe.type;\nexport const ETH_TYPE = COIN_REGISTRY.ETH.type;\nexport const WBTC_TYPE = COIN_REGISTRY.wBTC.type;\nexport const WAL_TYPE = COIN_REGISTRY.WAL.type;\nexport const NAVX_TYPE = COIN_REGISTRY.NAVX.type;\nexport const IKA_TYPE = COIN_REGISTRY.IKA.type;\nexport const LOFI_TYPE = COIN_REGISTRY.LOFI.type;\nexport const MANIFEST_TYPE = COIN_REGISTRY.MANIFEST.type;\n","import type { Ed25519Keypair } from '@mysten/sui/keypairs/ed25519';\nimport type { TransactionSigner } from '../signer.js';\n\nexport class KeypairSigner implements TransactionSigner {\n constructor(private readonly keypair: Ed25519Keypair) {}\n\n getAddress(): string {\n return this.keypair.getPublicKey().toSuiAddress();\n }\n\n async signTransaction(txBytes: Uint8Array): Promise<{ signature: string }> {\n return this.keypair.signTransaction(txBytes);\n }\n\n async signPersonalMessage(messageBytes: Uint8Array): Promise<{ signature: string; bytes: string }> {\n return this.keypair.signPersonalMessage(messageBytes);\n }\n\n /** Access the underlying keypair for APIs that still require it directly. */\n getKeypair(): Ed25519Keypair {\n return this.keypair;\n }\n}\n","import type { Ed25519Keypair } from '@mysten/sui/keypairs/ed25519';\nimport type { TransactionSigner } from '../signer.js';\n\nexport interface ZkLoginProof {\n proofPoints: {\n a: string[];\n b: string[][];\n c: string[];\n };\n issBase64Details: {\n indexMod4: number;\n value: string;\n };\n headerBase64: string;\n addressSeed: string;\n}\n\nexport class ZkLoginSigner implements TransactionSigner {\n constructor(\n private readonly ephemeralKeypair: Ed25519Keypair,\n private readonly zkProof: ZkLoginProof,\n private readonly userAddress: string,\n private readonly maxEpoch: number,\n ) {}\n\n getAddress(): string {\n return this.userAddress;\n }\n\n async signTransaction(txBytes: Uint8Array): Promise<{ signature: string }> {\n const { getZkLoginSignature } = await import('@mysten/zklogin');\n const ephSig = await this.ephemeralKeypair.signTransaction(txBytes);\n return {\n signature: getZkLoginSignature({\n inputs: this.zkProof,\n maxEpoch: this.maxEpoch,\n userSignature: ephSig.signature,\n }),\n };\n }\n\n async signPersonalMessage(_messageBytes: Uint8Array): Promise<{ signature: string; bytes: string }> {\n // zkLogin personal-message signing for `@suimpp/mpp` 0.7+ grief protection\n // is not yet wired here. Audric (the only zkLogin consumer today) uses the\n // sponsored-tx flow which does not call `sdk.pay()`. Implement when audric\n // needs to drive MPP payments directly from the SDK.\n throw new Error('ZkLoginSigner.signPersonalMessage is not yet implemented. Use KeypairSigner for sdk.pay() until grief-protection signing is wired for zkLogin.');\n }\n\n isExpired(currentEpoch: number): boolean {\n return currentEpoch >= this.maxEpoch;\n }\n}\n","/**\n * Browser-safe entry point for @t2000/sdk.\n *\n * Exports everything the web app needs WITHOUT Node-only modules:\n * - keyManager (fs-based wallet encryption)\n * - ContactManager (file-based contacts)\n *\n * Protocol adapters are NOT statically exported here — import them\n * via dynamic import() in the web app to keep the initial bundle small.\n */\n\n// Signer abstraction\nexport type { TransactionSigner } from './signer.js';\nexport { KeypairSigner } from './wallet/keypairSigner.js';\nexport { ZkLoginSigner, type ZkLoginProof } from './wallet/zkLoginSigner.js';\n\n// Error handling\nexport { T2000Error, mapWalletError, mapMoveAbortCode } from './errors.js';\nexport type { T2000ErrorCode, T2000ErrorData } from './errors.js';\n\n// Constants\nexport {\n MIST_PER_SUI,\n SUI_DECIMALS,\n USDC_DECIMALS,\n BPS_DENOMINATOR,\n SAVE_FEE_BPS,\n BORROW_FEE_BPS,\n T2000_OVERLAY_FEE_WALLET,\n SUPPORTED_ASSETS,\n CLOCK_ID,\n DEFAULT_NETWORK,\n} from './constants.js';\nexport type { SupportedAsset, StableAsset } from './constants.js';\nexport {\n STABLE_ASSETS,\n ALL_NAVI_ASSETS,\n GAS_RESERVE_MIN,\n} from './constants.js';\n\n// Utilities\nexport { validateAddress, truncateAddress } from './utils/sui.js';\nexport {\n KNOWN_TARGETS,\n LABEL_PATTERNS,\n classifyAction,\n classifyLabel,\n fallbackLabel,\n refineLendingLabel,\n classifyTransaction,\n extractTransferDetails,\n extractAllUserLegs,\n} from './wallet/classify.js';\nexport type {\n ClassifyBalanceChange,\n ClassifyResult,\n ExtractedTransfer,\n TxDirection,\n} from './wallet/classify.js';\n/**\n * RPC tx parsing helpers. Safe in the browser — they only do shape\n * inspection / classification and do not import any Node-only modules.\n * `queryHistory` and `queryTransaction` are not re-exported here\n * because they take a Node `SuiJsonRpcClient`; consumers can build\n * the same flow with `parseSuiRpcTx` + their own RPC fetch.\n */\nexport {\n parseSuiRpcTx,\n extractTxSender,\n extractTxCommands,\n} from './wallet/history.js';\nexport type { SuiRpcTxBlock } from './wallet/history.js';\nexport {\n mistToSui,\n suiToMist,\n usdcToRaw,\n rawToUsdc,\n stableToRaw,\n rawToStable,\n getDecimals,\n formatUsd,\n formatSui,\n formatAssetAmount,\n} from './utils/format.js';\nexport { toBase64, fromBase64 } from './utils/base64.js';\n\n// Simulation — use dynamic import() to avoid Buffer dependency in browser bundles\n// import { simulateTransaction } from '@t2000/sdk' (main entry) for Node usage\nexport type { SimulationResult } from './utils/simulate.js';\n\n// Protocol fee\nexport { calculateFee, addFeeTransfer } from './protocols/protocolFee.js';\nexport type { ProtocolFeeInfo, FeeOperation } from './protocols/protocolFee.js';\n\n// Cetus aggregator helpers — Audric prepare/route.ts uses these directly to\n// build swap PTBs with overlay fees (per-call, not module-global).\nexport { findSwapRoute, buildSwapTx, OVERLAY_FEE_RATE } from './protocols/cetus-swap.js';\nexport type { SwapRouteResult, OverlayFeeConfig } from './protocols/cetus-swap.js';\n\n// Safeguards — only browser-safe exports (SafeguardEnforcer uses node:fs)\nexport { SafeguardError } from './safeguards/errors.js';\nexport type { SafeguardRule, SafeguardErrorDetails } from './safeguards/errors.js';\nexport type { SafeguardConfig, TxMetadata } from './safeguards/types.js';\nexport { OUTBOUND_OPS, DEFAULT_SAFEGUARD_CONFIG } from './safeguards/types.js';\n\n// Types\nexport type {\n BalanceResponse,\n GasReserve,\n SendResult,\n SaveResult,\n WithdrawResult,\n BorrowResult,\n RepayResult,\n HealthFactorResult,\n MaxWithdrawResult,\n MaxBorrowResult,\n AssetRates,\n RatesResult,\n PositionEntry,\n PositionsResult,\n EarningsResult,\n FundStatusResult,\n DepositInfo,\n TransactionRecord,\n TransactionLeg,\n ClaimRewardsResult,\n PendingReward,\n PayOptions,\n PayResult,\n} from './types.js';\n\n// Token registry — zero Node.js deps, safe for client-side use\nexport {\n COIN_REGISTRY,\n TOKEN_MAP,\n resolveTokenType,\n resolveSymbol,\n getDecimalsForCoinType,\n isTier1,\n isTier2,\n isSupported,\n getTier,\n SUI_TYPE,\n USDC_TYPE,\n USDT_TYPE,\n USDSUI_TYPE,\n USDE_TYPE,\n ETH_TYPE,\n WBTC_TYPE,\n WAL_TYPE,\n NAVX_TYPE,\n IKA_TYPE,\n LOFI_TYPE,\n MANIFEST_TYPE,\n} from './token-registry.js';\nexport type { CoinMeta } from './token-registry.js';\n","import { T2000Error } from './errors.js';\n\nexport const MIST_PER_SUI = 1_000_000_000n;\nexport const SUI_DECIMALS = 9;\nexport const USDC_DECIMALS = 6;\n\nexport const BPS_DENOMINATOR = 10_000n;\nexport const PRECISION = 1_000_000_000_000_000_000n;\n\nexport const MIN_DEPOSIT = 1_000_000n; // 1 USDC (6 decimals)\n\nexport const SAVE_FEE_BPS = 10n; // 0.1%\nexport const BORROW_FEE_BPS = 5n; // 0.05%\n\nexport const CLOCK_ID = '0x6';\n\nexport const SUPPORTED_ASSETS = {\n USDC: {\n type: '0xdba34672e30cb065b1f93e3ab55318768fd6fef66c15942c9f7cb846e2f900e7::usdc::USDC',\n decimals: 6,\n symbol: 'USDC',\n displayName: 'USDC',\n },\n USDT: {\n type: '0x375f70cf2ae4c00bf37117d0c85a2c71545e6ee05c4a5c7d282cd66a4504b068::usdt::USDT',\n decimals: 6,\n symbol: 'USDT',\n displayName: 'suiUSDT',\n },\n USDe: {\n type: '0x41d587e5336f1c86cad50d38a7136db99333bb9bda91cea4ba69115defeb1402::sui_usde::SUI_USDE',\n decimals: 6,\n symbol: 'USDe',\n displayName: 'suiUSDe',\n },\n USDsui: {\n type: '0x44f838219cf67b058f3b37907b655f226153c18e33dfcd0da559a844fea9b1c1::usdsui::USDSUI',\n decimals: 6,\n symbol: 'USDsui',\n displayName: 'USDsui',\n },\n SUI: {\n type: '0x2::sui::SUI',\n decimals: 9,\n symbol: 'SUI',\n displayName: 'SUI',\n },\n WAL: {\n type: '0x356a26eb9e012a68958082340d4c4116e7f55615cf27affcff209cf0ae544f59::wal::WAL',\n decimals: 9,\n symbol: 'WAL',\n displayName: 'WAL',\n },\n ETH: {\n type: '0xd0e89b2af5e4910726fbcd8b8dd37bb79b29e5f83f7491bca830e94f7f226d29::eth::ETH',\n decimals: 8,\n symbol: 'ETH',\n displayName: 'suiETH',\n },\n NAVX: {\n type: '0xa99b8952d4f7d947ea77fe0ecdcc9e5fc0bcab2841d6e2a5aa00c3044e5544b5::navx::NAVX',\n decimals: 9,\n symbol: 'NAVX',\n displayName: 'NAVX',\n },\n GOLD: {\n type: '0x9d297676e7a4b771ab023291377b2adfaa4938fb9080b8d12430e4b108b836a9::xaum::XAUM',\n decimals: 6,\n symbol: 'GOLD',\n displayName: 'XAUM',\n },\n} as const;\n\nexport type SupportedAsset = keyof typeof SUPPORTED_ASSETS;\n\n// [SPEC_AGENTIC_STACK P1 / SDK F3 — 2026-05-25]\n// `StableAsset` = \"what we treat as worth $1 for wallet pricing and balance roll-up\".\n// Pre-Phase 1: USDC only — left USDsui wallet holdings invisible to balance.ts.\n// Phase 1: widened to USDC + USDsui (both are NAVI-native stables with $1 peg).\n// USDT / USDe stay OUT of this set deliberately — they are stables, but the\n// codebase has never priced them at $1, and adding them here would require\n// auditing balance.ts callers downstream. Keep the carve minimal.\nexport type StableAsset = 'USDC' | 'USDsui';\nexport const STABLE_ASSETS: readonly StableAsset[] = ['USDC', 'USDsui'] as const;\n\n// [SPEC_AGENTIC_STACK P1 / SDK F4 — 2026-05-25]\n// `SaveableAsset` = \"what you can deposit into a NAVI lending pool to earn yield\".\n// Semantically distinct from STABLE_ASSETS even though the sets are identical today:\n// if USDe-on-NAVI lands in the future, USDe would join STABLE_ASSETS but NOT\n// SAVEABLE_ASSETS until the NAVI USDe pool is verified live.\n// See `.cursor/rules/savings-usdc-only.mdc` for the rule that gates additions.\nexport type SaveableAsset = 'USDC' | 'USDsui';\nexport const SAVEABLE_ASSETS: readonly SaveableAsset[] = ['USDC', 'USDsui'] as const;\n\nexport const ALL_NAVI_ASSETS: readonly SupportedAsset[] = Object.keys(SUPPORTED_ASSETS) as SupportedAsset[];\n\n// ---------------------------------------------------------------------------\n// Operation → allowed asset rules (single source of truth)\n// ---------------------------------------------------------------------------\n\n// [v0.51.0] Saveable/borrowable set: USDC + USDsui.\n// USDC is the canonical default; USDsui is a strategic exception backed by an\n// existing NAVI pool. See `.cursor/rules/savings-usdc-only.mdc` for the\n// rationale and the rule that gates additional stables (don't add more here\n// without updating that file).\n//\n// [v4.0 Phase A Day 2 — 2026-05-26] `send` constrained from `'*'` (any) to\n// `['USDC', 'USDsui', 'SUI']`. Rationale (SPEC_AGENT_WALLET_GREENFIELD §A):\n// - USDC + USDsui are gasless via `0x2::balance::send_funds` (Sui mainnet\n// protocol allowlist) — the two foundation stables.\n// - SUI is the only non-stable kept on the allowlist so users with no\n// stablecoin balance can still pay gas-native SUI transfers.\n// - USDT, USDe, WAL, ETH, NAVX, GOLD are NOT sendable — users must swap to\n// USDC/USDsui first (one-step) or hold SUI and use a manual Move call.\n// - Tracking the full Sui gasless allowlist (suiUSDe, USDY, FDUSD, AUSD, USDB)\n// is intentionally deferred to follow-up SPEC; minimal allowlist now.\nexport const OPERATION_ASSETS = {\n save: ['USDC', 'USDsui'],\n borrow: ['USDC', 'USDsui'],\n withdraw: '*',\n repay: '*',\n send: ['USDC', 'USDsui', 'SUI'],\n swap: '*',\n} as const;\n\nexport type Operation = keyof typeof OPERATION_ASSETS;\n\nexport function isAllowedAsset(op: Operation, asset: string): boolean {\n const allowed = OPERATION_ASSETS[op];\n if (allowed === '*') return true;\n // [v0.51.0] Mixed-case canonical keys (USDsui, suiUSDT) need case-insensitive\n // membership. Pre-v0.51 we only had USDC ↔ USDC (uppercase identity), so\n // a one-sided uppercase compare looked correct. Now that USDsui is in the\n // set, normalize both sides.\n const target = asset.toLowerCase();\n return (allowed as readonly string[]).some((a) => a.toLowerCase() === target);\n}\n\n/**\n * Throws if the asset is not permitted for the given operation.\n *\n * [v4.0 Phase A Day 2] Pre-v4 this allowed `undefined` as a silent default\n * to USDC. Removed because every write path now requires explicit asset\n * (see `T2000.send` + `buildSendTx` + `composeTx.send_transfer`). Save /\n * borrow / repay still call this with `params.asset` (which may be\n * undefined when the caller relies on the per-method `?? 'USDC'` default\n * before this assertion fires), so the `undefined → no-op` branch stays\n * for back-compat; the `send_transfer` flow validates non-undefined.\n */\nexport function assertAllowedAsset(op: Operation, asset: string | undefined): void {\n if (!asset) return;\n if (!isAllowedAsset(op, asset)) {\n const allowed = OPERATION_ASSETS[op];\n const list = Array.isArray(allowed) ? allowed.join(', ') : 'any';\n const swapHint =\n op === 'save' ? ' Swap to USDC or USDsui first.'\n : op === 'send' ? ' Swap to USDC or USDsui first, or send SUI.'\n : '';\n throw new T2000Error(\n 'INVALID_ASSET',\n `${op} only supports ${list}. Cannot use ${asset}.${swapHint}`,\n );\n }\n}\n\n/**\n * [v4.0 Phase A Day 2] Narrow type alias for assets sendable through the\n * Agent Wallet. Matches `OPERATION_ASSETS.send` exactly. Exported so the\n * CLI / SDK / composeTx can share one type without re-declaring it.\n */\nexport type SendableAsset = 'USDC' | 'USDsui' | 'SUI';\nexport const SENDABLE_ASSETS: readonly SendableAsset[] = ['USDC', 'USDsui', 'SUI'] as const;\n\n/**\n * [v4.0 Phase A Day 2] Coin types for the two gasless-allowlisted stables.\n * Used by `wallet/send.ts` + `composeTx.send_transfer` to construct the\n * `0x2::balance::send_funds` Move call's `typeArguments`. SUI is excluded\n * because SUI transfers are NOT gasless (gas-native, uses `tx.gas` split +\n * `transferObjects` per the existing path).\n */\nexport const GASLESS_STABLE_TYPES: Record<'USDC' | 'USDsui', string> = {\n USDC: SUPPORTED_ASSETS.USDC.type,\n USDsui: SUPPORTED_ASSETS.USDsui.type,\n};\n\n// All protocol fees route here as a regular USDC wallet transfer. Audric's\n// prepare/route.ts adds `addFeeTransfer(...)` inline for save/borrow and passes\n// `overlayFee.receiver = T2000_OVERLAY_FEE_WALLET` for swaps. The CLI/SDK never\n// charge fees — this constant is exported for consumer apps only.\n//\n// Address corresponds to the treasury admin wallet. Override via env for local dev /\n// testnet only — production must use the canonical mainnet address below.\nexport const T2000_OVERLAY_FEE_WALLET = process.env.T2000_OVERLAY_FEE_WALLET\n ?? '0x5366efbf2b4fe5767fe2e78eb197aa5f5d138d88ac3333fbf3f80a1927da473a';\n\nexport const DEFAULT_NETWORK = 'mainnet' as const;\nexport const DEFAULT_RPC_URL = 'https://fullnode.mainnet.sui.io:443';\n// [v4.0 Phase A Day 2] gRPC fullnode endpoint used by `getSuiGrpcClient()` for\n// gasless stablecoin transfer detection (T2000.send + composeTx send_transfer).\n// Reads stay JSON-RPC; only write paths that need gasless eligibility detection\n// build via gRPC. Override with T2000_GRPC_URL for local dev / testnet.\nexport const DEFAULT_GRPC_URL = 'https://fullnode.mainnet.sui.io:443';\nexport const DEFAULT_KEY_PATH = '~/.t2000/wallet.key';\nexport const DEFAULT_CONFIG_PATH = '~/.t2000/config.json';\n\n// [v4.0 Phase A Day 2] Minimum stablecoin amount for protocol-level gasless\n// transfers via `0x2::balance::send_funds`. The Sui mainnet allowlist enforces\n// this floor at the protocol level to prevent dust spam; we surface a clear\n// error before signing rather than letting the tx revert on-chain.\nexport const GASLESS_MIN_STABLE_AMOUNT = 0.01;\n\n// Cetus USDC/SUI pool — read-only for SUI price oracle (no SDK dependency)\nexport const CETUS_USDC_SUI_POOL = '0x51e883ba7c0b566a26cbc8a94cd33eb0abd418a77cc1e60ad22fd9b1f29cd2ab';\n\nexport const GAS_RESERVE_MIN = 0.05; // minimum SUI to keep for gas\n","import { SuiJsonRpcClient, getJsonRpcFullnodeUrl } from '@mysten/sui/jsonRpc';\nimport { SuiGrpcClient } from '@mysten/sui/grpc';\nimport { isValidSuiAddress, normalizeSuiAddress } from '@mysten/sui/utils';\nimport { DEFAULT_GRPC_URL, DEFAULT_RPC_URL } from '../constants.js';\nimport { T2000Error } from '../errors.js';\n\n/**\n * Resolve the effective JSON-RPC URL: explicit arg > env var > default.\n * `T2000_RPC_URL` is an OPTIONAL override per the Greenfield SPEC's env\n * contract — no required vars, so we read inline (allowed by\n * `env-validation-gate.mdc` carve-out for packages with zero required\n * env vars).\n */\nfunction resolveRpcUrl(rpcUrl?: string): string {\n if (rpcUrl) return rpcUrl;\n const envUrl = process.env.T2000_RPC_URL?.trim();\n if (envUrl) return envUrl;\n return DEFAULT_RPC_URL;\n}\n\n/**\n * Same shape as `resolveRpcUrl` for the gRPC endpoint.\n */\nfunction resolveGrpcUrl(grpcUrl?: string): string {\n if (grpcUrl) return grpcUrl;\n const envUrl = process.env.T2000_GRPC_URL?.trim();\n if (envUrl) return envUrl;\n return DEFAULT_GRPC_URL;\n}\n\n/**\n * JSON-RPC client cache, keyed by URL. The earlier impl cached\n * unconditionally and ignored URL changes after the first call —\n * brittle for testnet smokes and custom-RPC test setups.\n */\nconst rpcClientCache = new Map<string, SuiJsonRpcClient>();\n\nexport function getSuiClient(rpcUrl?: string): SuiJsonRpcClient {\n const url = resolveRpcUrl(rpcUrl);\n const cached = rpcClientCache.get(url);\n if (cached) return cached;\n const client = new SuiJsonRpcClient({ url, network: 'mainnet' });\n rpcClientCache.set(url, client);\n return client;\n}\n\nexport function createSuiClient(network: 'mainnet' | 'testnet' = 'mainnet'): SuiJsonRpcClient {\n return new SuiJsonRpcClient({ url: getJsonRpcFullnodeUrl(network), network });\n}\n\n/**\n * gRPC client cache, keyed by URL. Same rationale as the JSON-RPC cache:\n * different URLs must produce different clients.\n */\nconst grpcClientCache = new Map<string, SuiGrpcClient>();\n\n/**\n * Cached `SuiGrpcClient` for gasless stablecoin transfer builds.\n *\n * [v4.0 Phase A Day 2 — SPEC_AGENT_WALLET_GREENFIELD §A]\n *\n * Why this exists: Sui mainnet's protocol-level gasless stablecoin transfers\n * (`0x2::balance::send_funds` on the USDC + USDsui allowlist) are detected\n * ONLY when the transaction is built through a `SuiGrpcClient`. The gRPC\n * client's build resolver inspects the PTB at `tx.build()` time and, if it\n * matches the gasless pattern, sets `gasPrice=0` + `gasBudget=0` automatically.\n * Building the SAME PTB through `SuiJsonRpcClient` produces the same bytes\n * but with non-zero gas — the tx still works, but the user pays SUI gas.\n *\n * Execution stays on JSON-RPC (`SuiJsonRpcClient.executeTransactionBlock`)\n * because (a) the rest of the SDK expects JSON-RPC and (b) Sui's docs\n * explicitly support a \"build via gRPC, execute via JSON-RPC\" hybrid:\n * https://docs.sui.io/develop/transaction-payment/gasless-stablecoin-transfers\n *\n * Override the endpoint with the `T2000_GRPC_URL` env var or the\n * `grpcUrl` arg. Cache is keyed by URL so multiple endpoints can\n * co-exist (e.g., the rare testnet smoke + production usage from the\n * same process).\n */\nexport function getSuiGrpcClient(grpcUrl?: string): SuiGrpcClient {\n const baseUrl = resolveGrpcUrl(grpcUrl);\n const cached = grpcClientCache.get(baseUrl);\n if (cached) return cached;\n const client = new SuiGrpcClient({ baseUrl, network: 'mainnet' });\n grpcClientCache.set(baseUrl, client);\n return client;\n}\n\nexport function validateAddress(address: string): string {\n const normalized = normalizeSuiAddress(address);\n if (!isValidSuiAddress(normalized)) {\n throw new T2000Error('INVALID_ADDRESS', `Invalid Sui address: ${address}`);\n }\n return normalized;\n}\n\nexport function truncateAddress(address: string): string {\n if (address.length <= 10) return address;\n return `${address.slice(0, 6)}...${address.slice(-4)}`;\n}\n\n/**\n * Normalize a Sui coin type to its canonical long-form 64-hex address.\n * `0x2::sui::SUI` → `0x0000…0002::sui::SUI`. Idempotent on already-long\n * forms. Returns the input unchanged if it doesn't look like a coin type\n * (`<address>::<module>::<name>`) so callers can pass arbitrary strings\n * without crashing.\n *\n * Why this exists: BlockVision's `/v2/sui/coin/price/list` endpoint\n * silently returns an empty `prices` map for short-form coin types\n * (notably `0x2::sui::SUI` — the native gas coin). Internal callers must\n * pass the long form, but external callers (LLM tool args, cached\n * coin-type strings, audit logs) commonly use the short form. Normalize\n * before the network call, denormalize back to the caller's input shape\n * after, and short/long become interchangeable.\n */\nexport function normalizeCoinType(coinType: string): string {\n const parts = coinType.split('::');\n if (parts.length !== 3) return coinType;\n const [addr, mod, name] = parts;\n if (!addr.startsWith('0x')) return coinType;\n return `${normalizeSuiAddress(addr)}::${mod}::${name}`;\n}\n","/**\n * Shared transaction classifier.\n *\n * Consumed by both the SDK's `parseTxRecord` (production agent path) and\n * the engine's `transaction_history` tool (cold-start RPC path). Keeping\n * a single source of truth here prevents the two paths from drifting —\n * see v1.5.3 regression where the SDK path was emitting `action:\n * 'transaction'` (rendered as \"On-chain\") while the engine path was\n * already producing fine-grained labels.\n */\n\nimport { getDecimalsForCoinType, resolveSymbol, SUI_TYPE } from '../token-registry.js';\n\n/**\n * Coarse action bucket — one of `'send' | 'lending' | 'swap' |\n * 'transaction'`. Used by the ACI `action` filter on the\n * `transaction_history` tool. STABLE: downstream queries depend on\n * exactly these values.\n *\n * Order matters: more specific buckets first. Lending patterns precede\n * swap patterns so a NAVI `::swap` helper (if one ever existed) would\n * still bucket as lending.\n */\nexport const KNOWN_TARGETS: readonly [RegExp, string][] = [\n [/::suilend|::obligation/, 'lending'],\n [/::navi|::lending_core|::incentive_v\\d+|::oracle_pro/, 'lending'],\n /**\n * DEX modules — both direct calls and aggregator legs. The Cetus\n * aggregator dispatches through a per-DEX module (e.g.\n * `cetus::swap`, `flowx_amm::swap`, `aftermath::swap`, …) plus\n * router glue functions. We list every DEX module the aggregator\n * supports today so a single-DEX call still classifies cleanly.\n */\n [/::cetus(?:_dlmm)?::|::pool::|::deepbook|::flowx_(?:amm|clmm)::|::kriya_(?:amm|clmm)::|::turbos::|::aftermath::|::afsui::|::bluefin::|::bluemove::|::ferra_(?:clmm|dlmm)::|::haedal_hmm::|::hasui::|::hawal::|::magma::|::momentum::|::obric::|::springsui::|::steamm_cpmm::|::fullsail::|::alphafi::|::volo_swap::/, 'swap'],\n /**\n * Cetus aggregator router glue. These are the swap-context and\n * balance-handling helpers the aggregator emits around per-DEX\n * legs. Without this entry a tx that ONLY had router calls\n * (theoretically possible for setup/cleanup) would slip through;\n * in practice these always coexist with a DEX leg, but the entry\n * is cheap insurance.\n */\n [/::router::(?:new_swap_context(?:_v)?|confirm_swap|transfer_balance|take_balance|transfer_or_destroy_coin)/, 'swap'],\n [/::transfer::public_transfer/, 'send'],\n];\n\n/**\n * Finer-grained display labels — derived from MoveCall function names.\n * The card renders `label ?? action`, so when this map matches we get\n * \"Deposit\" / \"Withdraw\" / \"Borrow\" / \"Repay\" / \"Payment link\" instead\n * of the generic \"Lending\" or \"Transaction\".\n *\n * Order matters: more specific patterns first. Each entry is\n * (regex, label) where the regex is matched against the\n * fully-qualified MoveCall target `pkg::module::function`.\n */\nexport const LABEL_PATTERNS: readonly [RegExp, string][] = [\n [/::pay(?:ment_kit|_kit)?::|::create_payment_link|::pay_link/, 'payment_link'],\n [/::create_invoice|::invoice::/, 'invoice'],\n [/::deposit|::supply|::mint_ctokens/, 'deposit'],\n [/::withdraw|::redeem|::redeem_ctokens/, 'withdraw'],\n [/::borrow/, 'borrow'],\n [/::repay/, 'repay'],\n [/::claim_reward|::claim::|::claim_incentive/, 'claim'],\n [/::stake/, 'stake'],\n [/::unstake|::burn::/, 'unstake'],\n [/::liquidate/, 'liquidate'],\n];\n\nexport interface ClassifyBalanceChange {\n owner: { AddressOwner?: string } | string;\n coinType: string;\n amount: string;\n}\n\nfunction resolveOwner(owner: ClassifyBalanceChange['owner']): string | null {\n if (typeof owner === 'object' && owner.AddressOwner) return owner.AddressOwner;\n if (typeof owner === 'string') return owner;\n return null;\n}\n\nexport function classifyAction(targets: string[], commandTypes: string[]): string {\n for (const target of targets) {\n for (const [pattern, label] of KNOWN_TARGETS) {\n if (pattern.test(target)) return label;\n }\n }\n if (commandTypes.includes('TransferObjects') && !commandTypes.includes('MoveCall')) return 'send';\n return 'transaction';\n}\n\n/**\n * Last-resort fallback when neither `LABEL_PATTERNS` nor the action\n * bucket produces something useful.\n *\n * Returns the first MoveCall's *module* name (e.g. \"navi\", \"spam\") so\n * the card shows something better than the literal word \"transaction\".\n * When no MoveCall exists, returns 'on-chain'.\n *\n * Note: callers should prefer `classifyLabel` which now layers\n * pattern-match → coarse action → module name (see commentary there).\n */\nexport function fallbackLabel(targets: string[]): string {\n if (!targets.length) return 'on-chain';\n const first = targets[0];\n const parts = first.split('::');\n if (parts.length >= 2 && parts[1]) return parts[1].toLowerCase();\n return 'on-chain';\n}\n\n/**\n * Three-tier label resolution for the transaction history card:\n * 1. Specific keyword match in `LABEL_PATTERNS` (\"deposit\",\n * \"payment_link\", …).\n * 2. Coarse action bucket from `classifyAction` (\"swap\", \"send\",\n * \"lending\") — prevents leaking opaque internal module names like\n * \"router\" (Cetus aggregator) or \"cross_swap\" (third-party DEX\n * aggregators) for txs that we already classified as a swap.\n * 3. Module name from the first MoveCall (`fallbackLabel`) — only\n * used when the action bucket itself is the generic \"transaction\".\n *\n * Pre-v0.46.2 we skipped tier 2, so swaps showed labels like \"router\",\n * \"cross_swap\", \"scallop_router\", etc. instead of the clean \"swap\".\n */\nexport function classifyLabel(targets: string[], commandTypes: string[]): string {\n for (const target of targets) {\n for (const [pattern, label] of LABEL_PATTERNS) {\n if (pattern.test(target)) return label;\n }\n }\n if (commandTypes.includes('TransferObjects') && !commandTypes.includes('MoveCall')) return 'send';\n const action = classifyAction(targets, commandTypes);\n if (action !== 'transaction') return action;\n return fallbackLabel(targets);\n}\n\n/**\n * Balance-direction tiebreaker for ambiguous lending calls.\n *\n * Many lending modules expose generic entry points (NAVI's bundled\n * flash actions, `lending_core::*::entry_*`, etc.) that don't carry\n * a `deposit`/`withdraw`/`borrow`/`repay` keyword in the function\n * name. When `classifyLabel` falls back to a bare module name like\n * `\"lending\"` for a known lending tx, infer direction from the user's\n * non-SUI balance change:\n * - net outflow of the supplied asset → deposit (also covers repay,\n * but repay-without-keyword is essentially never emitted).\n * - net inflow of the supplied asset → withdraw (also covers borrow).\n * SUI is excluded so gas-only transactions don't get mislabeled.\n *\n * If `LABEL_PATTERNS` matched a specific keyword, the existing label is\n * returned unchanged.\n */\nexport function refineLendingLabel(\n currentAction: string,\n currentLabel: string,\n moveCallTargets: string[],\n changes: ClassifyBalanceChange[],\n address: string,\n): string {\n if (currentAction !== 'lending') return currentLabel;\n const labelMatchedSpecific = LABEL_PATTERNS.some(([p]) =>\n moveCallTargets.some((t) => p.test(t)),\n );\n if (labelMatchedSpecific) return currentLabel;\n\n const userNonSuiOutflow = changes.find(\n (c) => resolveOwner(c.owner) === address && c.coinType !== SUI_TYPE && BigInt(c.amount) < 0n,\n );\n if (userNonSuiOutflow) return 'deposit';\n\n const userNonSuiInflow = changes.find(\n (c) => resolveOwner(c.owner) === address && c.coinType !== SUI_TYPE && BigInt(c.amount) > 0n,\n );\n if (userNonSuiInflow) return 'withdraw';\n\n return currentLabel;\n}\n\nexport interface ClassifyResult {\n action: string;\n label: string;\n}\n\nexport function classifyTransaction(\n moveCallTargets: string[],\n commandTypes: string[],\n balanceChanges: ClassifyBalanceChange[],\n address: string,\n): ClassifyResult {\n const action = classifyAction(moveCallTargets, commandTypes);\n const baseLabel = classifyLabel(moveCallTargets, commandTypes);\n const label = refineLendingLabel(action, baseLabel, moveCallTargets, balanceChanges, address);\n return { action, label };\n}\n\n/**\n * Direction of the user's net non-gas movement for this transaction.\n *\n * - `'out'` — the user spent the asset (sends, deposits, repays,\n * swap-in, payment-link payouts).\n * - `'in'` — the user received the asset (withdraws, borrows,\n * swap-out, claims, deposits credited from another wallet).\n *\n * Used by the `TransactionHistoryCard` to choose the `+`/`−` sign and\n * color. Direction is computed from the actual on-chain balance change\n * — never from the textual label — so opaque action types (`'router'`,\n * `'cross_swap'`, …) still render the correct sign.\n */\nexport type TxDirection = 'in' | 'out';\n\nexport interface ExtractedTransfer {\n amount?: number;\n asset?: string;\n recipient?: string;\n direction?: TxDirection;\n}\n\n/**\n * Extracts the principal amount/asset/direction for a transaction\n * from its `balanceChanges`.\n *\n * Algorithm:\n * 1. Restrict to the user's *own* balance changes.\n * 2. Prefer non-SUI changes (gas-only SUI deltas are noise).\n * 3. Pick the change with the largest absolute value — the \"principal\".\n * 4. If no non-SUI change exists, fall back to the largest SUI change\n * so pure-SUI transfers (stake/unstake/native send) still render.\n * 5. Direction follows the sign of the principal.\n * 6. Recipient is set only on outflows, by finding a matching inflow\n * on a *non-user* address with the same coinType.\n *\n * Pre-v0.46.2 this function only inspected outflows, so withdraws,\n * borrows, claims, swap-receives and payment-link receives all\n * rendered with no amount on the rich card (and with a wrong sign,\n * because the card guessed direction from the label string).\n */\nexport function extractTransferDetails(\n changes: ClassifyBalanceChange[] | undefined,\n sender: string,\n): ExtractedTransfer {\n if (!changes || changes.length === 0) return {};\n\n const userChanges = changes.filter((c) => resolveOwner(c.owner) === sender);\n if (userChanges.length === 0) return {};\n\n const userNonSui = userChanges.filter((c) => c.coinType !== SUI_TYPE);\n const pool = userNonSui.length > 0 ? userNonSui : userChanges;\n\n let primary = pool[0];\n let primaryAbs = bigintAbs(BigInt(primary.amount));\n for (let i = 1; i < pool.length; i++) {\n const abs = bigintAbs(BigInt(pool[i].amount));\n if (abs > primaryAbs) {\n primary = pool[i];\n primaryAbs = abs;\n }\n }\n\n const raw = BigInt(primary.amount);\n if (raw === 0n) return {};\n\n const decimals = getDecimalsForCoinType(primary.coinType);\n const amount = Number(primaryAbs) / 10 ** decimals;\n const asset = resolveSymbol(primary.coinType);\n const direction: TxDirection = raw < 0n ? 'out' : 'in';\n\n let recipient: string | undefined;\n if (direction === 'out') {\n const recipientChange = changes.find(\n (c) =>\n resolveOwner(c.owner) !== sender &&\n c.coinType === primary.coinType &&\n BigInt(c.amount) > 0n,\n );\n recipient = recipientChange ? resolveOwner(recipientChange.owner) ?? undefined : undefined;\n }\n\n return { amount, asset, recipient, direction };\n}\n\nfunction bigintAbs(n: bigint): bigint {\n return n < 0n ? -n : n;\n}\n\n/**\n * Extract every non-zero user balance leg for a transaction — not\n * just the largest one. Order is RPC order; callers responsible for\n * any sorting (e.g. audric sorts by USD value once it's priced).\n *\n * Sui collapses balance changes by coin type, so a 3-step bundle\n * touching USDC three times surfaces as ONE leg of net USDC delta.\n * Distinguishing per-step legs would require parsing the PTB's\n * commands; this helper deliberately stops at the balance-change\n * granularity because that's what's reliably available across all\n * Sui RPC versions.\n *\n * Pre-v1.27.2 the only public API was `extractTransferDetails`,\n * which returned a single \"primary\" leg and made swap rows\n * unrenderable (showed `Swapped 987.60 MANIFEST` because MANIFEST\n * was the largest raw delta even though USDC was the value side).\n */\nexport function extractAllUserLegs(\n changes: ClassifyBalanceChange[] | undefined,\n sender: string,\n): import('../types.js').TransactionLeg[] {\n if (!changes || changes.length === 0) return [];\n\n const legs: import('../types.js').TransactionLeg[] = [];\n for (const c of changes) {\n if (resolveOwner(c.owner) !== sender) continue;\n const raw = BigInt(c.amount);\n if (raw === 0n) continue;\n const decimals = getDecimalsForCoinType(c.coinType);\n const absAmount = bigintAbs(raw);\n legs.push({\n coinType: c.coinType,\n asset: resolveSymbol(c.coinType),\n decimals,\n amount: Number(absAmount) / 10 ** decimals,\n rawAmount: raw.toString(),\n direction: raw < 0n ? 'out' : 'in',\n });\n }\n\n return legs;\n}\n","import type { SuiJsonRpcClient } from '@mysten/sui/jsonRpc';\nimport type { TransactionRecord } from '../types.js';\nimport {\n classifyTransaction,\n extractAllUserLegs,\n extractTransferDetails,\n type ClassifyBalanceChange,\n} from './classify.js';\n\nexport async function queryHistory(\n client: SuiJsonRpcClient,\n address: string,\n limit = 20,\n): Promise<TransactionRecord[]> {\n const txns = await client.queryTransactionBlocks({\n filter: { FromAddress: address },\n options: { showEffects: true, showInput: true, showBalanceChanges: true },\n limit,\n order: 'descending',\n });\n\n return txns.data.map((tx) => parseTxRecord(tx as unknown as SuiRpcTxBlock, address));\n}\n\nexport async function queryTransaction(\n client: SuiJsonRpcClient,\n digest: string,\n senderAddress: string,\n): Promise<TransactionRecord | null> {\n try {\n const tx = await client.getTransactionBlock({\n digest,\n options: { showEffects: true, showInput: true, showBalanceChanges: true },\n });\n return parseTxRecord(tx as unknown as SuiRpcTxBlock, senderAddress);\n } catch {\n return null;\n }\n}\n\n/**\n * Shape of a transaction block as returned by `suix_queryTransactionBlocks`\n * with `showEffects | showInput | showBalanceChanges` enabled. Exported so\n * downstream consumers (audric dashboard `/api/history`, `/api/activity`,\n * etc.) can type their RPC calls without redeclaring the structure.\n */\nexport interface SuiRpcTxBlock {\n digest: string;\n timestampMs?: string;\n transaction?: unknown;\n effects?: { gasUsed?: { computationCost: string; storageCost: string; storageRebate: string } };\n balanceChanges?: ClassifyBalanceChange[];\n}\n\n/**\n * Convert a single Sui RPC transaction block to a {@link TransactionRecord}\n * using the canonical (shared) classifier and balance-change extractor.\n *\n * This is the single source of truth for transaction parsing across the\n * agent-tool path AND the dashboard-API path. Use it instead of writing\n * a bespoke parser per surface.\n *\n * @param tx Raw RPC tx block (must include `effects`, `input`, `balanceChanges`).\n * @param address Wallet address whose perspective we're parsing from.\n */\nexport function parseSuiRpcTx(tx: SuiRpcTxBlock, address: string): TransactionRecord {\n return parseTxRecord(tx, address);\n}\n\n/**\n * Extract the sender (signer) address from a raw RPC tx block.\n * Returns `null` if the block shape is unexpected.\n */\nexport function extractTxSender(txBlock: unknown): string | null {\n try {\n if (!txBlock || typeof txBlock !== 'object') return null;\n const data = 'data' in txBlock ? (txBlock as Record<string, unknown>).data : undefined;\n if (!data || typeof data !== 'object') return null;\n return ((data as Record<string, unknown>).sender as string) ?? null;\n } catch {\n return null;\n }\n}\n\n/**\n * Extract MoveCall targets (`<pkg>::<module>::<function>`) and the\n * sequence of programmable-transaction command types (e.g. `MoveCall`,\n * `TransferObjects`) from a raw RPC tx block. Tolerates both the\n * legacy `inner.transactions` field and the newer `inner.commands`\n * field.\n */\nexport function extractTxCommands(txBlock: unknown): {\n moveCallTargets: string[];\n commandTypes: string[];\n} {\n return extractCommands(txBlock);\n}\n\nfunction parseTxRecord(tx: SuiRpcTxBlock, address: string): TransactionRecord {\n const gasUsed = tx.effects?.gasUsed;\n const gasCost = gasUsed\n ? (Number(gasUsed.computationCost) +\n Number(gasUsed.storageCost) -\n Number(gasUsed.storageRebate)) /\n 1e9\n : undefined;\n\n const { moveCallTargets, commandTypes } = extractCommands(tx.transaction);\n const balanceChanges = tx.balanceChanges ?? [];\n const legs = extractAllUserLegs(balanceChanges, address);\n const { amount, asset, recipient, direction } = extractTransferDetails(balanceChanges, address);\n const { action, label } = classifyTransaction(\n moveCallTargets,\n commandTypes,\n balanceChanges,\n address,\n );\n\n return {\n digest: tx.digest,\n action,\n label,\n legs,\n amount,\n asset,\n recipient,\n direction,\n timestamp: Number(tx.timestampMs ?? 0),\n gasCost,\n };\n}\n\ninterface CommandInfo {\n moveCallTargets: string[];\n commandTypes: string[];\n}\n\nfunction extractCommands(txBlock: unknown): CommandInfo {\n const result: CommandInfo = { moveCallTargets: [], commandTypes: [] };\n try {\n if (!txBlock || typeof txBlock !== 'object') return result;\n const data = 'data' in txBlock ? (txBlock as Record<string, unknown>).data : undefined;\n if (!data || typeof data !== 'object') return result;\n const inner = 'transaction' in (data as Record<string, unknown>)\n ? (data as Record<string, unknown>).transaction\n : undefined;\n if (!inner || typeof inner !== 'object') return result;\n const commands = 'commands' in (inner as Record<string, unknown>)\n ? (inner as Record<string, unknown>).commands\n : 'transactions' in (inner as Record<string, unknown>)\n ? (inner as Record<string, unknown>).transactions\n : undefined;\n if (!Array.isArray(commands)) return result;\n\n for (const cmd of commands as Record<string, unknown>[]) {\n if (cmd.MoveCall) {\n const mc = cmd.MoveCall as { package: string; module: string; function: string };\n result.moveCallTargets.push(`${mc.package}::${mc.module}::${mc.function}`);\n result.commandTypes.push('MoveCall');\n } else if (cmd.TransferObjects) {\n result.commandTypes.push('TransferObjects');\n }\n }\n } catch { /* best effort */ }\n return result;\n}\n","import { MIST_PER_SUI, BPS_DENOMINATOR, USDC_DECIMALS, SUPPORTED_ASSETS } from '../constants.js';\nimport type { SupportedAsset } from '../constants.js';\n\nexport function mistToSui(mist: bigint): number {\n return Number(mist) / Number(MIST_PER_SUI);\n}\n\nexport function suiToMist(sui: number): bigint {\n return BigInt(Math.round(sui * Number(MIST_PER_SUI)));\n}\n\nexport function usdcToRaw(amount: number): bigint {\n return BigInt(Math.round(amount * 10 ** USDC_DECIMALS));\n}\n\nexport function rawToUsdc(raw: bigint): number {\n return Number(raw) / 10 ** USDC_DECIMALS;\n}\n\nexport function stableToRaw(amount: number, decimals: number): bigint {\n return BigInt(Math.round(amount * 10 ** decimals));\n}\n\nexport function rawToStable(raw: bigint, decimals: number): number {\n return Number(raw) / 10 ** decimals;\n}\n\nexport function getDecimals(asset: SupportedAsset): number {\n return SUPPORTED_ASSETS[asset].decimals;\n}\n\nexport function rawToDisplay(raw: bigint, decimals: number): number {\n return Number(raw) / 10 ** decimals;\n}\n\nexport function displayToRaw(amount: number, decimals: number): bigint {\n return BigInt(Math.round(amount * 10 ** decimals));\n}\n\nexport function bpsToPercent(bps: bigint): number {\n return Number(bps) / Number(BPS_DENOMINATOR) * 100;\n}\n\nexport function formatUsd(amount: number): string {\n return `$${amount.toFixed(2)}`;\n}\n\nexport function formatSui(amount: number): string {\n if (amount < 0.001) return `${amount.toFixed(6)} SUI`;\n return `${amount.toFixed(3)} SUI`;\n}\n\nexport function formatLargeNumber(n: number): string {\n if (n >= 1_000_000) return `${(n / 1_000_000).toFixed(1)}M`;\n if (n >= 1_000) return `${(n / 1_000).toFixed(1)}K`;\n return n.toFixed(2);\n}\n\nexport function formatAssetAmount(amount: number, asset: string): string {\n if (asset === 'BTC') return amount.toFixed(8);\n if (asset === 'GOLD') return amount.toFixed(6);\n if (asset === 'ETH') return amount.toFixed(6);\n return amount.toFixed(4);\n}\n\nconst ASSET_LOOKUP: Map<string, string> = new Map();\nfor (const [key, info] of Object.entries(SUPPORTED_ASSETS)) {\n ASSET_LOOKUP.set(key.toUpperCase(), key);\n if (info.displayName && info.displayName.toUpperCase() !== key.toUpperCase()) {\n ASSET_LOOKUP.set(info.displayName.toUpperCase(), key);\n }\n}\n\n/**\n * Case-insensitive lookup against SUPPORTED_ASSETS keys AND display names.\n * 'usde' → 'USDe', 'suiusde' → 'USDe', 'suiusdt' → 'USDT', 'usdsui' → 'USDsui'.\n * Returns the original input if not found so downstream validation can reject it.\n */\nexport function normalizeAsset(input: string): string {\n return ASSET_LOOKUP.get(input.toUpperCase()) ?? input;\n}\n","/** Cross-platform (Node + browser) base64 helpers. */\n\nexport function toBase64(bytes: Uint8Array): string {\n let binary = '';\n for (const byte of bytes) binary += String.fromCharCode(byte);\n return btoa(binary);\n}\n\nexport function fromBase64(b64: string): Uint8Array {\n const binary = atob(b64);\n const bytes = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);\n return bytes;\n}\n","/**\n * Protocol fee primitives — wallet-direct transfer model.\n *\n * Fees are collected by splitting from the payment coin and transferring directly\n * to the treasury wallet inside the same PTB. Atomic with the operation (PTB\n * semantics); the wallet IS the ledger; the server-side indexer reads\n * `balanceChanges` and writes a `ProtocolFeeLedger` row tagged with the operation\n * classified from the tx's moveCall targets.\n *\n * The SDK / CLI never call this helper — they're fee-free by design (t2000 = infra\n * brand, no opinion on fees). Audric's `prepare/route.ts` is the canonical caller.\n */\nimport { Transaction, type TransactionObjectArgument } from '@mysten/sui/transactions';\nimport {\n SAVE_FEE_BPS,\n BORROW_FEE_BPS,\n BPS_DENOMINATOR,\n USDC_DECIMALS,\n} from '../constants.js';\nimport { stableToRaw } from '../utils/format.js';\n\nexport type FeeOperation = 'save' | 'borrow' | 'swap';\n\nexport interface ProtocolFeeInfo {\n amount: number;\n asset: string;\n rate: number;\n rawAmount: bigint;\n}\n\nconst FEE_RATES: Record<FeeOperation, bigint> = {\n save: SAVE_FEE_BPS,\n borrow: BORROW_FEE_BPS,\n // Swap uses Cetus's overlay-fee mechanism (taken from output by the aggregator\n // and transferred to `overlayFee.receiver`). We list the rate here for display\n // / quote calculations only — `addFeeTransfer` is NOT called for swaps.\n swap: 10n, // 0.1%\n};\n\n/**\n * Compute the fee amount for a given operation against a USD-denominated input.\n * Used pre-tx for receipt display + quote math. Does not modify any tx.\n */\nexport function calculateFee(operation: FeeOperation, amount: number): ProtocolFeeInfo {\n const bps = FEE_RATES[operation];\n const feeAmount = amount * Number(bps) / Number(BPS_DENOMINATOR);\n const rawAmount = stableToRaw(feeAmount, USDC_DECIMALS);\n\n return {\n amount: feeAmount,\n asset: 'USDC',\n rate: Number(bps) / Number(BPS_DENOMINATOR),\n rawAmount,\n };\n}\n\n/**\n * Split a fee from `paymentCoin` and transfer it to `receiver` inside the given PTB.\n *\n * **Order is load-bearing.** Call this BEFORE the protocol operation that consumes\n * `paymentCoin` (e.g. NAVI deposit). `splitCoins` mutates the source coin in place,\n * leaving the remainder for the protocol step. If you split AFTER the deposit,\n * the deposit will have consumed the coin and the split will fail.\n *\n * Atomicity: `splitCoins` + `transferObjects` are PTB ops; if anything later in\n * the PTB reverts, the fee transfer reverts too.\n *\n * @param tx Active PTB\n * @param paymentCoin Coin to split the fee from (mutated in place)\n * @param feeBps Fee rate in basis points (e.g. `SAVE_FEE_BPS = 10n` = 0.1%)\n * @param receiver Treasury wallet address (typically `T2000_OVERLAY_FEE_WALLET`)\n * @param amount Display-units input amount (matches what was passed to the\n * protocol operation; used to compute the raw fee amount)\n * @param decimals Coin decimals for raw conversion. Defaults to USDC_DECIMALS\n * (6). Pass the actual coin decimals when skimming a fee\n * from a non-USDC coin (e.g. USDsui = 6, GOLD = 6, ETH = 8,\n * SUI = 9). Backward-compatible: existing USDC callers can\n * omit. Wrong decimals → wrong raw amount → either fee\n * too small (silent loss) or too large (PTB revert from\n * insufficient coin balance).\n */\nexport function addFeeTransfer(\n tx: Transaction,\n paymentCoin: TransactionObjectArgument,\n feeBps: bigint,\n receiver: string,\n amount: number,\n decimals: number = USDC_DECIMALS,\n): void {\n if (feeBps <= 0n) return;\n if (amount <= 0) return;\n\n const feeAmount = amount * Number(feeBps) / Number(BPS_DENOMINATOR);\n const rawFee = stableToRaw(feeAmount, decimals);\n if (rawFee <= 0n) return;\n\n const [feeCoin] = tx.splitCoins(paymentCoin, [tx.pure.u64(rawFee)]);\n tx.transferObjects([feeCoin], tx.pure.address(receiver));\n}\n","/**\n * Cetus Aggregator V3 SDK wrapper — the ONLY file that imports @cetusprotocol/aggregator-sdk.\n * Documented CLAUDE.md exception: multi-DEX routing cannot be feasibly replaced by thin tx builders.\n *\n * [B5 v2 / @t2000/sdk@1.1.0 / 2026-04-30]\n * Overlay fee config is now per-call instead of a module-level singleton. CLI / direct\n * SDK callers (`T2000.swap()`) DON'T pass `overlayFee` → fee-free swap. Audric's\n * prepare/route.ts ALWAYS passes `overlayFee = { rate: OVERLAY_FEE_RATE, receiver:\n * T2000_OVERLAY_FEE_WALLET }` → fee charged. Structural inclusion (Audric's code can't\n * forget to pass it because it IS the code), not a toggle that defaults to safe.\n *\n * Pre-1.1.0: a module-level `OVERLAY_FEE_RECEIVER` constant defaulted to a Move object\n * ID. USDC sent there became OwnedObjects keyed to the object and was inaccessible.\n * Fixed by making the receiver a regular wallet address (T2000_OVERLAY_FEE_WALLET) AND\n * by removing the singleton pattern that hid the misconfig.\n */\nimport { AggregatorClient, Env, type FindRouterParams, type RouterDataV3 } from '@cetusprotocol/aggregator-sdk';\nimport { Transaction, type TransactionObjectArgument } from '@mysten/sui/transactions';\nimport type { SuiJsonRpcClient } from '@mysten/sui/jsonRpc';\nimport BN from 'bn.js';\nimport { resolveTokenType, getDecimalsForCoinType } from '../token-registry.js';\n\nexport interface OverlayFeeConfig {\n /** Fee rate as a fraction (e.g. 0.001 = 0.1%). Pass 0 to disable. */\n rate: number;\n /** Wallet address that receives the overlay fee. */\n receiver: string;\n}\n\nexport interface SwapRouteResult {\n routerData: RouterDataV3;\n amountIn: string;\n amountOut: string;\n byAmountIn: boolean;\n priceImpact: number;\n insufficientLiquidity: boolean;\n}\n\n// [SPEC 20.2 / D-1 (a)] Typed JSON-friendly representation of a Cetus\n// `RouterDataV3` for cross-process / cross-network transport. The native\n// shape contains `BN` instances (`bn.js`) and a `Map<string, string>`\n// (`packages`) that don't survive JSON.stringify / JSON.parse cleanly:\n// - `BN.toJSON()` returns the internal `{negative,words,length,red}` blob\n// - `Map.toJSON()` returns `{}`\n// Round-tripping via `serializeCetusRoute` + `deserializeCetusRoute`\n// converts BN ↔ decimal string and Map ↔ Record. Engine + audric both\n// reference fields by path (`route.routerData.paths[i].provider`) without\n// needing to know about the underlying BN/Map types.\nexport interface SerializedCetusRoutePath {\n id: string;\n direction: boolean;\n provider: string;\n from: string;\n target: string;\n feeRate: number;\n amountIn: string;\n amountOut: string;\n version?: string;\n publishedAt?: string;\n extendedDetails?: Record<string, unknown>;\n}\n\nexport interface SerializedRouterDataV3 {\n quoteID?: string;\n /** RouterDataV3.amountIn (BN) → decimal string */\n amountIn: string;\n /** RouterDataV3.amountOut (BN) → decimal string */\n amountOut: string;\n byAmountIn: boolean;\n paths: SerializedCetusRoutePath[];\n insufficientLiquidity: boolean;\n deviationRatio: number;\n /** RouterDataV3.packages (Map) → Record */\n packages?: Record<string, string>;\n totalDeepFee?: number;\n error?: { code: number; msg: string };\n overlayFee?: number;\n}\n\nexport interface SerializedCetusRoute {\n routerData: SerializedRouterDataV3;\n amountIn: string;\n amountOut: string;\n byAmountIn: boolean;\n priceImpact: number;\n insufficientLiquidity: boolean;\n /**\n * Wall-clock timestamp (ms since epoch) at which the route was discovered.\n * Used by audric's prepare-route for SPEC 20.2 D-3 TTL re-validation: if\n * the route is older than the threshold AND price impact has shifted\n * beyond tolerance, fall back to a fresh `findSwapRoute()` call.\n */\n discoveredAt: number;\n /**\n * Snapshot of the input/output coin types the route was discovered for.\n * SPEC 20.2 D-2 (b) structural verification: prepare-route asserts\n * input/output coins match before using the fast-path; mismatch falls\n * back to fresh discovery (defense against client-side tampering and\n * against legitimate token-type drift in the request).\n */\n fromCoinType: string;\n toCoinType: string;\n}\n\nexport function serializeCetusRoute(\n route: SwapRouteResult,\n context: { fromCoinType: string; toCoinType: string },\n): SerializedCetusRoute {\n return {\n routerData: serializeRouterDataV3(route.routerData),\n amountIn: route.amountIn,\n amountOut: route.amountOut,\n byAmountIn: route.byAmountIn,\n priceImpact: route.priceImpact,\n insufficientLiquidity: route.insufficientLiquidity,\n discoveredAt: Date.now(),\n fromCoinType: context.fromCoinType,\n toCoinType: context.toCoinType,\n };\n}\n\nexport function deserializeCetusRoute(serialized: SerializedCetusRoute): SwapRouteResult {\n return {\n routerData: deserializeRouterDataV3(serialized.routerData),\n amountIn: serialized.amountIn,\n amountOut: serialized.amountOut,\n byAmountIn: serialized.byAmountIn,\n priceImpact: serialized.priceImpact,\n insufficientLiquidity: serialized.insufficientLiquidity,\n };\n}\n\nfunction serializeRouterDataV3(rd: RouterDataV3): SerializedRouterDataV3 {\n const out: SerializedRouterDataV3 = {\n amountIn: rd.amountIn.toString(),\n amountOut: rd.amountOut.toString(),\n byAmountIn: rd.byAmountIn,\n paths: rd.paths.map(serializeCetusRoutePath),\n insufficientLiquidity: rd.insufficientLiquidity,\n deviationRatio: rd.deviationRatio,\n };\n if (rd.quoteID !== undefined) out.quoteID = rd.quoteID;\n if (rd.packages) {\n const obj: Record<string, string> = {};\n for (const [k, v] of rd.packages) obj[k] = v;\n out.packages = obj;\n }\n if (rd.totalDeepFee !== undefined) out.totalDeepFee = rd.totalDeepFee;\n if (rd.error) out.error = { code: rd.error.code, msg: rd.error.msg };\n if (rd.overlayFee !== undefined) out.overlayFee = rd.overlayFee;\n return out;\n}\n\nfunction deserializeRouterDataV3(s: SerializedRouterDataV3): RouterDataV3 {\n const out: RouterDataV3 = {\n amountIn: new BN(s.amountIn),\n amountOut: new BN(s.amountOut),\n byAmountIn: s.byAmountIn,\n paths: s.paths.map(deserializeCetusRoutePath),\n insufficientLiquidity: s.insufficientLiquidity,\n deviationRatio: s.deviationRatio,\n };\n if (s.quoteID !== undefined) out.quoteID = s.quoteID;\n if (s.packages) out.packages = new Map(Object.entries(s.packages));\n if (s.totalDeepFee !== undefined) out.totalDeepFee = s.totalDeepFee;\n if (s.error) out.error = { code: s.error.code, msg: s.error.msg };\n if (s.overlayFee !== undefined) out.overlayFee = s.overlayFee;\n return out;\n}\n\nfunction serializeCetusRoutePath(p: RouterDataV3['paths'][number]): SerializedCetusRoutePath {\n const out: SerializedCetusRoutePath = {\n id: p.id,\n direction: p.direction,\n provider: p.provider,\n from: p.from,\n target: p.target,\n feeRate: p.feeRate,\n amountIn: p.amountIn,\n amountOut: p.amountOut,\n };\n if (p.version !== undefined) out.version = p.version;\n if (p.publishedAt !== undefined) out.publishedAt = p.publishedAt;\n if (p.extendedDetails) out.extendedDetails = { ...p.extendedDetails };\n return out;\n}\n\nfunction deserializeCetusRoutePath(p: SerializedCetusRoutePath): RouterDataV3['paths'][number] {\n const out: RouterDataV3['paths'][number] = {\n id: p.id,\n direction: p.direction,\n provider: p.provider,\n from: p.from,\n target: p.target,\n feeRate: p.feeRate,\n amountIn: p.amountIn,\n amountOut: p.amountOut,\n };\n if (p.version !== undefined) out.version = p.version;\n if (p.publishedAt !== undefined) out.publishedAt = p.publishedAt;\n if (p.extendedDetails) out.extendedDetails = { ...p.extendedDetails };\n return out;\n}\n\n/**\n * SPEC 20.2 D-2 (b) structural verification helper. Returns true when the\n * serialized route matches the requested coin types (i.e. it's safe to use\n * as the prepare-route fast-path), false otherwise (tampered, or input\n * mismatch from a legitimate but stale pending action). Caller falls back\n * to a fresh `findSwapRoute()` call when verification fails.\n */\nexport function verifyCetusRouteCoinMatch(\n serialized: SerializedCetusRoute,\n expected: { fromCoinType: string; toCoinType: string },\n): boolean {\n return serialized.fromCoinType === expected.fromCoinType && serialized.toCoinType === expected.toCoinType;\n}\n\n/**\n * SPEC 20.2 D-3 (b) TTL helper. Returns true when the serialized route is\n * fresh enough to use as the fast-path (< `maxAgeMs` old). Returns false\n * for stale routes — caller falls back to fresh `findSwapRoute()` to pick\n * up any pool-price drift since route discovery.\n *\n * Default 30s aligns with the existing quote-freshness contract surfaced\n * to users via `pending_action.quoteAge` (the PermissionCard \"QUOTE Ns OLD\"\n * badge starts warning the user past 30s).\n */\nexport function isCetusRouteFresh(serialized: SerializedCetusRoute, maxAgeMs: number = 30_000): boolean {\n return Date.now() - serialized.discoveredAt < maxAgeMs;\n}\n\n/**\n * Default Audric swap overlay fee — 0.1%. Exported for consumers that want to use\n * the canonical Audric rate (the Audric prepare-route does this). Changing this\n * rate requires a coordinated SDK + audric release.\n */\nexport const OVERLAY_FEE_RATE = 0.001;\n\n/**\n * Cache `AggregatorClient` instances by `(signer + overlay rate + overlay receiver)`.\n * Per-call instantiation is cheap (the client is mostly config), but caching avoids\n * pointless re-allocation when the same caller swaps multiple times in a loop.\n */\nconst clientCache = new Map<string, AggregatorClient>();\n\nfunction getClient(walletAddress: string, overlayFee?: OverlayFeeConfig): AggregatorClient {\n const rate = overlayFee?.rate ?? 0;\n const receiver = overlayFee?.receiver ?? '';\n const key = `${walletAddress}|${rate}|${receiver}`;\n\n const cached = clientCache.get(key);\n if (cached) return cached;\n\n const client = new AggregatorClient({\n signer: walletAddress,\n env: Env.Mainnet,\n ...(rate > 0 && receiver\n ? { overlayFeeRate: rate, overlayFeeReceiver: receiver }\n : {}),\n });\n clientCache.set(key, client);\n return client;\n}\n\n/**\n * [Bug A defense-in-depth / 2026-05-10] Returns true when every path\n * provider in `route.routerData.paths` is present in the active\n * `providers` allow-list. Cetus's `getProvidersExcluding(...)` returns\n * an inclusion list (the complement of the exclusion), so when a caller\n * passes `providers`, every walked provider must be IN that list to be\n * compatible.\n *\n * When `providers` is undefined (non-sponsored caller, e.g. CLI) every\n * route is compatible — same semantics as `findSwapRoute` itself.\n *\n * Why per-path: a Cetus aggregator route can split across multiple DEXes\n * (e.g. 60% Cetus + 40% Bluefin). A single excluded provider in any path\n * triggers `tx.gas` usage in `routerSwap`. Reject the whole route if any\n * leg is excluded.\n */\nexport function isPrecomputedRouteCompatibleWithProviders(\n route: SwapRouteResult,\n providers: string[] | undefined,\n): boolean {\n if (!providers || providers.length === 0) return true;\n const allowed = new Set(providers);\n for (const path of route.routerData.paths) {\n if (!allowed.has(path.provider)) return false;\n }\n return true;\n}\n\n/**\n * Find the optimal swap route via Cetus Aggregator REST API.\n *\n * Pass `overlayFee` to charge an overlay fee on the output (Audric's pattern).\n * Omit it for a fee-free swap (CLI / direct SDK pattern).\n */\nexport async function findSwapRoute(params: {\n walletAddress: string;\n from: string;\n to: string;\n amount: bigint;\n byAmountIn: boolean;\n overlayFee?: OverlayFeeConfig;\n /**\n * Optional Cetus provider allow-list. When omitted, all 30+ DEXes\n * are eligible. Sponsored flows (Enoki) MUST pass an exclusion list\n * computed via `getProvidersExcluding([...])` from the Cetus SDK to\n * remove Pyth-dependent providers (HAEDALPMM, METASTABLE, OBRIC,\n * STEAMM_OMM, STEAMM_OMM_V2, SEVENK, HAEDALHMMV2) — those reference\n * `tx.gas` for oracle fees, which Enoki rejects in sponsored txs.\n * Non-sponsored callers (CLI, direct SDK) leave this undefined.\n */\n providers?: string[];\n}): Promise<SwapRouteResult | null> {\n const client = getClient(params.walletAddress, params.overlayFee);\n\n const findParams: FindRouterParams = {\n from: params.from,\n target: params.to,\n amount: params.amount.toString(),\n byAmountIn: params.byAmountIn,\n ...(params.providers ? { providers: params.providers } : {}),\n };\n\n const routerData = await client.findRouters(findParams);\n if (!routerData) return null;\n\n if (routerData.insufficientLiquidity) {\n return {\n routerData,\n amountIn: routerData.amountIn.toString(),\n amountOut: routerData.amountOut.toString(),\n byAmountIn: params.byAmountIn,\n priceImpact: normalizePriceImpact(routerData.deviationRatio),\n insufficientLiquidity: true,\n };\n }\n\n if (routerData.error) {\n const { T2000Error } = await import('../errors.js');\n throw new T2000Error('SWAP_FAILED', `Cetus routing error: ${routerData.error.msg} (code ${routerData.error.code})`);\n }\n\n return {\n routerData,\n amountIn: routerData.amountIn.toString(),\n amountOut: routerData.amountOut.toString(),\n byAmountIn: params.byAmountIn,\n priceImpact: normalizePriceImpact(routerData.deviationRatio),\n insufficientLiquidity: false,\n };\n}\n\n/**\n * Cetus' aggregator types `deviationRatio` as `number`, but in some routes\n * the router actually returns a string (\"0.001234\"). The SDK type lies, so we\n * always coerce to a finite number here (NaN/null/undefined → 0). Without\n * this every downstream consumer that calls `priceImpact.toFixed(...)` will\n * crash at runtime — including the Audric SwapQuoteCard, which takes the\n * whole chat UI down through its error boundary.\n */\nfunction normalizePriceImpact(value: unknown): number {\n const n = typeof value === 'number' ? value : Number(value);\n return Number.isFinite(n) ? n : 0;\n}\n\n/**\n * Build a swap PTB from a route result. The caller must provide an input coin\n * obtained by splitting/merging wallet coins.\n *\n * **Important:** Cetus's `routerSwap` reads the overlay-fee config from the\n * AggregatorClient instance. The `overlayFee` param here MUST match the one\n * passed to `findSwapRoute` for the same swap (otherwise you'll hit the cache\n * boundary and get a different client with different overlay config).\n */\nexport async function buildSwapTx(params: {\n walletAddress: string;\n route: SwapRouteResult;\n tx: Transaction;\n inputCoin: TransactionObjectArgument;\n slippage: number;\n overlayFee?: OverlayFeeConfig;\n}): Promise<TransactionObjectArgument> {\n const client = getClient(params.walletAddress, params.overlayFee);\n const clampedSlippage = Math.max(0.001, Math.min(params.slippage, 0.05));\n\n const outputCoin = await client.routerSwap({\n router: params.route.routerData,\n inputCoin: params.inputCoin,\n slippage: clampedSlippage,\n txb: params.tx,\n });\n\n return outputCoin;\n}\n\n/**\n * Append a swap fragment to an existing PTB. SPEC 7 § \"Layer 1\" Cetus\n * appender. Two modes, dispatched by the presence of `input.inputCoin`:\n *\n * - **Wallet mode** (`inputCoin` omitted) — sources `from`-asset funds\n * via `coinWithBalance({ type, balance })` (resolves coin objects +\n * address balance at build time), runs the swap. Mirrors the audric\n * host's `transactions/prepare/route.ts` swap branch (P2.2c will\n * retire that branch in favor of this appender via `composeTx`).\n *\n * - **Chain mode** (`inputCoin` provided) — consumes the passed-in coin\n * reference (typically produced by an upstream appender like\n * `addWithdrawToTx`) directly, no wallet fetch / no merge / no\n * split. This is the SPEC 7 multi-write enabler (\"withdraw → swap →\n * save\" without intermediate wallet materialization).\n *\n * **SUI in wallet mode:** ALWAYS sources through `selectSuiCoin` (which\n * routes via `coinWithBalance({ type: SUI, useGasCoin: false })` under\n * sponsored flows, OR `tx.splitCoins(tx.gas, ...)` under self-funded\n * flows). The caller MUST set `sponsoredContext` correctly — otherwise\n * sponsored swaps with SUI source fail with `Cannot use GasCoin as a\n * transaction argument` (Enoki owns `tx.gas`, the PTB body referencing\n * it as an argument is invalid for sponsorship). 2.14.0 shipped without\n * this branch and broke audric/web-v2 SUI→USDC swaps; restored in 2.14.1\n * (S.260). For non-sponsored flows (CLI), `T2000.swap()` pre-builds the\n * inputCoin via `tx.splitCoins(tx.gas, [rawAmount])[0]` and uses chain\n * mode, sidestepping wallet-mode entirely — this branch is a defensive\n * safety net for future direct SDK users who pass SUI in wallet mode.\n *\n * **`swapAll` semantics (wallet mode):** if the requested raw amount\n * is >= the wallet's total `from` balance, the appender consumes the\n * entire merged primary coin (not a split), matching audric's host\n * route's `swapAll` clipping. The returned `effectiveAmountIn` reflects\n * the actual consumed amount in display units.\n *\n * **Slippage:** clamped to [0.001, 0.05] (0.1% – 5%). Defaults to 0.01.\n *\n * @returns\n * - `coin` — output coin reference, ready for downstream consumption\n * (e.g. `addSaveToTx`) or wallet transfer (`tx.transferObjects`).\n * - `effectiveAmountIn` — display-units input amount the swap actually\n * consumes (handles `swapAll` clipping in wallet mode; in chain mode\n * echoes the requested `input.amount`).\n * - `expectedAmountOut` — display-units output amount per the route\n * quote. Actual on-chain output may differ within slippage.\n * - `route` — raw `SwapRouteResult` for downstream telemetry / logging.\n */\nexport async function addSwapToTx(\n tx: Transaction,\n client: SuiJsonRpcClient,\n address: string,\n input: {\n from: string;\n to: string;\n amount: number;\n slippage?: number;\n byAmountIn?: boolean;\n overlayFee?: OverlayFeeConfig;\n inputCoin?: TransactionObjectArgument;\n /**\n * Optional Cetus provider allow-list. Forwarded to `findSwapRoute`.\n * Sponsored flows (Enoki) MUST pass `getProvidersExcluding([...])`\n * to remove Pyth-dependent providers — see `findSwapRoute`'s JSDoc\n * for the exclusion list. Non-sponsored callers omit this.\n */\n providers?: string[];\n /**\n * [SPEC 20.2 D-3 (b)] Precomputed route from a prior `findSwapRoute()`\n * call (typically captured by `swap_quote` and threaded through\n * `pending_action.cetusRoute`). When present AND not stale (per\n * `isCetusRouteFresh`) AND the input/output coins match, this skips\n * the ~400-500ms `findSwapRoute()` discovery call. Stale routes are\n * silently ignored (caller falls back to fresh discovery).\n *\n * Caller responsibility: pass the SAME `overlayFee` / `providers` /\n * `byAmountIn` that produced the precomputed route. Mismatch will\n * still produce a working swap but may use the wrong overlay-fee\n * config (the route data already encodes the chosen DEX path).\n */\n precomputedRoute?: SwapRouteResult;\n /**\n * Whether this swap is being built inside a sponsored-tx flow (Enoki)\n * vs self-funded (CLI / direct sign). Load-bearing for SUI-source\n * swaps in wallet mode: under sponsored flows, `tx.gas` belongs to\n * the sponsor and CANNOT be referenced as a transaction argument\n * (Sui protocol rejects with `Cannot use GasCoin as a transaction\n * argument`). When `true`, SUI source routes through `selectSuiCoin`\n * with `useGasCoin: false` so the resolver sources from the user's\n * SUI coin objects + address balance instead. Defaults to `false`\n * (back-compat — pre-2.14.1 behavior). Audric/web-v2's compose path\n * threads this through via `composeTx({ sponsoredContext: true })`.\n */\n sponsoredContext?: boolean;\n },\n): Promise<{\n coin: TransactionObjectArgument;\n effectiveAmountIn: number;\n expectedAmountOut: number;\n route: SwapRouteResult;\n /** True when `precomputedRoute` was used (no `findSwapRoute()` call). */\n usedPrecomputedRoute: boolean;\n}> {\n const { T2000Error } = await import('../errors.js');\n\n const fromType = resolveTokenType(input.from);\n const toType = resolveTokenType(input.to);\n if (!fromType) throw new T2000Error('ASSET_NOT_SUPPORTED', `Unknown token: ${input.from}. Provide the symbol (USDC, SUI, ...) or full coin type.`);\n if (!toType) throw new T2000Error('ASSET_NOT_SUPPORTED', `Unknown token: ${input.to}. Provide the symbol (USDC, SUI, ...) or full coin type.`);\n if (fromType === toType) throw new T2000Error('SWAP_FAILED', 'Cannot swap a token to itself');\n if (!Number.isFinite(input.amount) || input.amount <= 0) {\n throw new T2000Error('INVALID_AMOUNT', 'Amount must be greater than zero');\n }\n\n const fromDecimals = getDecimalsForCoinType(fromType);\n const toDecimals = getDecimalsForCoinType(toType);\n const requestedRaw = BigInt(Math.floor(input.amount * 10 ** fromDecimals));\n\n const slippage = Math.max(0.001, Math.min(input.slippage ?? 0.01, 0.05));\n const byAmountIn = input.byAmountIn ?? true;\n\n let inputCoin: TransactionObjectArgument;\n let effectiveRaw: bigint;\n\n if (input.inputCoin) {\n inputCoin = input.inputCoin;\n effectiveRaw = requestedRaw;\n } else if (fromType === '0x2::sui::SUI') {\n // SUI source needs special handling: under sponsored flows (Enoki),\n // referencing `tx.gas` as a transaction argument is forbidden (sponsor\n // owns the gas coin). `selectSuiCoin` does the right thing for both\n // sponsored (uses `coinWithBalance({ useGasCoin: false })`) and\n // self-funded (splits from `tx.gas` directly). The 2.14.0 release\n // shipped without this branch and broke audric/web-v2 SUI→USDC swaps\n // (\"Cannot use GasCoin as a transaction argument\" from Enoki); fixed\n // in 2.14.1 (S.260).\n const { selectSuiCoin } = await import('../wallet/coinSelection.js');\n const result = await selectSuiCoin(\n tx,\n client,\n address,\n requestedRaw,\n input.sponsoredContext ?? false,\n );\n inputCoin = result.coin;\n effectiveRaw = result.effectiveAmount;\n } else {\n // Non-SUI wallet-mode source — delegate to the canonical prelude.\n // Pre-flights against `getBalance().totalBalance` (coins + address\n // balance) and returns a `coinWithBalance({ type, balance })` arg.\n // Multi-write bundles that consume the same input asset across legs\n // (swap+save, swap+send) get correct merge/split dedup automatically\n // because the `@mysten/sui` resolver batches all `coinWithBalance`\n // intents for a given coin type into a single merge at `tx.build()`\n // time. Replaces the per-PTB merge cache that was load-bearing\n // pre-2026-05-22 (when `selectAndSplitCoin` emitted explicit\n // `mergeCoins` itself).\n const { selectAndSplitCoin } = await import('../wallet/coinSelection.js');\n const result = await selectAndSplitCoin(tx, client, address, fromType, requestedRaw, {\n sponsoredContext: input.sponsoredContext ?? false,\n });\n inputCoin = result.coin;\n effectiveRaw = result.effectiveAmount;\n }\n\n // [SPEC 20.2 D-3 (b)] Use the precomputed route when available + valid.\n // Validity = same input/output coin types AND the requested raw amount\n // matches what the route was discovered for (mismatch indicates the user\n // edited the amount post-quote, in which case we must re-discover at the\n // new amount because price impact is amount-dependent). The caller\n // (`audric prepare-route`) owns the staleness check (`isCetusRouteFresh`)\n // and only forwards `precomputedRoute` when fresh.\n //\n // [Bug A defense-in-depth / 2026-05-10] Even with the engine fix that\n // makes `swap_quote` discover sponsor-safe routes, this layer also\n // validates the precomputed route against the active providers\n // allow-list. If the route walks any excluded provider (e.g. a stale\n // `pending_action.cetusRoute` from before the engine fix shipped, or a\n // provider list that drifted between quote and execute), fall back to\n // fresh discovery. Better to eat 400ms than to let a Pyth-dependent\n // route reach Enoki and revert with HTTP 400.\n let route: SwapRouteResult | null;\n let usedPrecomputedRoute = false;\n if (\n input.precomputedRoute &&\n input.precomputedRoute.amountIn === effectiveRaw.toString() &&\n input.precomputedRoute.byAmountIn === byAmountIn &&\n isPrecomputedRouteCompatibleWithProviders(input.precomputedRoute, input.providers)\n ) {\n route = input.precomputedRoute;\n usedPrecomputedRoute = true;\n } else {\n route = await findSwapRoute({\n walletAddress: address,\n from: fromType,\n to: toType,\n amount: effectiveRaw,\n byAmountIn,\n overlayFee: input.overlayFee,\n providers: input.providers,\n });\n }\n\n if (!route) {\n throw new T2000Error('SWAP_NO_ROUTE', `No swap route found for ${input.from} → ${input.to}`);\n }\n if (route.insufficientLiquidity) {\n throw new T2000Error('SWAP_NO_ROUTE', `Insufficient liquidity for ${input.from} → ${input.to}`);\n }\n\n const outputCoin = await buildSwapTx({\n walletAddress: address,\n route,\n tx,\n inputCoin,\n slippage,\n overlayFee: input.overlayFee,\n });\n\n return {\n coin: outputCoin,\n effectiveAmountIn: Number(effectiveRaw) / 10 ** fromDecimals,\n expectedAmountOut: Number(route.amountOut) / 10 ** toDecimals,\n route,\n usedPrecomputedRoute,\n };\n}\n\n/**\n * Simulate a swap transaction without executing it.\n */\nexport async function simulateSwap(params: {\n walletAddress: string;\n tx: Transaction;\n overlayFee?: OverlayFeeConfig;\n}): Promise<{ success: boolean; error?: string }> {\n const client = getClient(params.walletAddress, params.overlayFee);\n try {\n await client.devInspectTransactionBlock(params.tx);\n return { success: true };\n } catch (err) {\n return { success: false, error: err instanceof Error ? err.message : String(err) };\n }\n}\n\n// Re-export from the canonical token registry for backward-compat.\nexport { TOKEN_MAP, resolveTokenType } from '../token-registry.js';\n","import { T2000Error } from '../errors.js';\n\nexport type SafeguardRule = 'locked' | 'maxPerTx' | 'maxDailySend';\n\nexport interface SafeguardErrorDetails {\n attempted?: number;\n limit?: number;\n current?: number;\n}\n\nexport class SafeguardError extends T2000Error {\n readonly rule: SafeguardRule;\n readonly details: SafeguardErrorDetails;\n\n constructor(rule: SafeguardRule, details: SafeguardErrorDetails, message?: string) {\n const msg = message ?? buildMessage(rule, details);\n super('SAFEGUARD_BLOCKED' as any, msg, { rule, ...details });\n this.name = 'SafeguardError';\n this.rule = rule;\n this.details = details;\n }\n\n override toJSON() {\n return {\n error: 'SAFEGUARD_BLOCKED' as const,\n message: this.message,\n retryable: this.retryable,\n data: { rule: this.rule, ...this.details },\n };\n }\n}\n\nfunction buildMessage(rule: SafeguardRule, details: SafeguardErrorDetails): string {\n switch (rule) {\n case 'locked':\n return 'Agent is locked. All operations are frozen.';\n case 'maxPerTx':\n return `Amount $${(details.attempted ?? 0).toFixed(2)} exceeds per-transaction limit ($${(details.limit ?? 0).toFixed(2)})`;\n case 'maxDailySend':\n return `Daily send limit reached ($${(details.current ?? 0).toFixed(2)}/$${(details.limit ?? 0).toFixed(2)} used today)`;\n }\n}\n","export interface SafeguardConfig {\n locked: boolean;\n maxPerTx: number;\n maxDailySend: number;\n dailyUsed: number;\n dailyResetDate: string;\n maxLeverage?: number;\n maxPositionSize?: number;\n}\n\nexport interface TxMetadata {\n operation:\n | 'send'\n | 'save'\n | 'withdraw'\n | 'borrow'\n | 'repay'\n | 'pay';\n amount?: number;\n}\n\nexport const OUTBOUND_OPS = new Set<TxMetadata['operation']>([\n 'send',\n 'pay',\n]);\n\nexport const DEFAULT_SAFEGUARD_CONFIG: SafeguardConfig = {\n locked: false,\n maxPerTx: 0,\n maxDailySend: 0,\n dailyUsed: 0,\n dailyResetDate: '',\n};\n"]}
|