diff --git a/package.json b/package.json index 000c30f6f9..a1a8fc052d 100644 --- a/package.json +++ b/package.json @@ -25,6 +25,10 @@ "rebuild-bigint": "cd node_modules/bigint-buffer && npm run rebuild" }, "dependencies": { + "@aiquant/lucid-cardano": "^0.10.11", + "@aiquant/minswap-sdk": "^0.0.0", + "@aiquant/sundaeswap-core": "^1.2.10", + "@blockfrost/blockfrost-js": "^5.7.0", "@coral-xyz/anchor": "^0.29.0", "@ethersproject/abstract-provider": "5.7.0", "@ethersproject/address": "5.7.0", @@ -52,6 +56,7 @@ "@solana/spl-token-registry": "^0.2.4574", "@solana/web3.js": "^1.98.0", "@solflare-wallet/utl-sdk": "^1.4.0", + "@sundaeswap/asset": "^1.0.10", "@uniswap/sdk": "3.0.3", "@uniswap/sdk-core": "^5.9.0", "@uniswap/smart-order-router": "^3.59.0", @@ -64,6 +69,7 @@ "axios": "^1.8.4", "bn.js": "5.2.1", "brotli": "1.3.2", + "core-js": "^3.43.0", "dayjs": "^1.11.13", "decimal.js": "^10.5.0", "decimal.js-light": "^2.5.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 7ecebb7cf2..0674ab59dc 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -17,6 +17,18 @@ importers: .: dependencies: + '@aiquant/lucid-cardano': + specifier: ^0.10.11 + version: 0.10.11(bufferutil@4.0.9)(utf-8-validate@5.0.10) + '@aiquant/minswap-sdk': + specifier: ^0.0.0 + version: 0.0.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) + '@aiquant/sundaeswap-core': + specifier: ^1.2.10 + version: 1.2.10(@aiquant/lucid-cardano@0.10.11(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@sundaeswap/asset@1.0.10)(@sundaeswap/bigint-math@0.6.3)(@sundaeswap/cpp@1.0.11(@sundaeswap/asset@1.0.10)(@sundaeswap/bigint-math@0.6.3)(@sundaeswap/fraction@1.0.7))(@sundaeswap/fraction@1.0.7) + '@blockfrost/blockfrost-js': + specifier: ^5.7.0 + version: 5.7.0 '@coral-xyz/anchor': specifier: ^0.29.0 version: 0.29.0(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.8.3)(utf-8-validate@5.0.10) @@ -70,13 +82,13 @@ importers: version: 1.0.15 '@oclif/plugin-autocomplete': specifier: ^3.2.26 - version: 3.2.28 + version: 3.2.32 '@oclif/plugin-help': specifier: ^6.2.27 - version: 6.2.28 + version: 6.2.30 '@oclif/plugin-plugins': specifier: ^5.4.36 - version: 5.4.37 + version: 5.4.44 '@orca-so/common-sdk': specifier: ^0.6.11 version: 0.6.11(@solana/spl-token@0.4.8(@solana/web3.js@1.98.2(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.8.3)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3)(utf-8-validate@5.0.10))(@solana/web3.js@1.98.2(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.8.3)(utf-8-validate@5.0.10)) @@ -98,6 +110,9 @@ importers: '@solflare-wallet/utl-sdk': specifier: ^1.4.0 version: 1.4.0(@solana/web3.js@1.98.2(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.8.3)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3)(utf-8-validate@5.0.10) + '@sundaeswap/asset': + specifier: ^1.0.10 + version: 1.0.10 '@uniswap/sdk': specifier: 3.0.3 version: 3.0.3(@ethersproject/address@5.7.0)(@ethersproject/contracts@5.7.0)(@ethersproject/networks@5.7.0)(@ethersproject/providers@5.7.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@ethersproject/solidity@5.7.0) @@ -106,7 +121,7 @@ importers: version: 5.9.0 '@uniswap/smart-order-router': specifier: ^3.59.0 - version: 3.59.0(bufferutil@4.0.9)(encoding@0.1.13)(hardhat@2.24.0(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@15.14.9)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10))(jsbi@3.2.5)(utf-8-validate@5.0.10) + version: 3.59.0(bufferutil@4.0.9)(encoding@0.1.13)(hardhat@2.25.0(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@15.14.9)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10))(jsbi@3.2.5)(utf-8-validate@5.0.10) '@uniswap/v2-sdk': specifier: ^4.15.2 version: 4.15.2 @@ -118,7 +133,7 @@ importers: version: 1.4.4 '@uniswap/v3-sdk': specifier: ^3.25.2 - version: 3.25.2(hardhat@2.24.0(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@15.14.9)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10)) + version: 3.25.2(hardhat@2.25.0(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@15.14.9)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10)) ajv: specifier: ^8.17.1 version: 8.17.1 @@ -127,25 +142,28 @@ importers: version: 3.1.0 axios: specifier: ^1.8.4 - version: 1.9.0 + version: 1.10.0 bn.js: specifier: 5.2.1 version: 5.2.1 brotli: specifier: 1.3.2 version: 1.3.2 + core-js: + specifier: ^3.43.0 + version: 3.43.0 dayjs: specifier: ^1.11.13 version: 1.11.13 decimal.js: specifier: ^10.5.0 - version: 10.5.0 + version: 10.6.0 decimal.js-light: specifier: ^2.5.1 version: 2.5.1 dotenv: specifier: ^16.4.7 - version: 16.5.0 + version: 16.6.1 ethers: specifier: ^5.8.0 version: 5.8.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) @@ -157,7 +175,7 @@ importers: version: 4.29.1 fastify-type-provider-zod: specifier: ^2.1.0 - version: 2.1.0(fastify@4.29.1)(zod@3.24.4) + version: 2.1.0(fastify@4.29.1)(zod@3.25.74) fs-extra: specifier: ^10.1.0 version: 10.1.0 @@ -181,7 +199,7 @@ importers: version: 11.3.0 pnpm: specifier: ^10.10.0 - version: 10.10.0 + version: 10.12.4 snake-case: specifier: ^4.0.0 version: 4.0.0 @@ -202,14 +220,14 @@ importers: version: 4.7.1(winston@3.17.0) zod: specifier: ^3.24.2 - version: 3.24.4 + version: 3.25.74 devDependencies: '@babel/core': specifier: ^7.26.10 - version: 7.27.1 + version: 7.28.0 '@babel/runtime': specifier: ^7.27.0 - version: 7.27.1 + version: 7.27.6 '@connectis/diff-test-coverage': specifier: ^1.5.3 version: 1.5.3 @@ -224,7 +242,7 @@ importers: version: 4.0.4 '@types/express': specifier: ^4.17.21 - version: 4.17.21 + version: 4.17.23 '@types/fs-extra': specifier: ^9.0.13 version: 9.0.13 @@ -278,19 +296,19 @@ importers: version: 9.1.0(eslint@8.57.1) eslint-config-standard: specifier: ^17.1.0 - version: 17.1.0(eslint-plugin-import@2.31.0(@typescript-eslint/parser@7.18.0(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1))(eslint-plugin-n@16.6.2(eslint@8.57.1))(eslint-plugin-promise@6.6.0(eslint@8.57.1))(eslint@8.57.1) + version: 17.1.0(eslint-plugin-import@2.32.0(@typescript-eslint/parser@7.18.0(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1))(eslint-plugin-n@16.6.2(eslint@8.57.1))(eslint-plugin-promise@6.6.0(eslint@8.57.1))(eslint@8.57.1) eslint-formatter-table: specifier: ^7.32.1 version: 7.32.1 eslint-plugin-import: specifier: ^2.31.0 - version: 2.31.0(@typescript-eslint/parser@7.18.0(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1) + version: 2.32.0(@typescript-eslint/parser@7.18.0(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1) eslint-plugin-n: specifier: ^16.6.2 version: 16.6.2(eslint@8.57.1) eslint-plugin-prettier: specifier: ^5.2.5 - version: 5.4.0(eslint-config-prettier@9.1.0(eslint@8.57.1))(eslint@8.57.1)(prettier@3.5.3) + version: 5.5.1(eslint-config-prettier@9.1.0(eslint@8.57.1))(eslint@8.57.1)(prettier@3.6.2) eslint-plugin-promise: specifier: ^6.1.1 version: 6.6.0(eslint@8.57.1) @@ -302,7 +320,7 @@ importers: version: 3.21.4 hardhat: specifier: ^2.22.19 - version: 2.24.0(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@15.14.9)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10) + version: 2.25.0(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@15.14.9)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10) husky: specifier: ^9.1.7 version: 9.1.7 @@ -326,7 +344,7 @@ importers: version: 2.0.22 prettier: specifier: ^3.5.3 - version: 3.5.3 + version: 3.6.2 react: specifier: ^18.3.1 version: 18.3.1 @@ -338,10 +356,10 @@ importers: version: 3.0.2 supertest: specifier: ^7.1.0 - version: 7.1.0 + version: 7.1.1 ts-jest: specifier: ^29.3.0 - version: 29.3.2(@babel/core@7.27.1)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.27.1))(jest@29.7.0(@types/node@15.14.9)(ts-node@10.9.2(@types/node@15.14.9)(typescript@5.8.3)))(typescript@5.8.3) + version: 29.4.0(@babel/core@7.28.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.28.0))(jest-util@29.7.0)(jest@29.7.0(@types/node@15.14.9)(ts-node@10.9.2(@types/node@15.14.9)(typescript@5.8.3)))(typescript@5.8.3) ts-node: specifier: ^10.9.2 version: 10.9.2(@types/node@15.14.9)(typescript@5.8.3) @@ -350,13 +368,29 @@ importers: version: 5.8.3 viem: specifier: ^0.3.50 - version: 0.3.50(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.24.4) + version: 0.3.50(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.74) packages: '@adraffy/ens-normalize@1.9.0': resolution: {integrity: sha512-iowxq3U30sghZotgl4s/oJRci6WPBfNO5YYgk2cIOMCHr3LeGPcsZjCEr+33Q4N+oV3OABDAtA+pyvWjbvBifQ==} + '@aiquant/lucid-cardano@0.10.11': + resolution: {integrity: sha512-ZJxnEUAO/yhBIklW3KHWffWlgOCW7Lr/in/Ktd6dzpu4mqagnLUM4bV4VZeaZimknPZ3nA+750dz3mD+wUFPEA==} + engines: {node: '>=14'} + + '@aiquant/minswap-sdk@0.0.0': + resolution: {integrity: sha512-wCVepFXHRC4d7tyLJ4uDsHn0KgQKZuKicR4U4xkkXfdwJv7C621Ki9gWw1JawFm6wBuyntmVmZAnm3JCNcyQLQ==} + + '@aiquant/sundaeswap-core@1.2.10': + resolution: {integrity: sha512-v84BeHaDQa24cxIIE0U/+iiOHTxlOmC785oQNa8CgQ6X0UUmaoPYj1bK3C1ahGU395XkG8f5ICvAVc+2JlsrgA==} + peerDependencies: + '@aiquant/lucid-cardano': ^0.10.7 + '@sundaeswap/asset': ^1.0.3 + '@sundaeswap/bigint-math': ^0.6.3 + '@sundaeswap/cpp': ^1.0.3 + '@sundaeswap/fraction': ^1.0.3 + '@ampproject/remapping@2.3.0': resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} engines: {node: '>=6.0.0'} @@ -384,123 +418,123 @@ packages: '@aws-crypto/util@5.2.0': resolution: {integrity: sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ==} - '@aws-sdk/client-s3@3.806.0': - resolution: {integrity: sha512-kQaBBBxEBU/IJ2wKG+LL2BK+uvBwpdvOA9jy1WhW+U2/DIMwMrjVs7M/ZvTlmVOJwhZaONcJbgQqsN4Yirjj4g==} + '@aws-sdk/client-s3@3.842.0': + resolution: {integrity: sha512-T5Rh72Rcq1xIaM8KkTr1Wpr7/WPCYO++KrM+/Em0rq2jxpjMMhj77ITpgH7eEmNxWmwIndTwqpgfmbpNfk7Gbw==} engines: {node: '>=18.0.0'} - '@aws-sdk/client-sso@3.806.0': - resolution: {integrity: sha512-X0p/9/u9e6b22rlQqKucdtjdqmjSNB4c/8zDEoD5MvgYAAbMF9HNE0ST2xaA/WsJ7uE0jFfhPY2/00pslL1DqQ==} + '@aws-sdk/client-sso@3.840.0': + resolution: {integrity: sha512-3Zp+FWN2hhmKdpS0Ragi5V2ZPsZNScE3jlbgoJjzjI/roHZqO+e3/+XFN4TlM0DsPKYJNp+1TAjmhxN6rOnfYA==} engines: {node: '>=18.0.0'} - '@aws-sdk/core@3.806.0': - resolution: {integrity: sha512-HJRINPncdjPK0iL3f6cBpqCMaxVwq2oDbRCzOx04tsLZ0tNgRACBfT3d/zNVRvMt6fnOVKXoN1LAtQaw50pjEA==} + '@aws-sdk/core@3.840.0': + resolution: {integrity: sha512-x3Zgb39tF1h2XpU+yA4OAAQlW6LVEfXNlSedSYJ7HGKXqA/E9h3rWQVpYfhXXVVsLdYXdNw5KBUkoAoruoZSZA==} engines: {node: '>=18.0.0'} - '@aws-sdk/credential-provider-env@3.806.0': - resolution: {integrity: sha512-nbPwmZn0kt6Q1XI2FaJWP6AhF9tro4cO5HlmZQx8NU+B0H1y9WMo659Q5zLLY46BXgoQVIJEsPSZpcZk27O4aw==} + '@aws-sdk/credential-provider-env@3.840.0': + resolution: {integrity: sha512-EzF6VcJK7XvQ/G15AVEfJzN2mNXU8fcVpXo4bRyr1S6t2q5zx6UPH/XjDbn18xyUmOq01t+r8gG+TmHEVo18fA==} engines: {node: '>=18.0.0'} - '@aws-sdk/credential-provider-http@3.806.0': - resolution: {integrity: sha512-e/gB2iJQQ4ZpecOVpEFhEvjGwuTqNCzhVaVsFYVc49FPfR1seuN7qBGYe1MO7mouGDQFInzJgcNup0DnYUrLiw==} + '@aws-sdk/credential-provider-http@3.840.0': + resolution: {integrity: sha512-wbnUiPGLVea6mXbUh04fu+VJmGkQvmToPeTYdHE8eRZq3NRDi3t3WltT+jArLBKD/4NppRpMjf2ju4coMCz91g==} engines: {node: '>=18.0.0'} - '@aws-sdk/credential-provider-ini@3.806.0': - resolution: {integrity: sha512-FogfbuYSEZgFxbNy0QcsBZHHe5mSv5HV3+JyB5n0kCyjOISCVCZD7gwxKdXjt8O1hXq5k5SOdQvydGULlB6rew==} + '@aws-sdk/credential-provider-ini@3.840.0': + resolution: {integrity: sha512-7F290BsWydShHb+7InXd+IjJc3mlEIm9I0R57F/Pjl1xZB69MdkhVGCnuETWoBt4g53ktJd6NEjzm/iAhFXFmw==} engines: {node: '>=18.0.0'} - '@aws-sdk/credential-provider-node@3.806.0': - resolution: {integrity: sha512-fZX8xP2Kf0k70kDTog/87fh/M+CV0E2yujSw1cUBJhDSwDX3RlUahiJk7TpB/KGw6hEFESMd6+7kq3UzYuw3rg==} + '@aws-sdk/credential-provider-node@3.840.0': + resolution: {integrity: sha512-KufP8JnxA31wxklLm63evUPSFApGcH8X86z3mv9SRbpCm5ycgWIGVCTXpTOdgq6rPZrwT9pftzv2/b4mV/9clg==} engines: {node: '>=18.0.0'} - '@aws-sdk/credential-provider-process@3.806.0': - resolution: {integrity: sha512-8Y8GYEw/1e5IZRDQL02H6nsTDcRWid/afRMeWg+93oLQmbHcTtdm48tjis+7Xwqy+XazhMDmkbUht11QPTDJcQ==} + '@aws-sdk/credential-provider-process@3.840.0': + resolution: {integrity: sha512-HkDQWHy8tCI4A0Ps2NVtuVYMv9cB4y/IuD/TdOsqeRIAT12h8jDb98BwQPNLAImAOwOWzZJ8Cu0xtSpX7CQhMw==} engines: {node: '>=18.0.0'} - '@aws-sdk/credential-provider-sso@3.806.0': - resolution: {integrity: sha512-hT9OBwCxWMPBydNhXm2gdNNzx5AJNheS9RglwDDvXWzQ9qDuRztjuMBilMSUMb0HF9K4IqQjYzGqczMuktz4qQ==} + '@aws-sdk/credential-provider-sso@3.840.0': + resolution: {integrity: sha512-2qgdtdd6R0Z1y0KL8gzzwFUGmhBHSUx4zy85L2XV1CXhpRNwV71SVWJqLDVV5RVWVf9mg50Pm3AWrUC0xb0pcA==} engines: {node: '>=18.0.0'} - '@aws-sdk/credential-provider-web-identity@3.806.0': - resolution: {integrity: sha512-XxaSY9Zd3D4ClUGENYMvi52ac5FuJPPAsvRtEfyrSdEpf6QufbMpnexWBZMYRF31h/VutgqtJwosGgNytpxMEg==} + '@aws-sdk/credential-provider-web-identity@3.840.0': + resolution: {integrity: sha512-dpEeVXG8uNZSmVXReE4WP0lwoioX2gstk4RnUgrdUE3YaPq8A+hJiVAyc3h+cjDeIqfbsQbZm9qFetKC2LF9dQ==} engines: {node: '>=18.0.0'} - '@aws-sdk/middleware-bucket-endpoint@3.806.0': - resolution: {integrity: sha512-ACjuyKJw9OZl8z8HzPEaqn1o7ElVW94mowyoZvyUIDouwAPGqPGJbJ5V35qx1oDTFSAJX+N3O3AO6RyFc8nUhw==} + '@aws-sdk/middleware-bucket-endpoint@3.840.0': + resolution: {integrity: sha512-+gkQNtPwcSMmlwBHFd4saVVS11In6ID1HczNzpM3MXKXRBfSlbZJbCt6wN//AZ8HMklZEik4tcEOG0qa9UY8SQ==} engines: {node: '>=18.0.0'} - '@aws-sdk/middleware-expect-continue@3.804.0': - resolution: {integrity: sha512-YW1hySBolALMII6C8y7Z0CRG2UX1dGJjLEBNFeefhO/xP7ZuE1dvnmfJGaEuBMnvc3wkRS63VZ3aqX6sevM1CA==} + '@aws-sdk/middleware-expect-continue@3.840.0': + resolution: {integrity: sha512-iJg2r6FKsKKvdiU4oCOuCf7Ro/YE0Q2BT/QyEZN3/Rt8Nr4SAZiQOlcBXOCpGvuIKOEAhvDOUnW3aDHL01PdVw==} engines: {node: '>=18.0.0'} - '@aws-sdk/middleware-flexible-checksums@3.806.0': - resolution: {integrity: sha512-YEmuU2Nr/+blhi70gS38fnCe2IoL6OVVZXMp4MbzqZRUqeBbnxZhHQrd5YOiboJz7iq+g98xwFebHY167iejcg==} + '@aws-sdk/middleware-flexible-checksums@3.840.0': + resolution: {integrity: sha512-Kg/o2G6o72sdoRH0J+avdcf668gM1bp6O4VeEXpXwUj/urQnV5qiB2q1EYT110INHUKWOLXPND3sQAqh6sTqHw==} engines: {node: '>=18.0.0'} - '@aws-sdk/middleware-host-header@3.804.0': - resolution: {integrity: sha512-bum1hLVBrn2lJCi423Z2fMUYtsbkGI2s4N+2RI2WSjvbaVyMSv/WcejIrjkqiiMR+2Y7m5exgoKeg4/TODLDPQ==} + '@aws-sdk/middleware-host-header@3.840.0': + resolution: {integrity: sha512-ub+hXJAbAje94+Ya6c6eL7sYujoE8D4Bumu1NUI8TXjUhVVn0HzVWQjpRLshdLsUp1AW7XyeJaxyajRaJQ8+Xg==} engines: {node: '>=18.0.0'} - '@aws-sdk/middleware-location-constraint@3.804.0': - resolution: {integrity: sha512-AMtKnllIWKgoo7hiJfphLYotEwTERfjVMO2+cKAncz9w1g+bnYhHxiVhJJoR94y047c06X4PU5MsTxvdQ73Znw==} + '@aws-sdk/middleware-location-constraint@3.840.0': + resolution: {integrity: sha512-KVLD0u0YMF3aQkVF8bdyHAGWSUY6N1Du89htTLgqCcIhSxxAJ9qifrosVZ9jkAzqRW99hcufyt2LylcVU2yoKQ==} engines: {node: '>=18.0.0'} - '@aws-sdk/middleware-logger@3.804.0': - resolution: {integrity: sha512-w/qLwL3iq0KOPQNat0Kb7sKndl9BtceigINwBU7SpkYWX9L/Lem6f8NPEKrC9Tl4wDBht3Yztub4oRTy/horJA==} + '@aws-sdk/middleware-logger@3.840.0': + resolution: {integrity: sha512-lSV8FvjpdllpGaRspywss4CtXV8M7NNNH+2/j86vMH+YCOZ6fu2T/TyFd/tHwZ92vDfHctWkRbQxg0bagqwovA==} engines: {node: '>=18.0.0'} - '@aws-sdk/middleware-recursion-detection@3.804.0': - resolution: {integrity: sha512-zqHOrvLRdsUdN/ehYfZ9Tf8svhbiLLz5VaWUz22YndFv6m9qaAcijkpAOlKexsv3nLBMJdSdJ6GUTAeIy3BZzw==} + '@aws-sdk/middleware-recursion-detection@3.840.0': + resolution: {integrity: sha512-Gu7lGDyfddyhIkj1Z1JtrY5NHb5+x/CRiB87GjaSrKxkDaydtX2CU977JIABtt69l9wLbcGDIQ+W0uJ5xPof7g==} engines: {node: '>=18.0.0'} - '@aws-sdk/middleware-sdk-s3@3.806.0': - resolution: {integrity: sha512-K1ssdovHH/kPN9EUS1LznwzoL+r89Cx8qAkp0K8MqdCQuBjZ0KRnjvo9nx69Vg5d/rg01VYTxomFUPXfcPtVXw==} + '@aws-sdk/middleware-sdk-s3@3.840.0': + resolution: {integrity: sha512-rOUji7CayWN3O09zvvgLzDVQe0HiJdZkxoTS6vzOS3WbbdT7joGdVtAJHtn+x776QT3hHzbKU5gnfhel0o6gQA==} engines: {node: '>=18.0.0'} - '@aws-sdk/middleware-ssec@3.804.0': - resolution: {integrity: sha512-Tk8jK0gOIUBvEPTz/wwSlP1V70zVQ3QYqsLPAjQRMO6zfOK9ax31dln3MgKvFDJxBydS2tS3wsn53v+brxDxTA==} + '@aws-sdk/middleware-ssec@3.840.0': + resolution: {integrity: sha512-CBZP9t1QbjDFGOrtnUEHL1oAvmnCUUm7p0aPNbIdSzNtH42TNKjPRN3TuEIJDGjkrqpL3MXyDSmNayDcw/XW7Q==} engines: {node: '>=18.0.0'} - '@aws-sdk/middleware-user-agent@3.806.0': - resolution: {integrity: sha512-XoIromVffgXnc+/mjlR2EVzQVIei3bPVtafIZNsHuEmUvIWJXiWsa2eJpt3BUqa0HF9YPknK7ommNEhqRb8ucg==} + '@aws-sdk/middleware-user-agent@3.840.0': + resolution: {integrity: sha512-hiiMf7BP5ZkAFAvWRcK67Mw/g55ar7OCrvrynC92hunx/xhMkrgSLM0EXIZ1oTn3uql9kH/qqGF0nqsK6K555A==} engines: {node: '>=18.0.0'} - '@aws-sdk/nested-clients@3.806.0': - resolution: {integrity: sha512-ua2gzpfQ9MF8Rny+tOAivowOWWvqEusez2rdcQK8jdBjA1ANd/0xzToSZjZh0ziN8Kl8jOhNnHbQJ0v6dT6+hg==} + '@aws-sdk/nested-clients@3.840.0': + resolution: {integrity: sha512-LXYYo9+n4hRqnRSIMXLBb+BLz+cEmjMtTudwK1BF6Bn2RfdDv29KuyeDRrPCS3TwKl7ZKmXUmE9n5UuHAPfBpA==} engines: {node: '>=18.0.0'} - '@aws-sdk/region-config-resolver@3.806.0': - resolution: {integrity: sha512-cuv5pX55JOlzKC/iLsB5nZ9eUyVgncim3VhhWHZA/KYPh7rLMjOEfZ+xyaE9uLJXGmzOJboFH7+YdTRdIcOgrg==} + '@aws-sdk/region-config-resolver@3.840.0': + resolution: {integrity: sha512-Qjnxd/yDv9KpIMWr90ZDPtRj0v75AqGC92Lm9+oHXZ8p1MjG5JE2CW0HL8JRgK9iKzgKBL7pPQRXI8FkvEVfrA==} engines: {node: '>=18.0.0'} - '@aws-sdk/signature-v4-multi-region@3.806.0': - resolution: {integrity: sha512-IrbEnpKvG8d9rUWAvsF28g8qBlQ02FaOxn4cGXtTs0b0BGMK1M+cGQrYjJ7Ak08kIXDxBqsdIlZGsKYr+Ds9+w==} + '@aws-sdk/signature-v4-multi-region@3.840.0': + resolution: {integrity: sha512-8AoVgHrkSfhvGPtwx23hIUO4MmMnux2pjnso1lrLZGqxfElM6jm2w4jTNLlNXk8uKHGyX89HaAIuT0lL6dJj9g==} engines: {node: '>=18.0.0'} - '@aws-sdk/token-providers@3.806.0': - resolution: {integrity: sha512-I6SxcsvV7yinJZmPgGullFHS0tsTKa7K3jEc5dmyCz8X+kZPfsWNffZmtmnCvWXPqMXWBvK6hVaxwomx79yeHA==} + '@aws-sdk/token-providers@3.840.0': + resolution: {integrity: sha512-6BuTOLTXvmgwjK7ve7aTg9JaWFdM5UoMolLVPMyh3wTv9Ufalh8oklxYHUBIxsKkBGO2WiHXytveuxH6tAgTYg==} engines: {node: '>=18.0.0'} - '@aws-sdk/types@3.804.0': - resolution: {integrity: sha512-A9qnsy9zQ8G89vrPPlNG9d1d8QcKRGqJKqwyGgS0dclJpwy6d1EWgQLIolKPl6vcFpLoe6avLOLxr+h8ur5wpg==} + '@aws-sdk/types@3.840.0': + resolution: {integrity: sha512-xliuHaUFZxEx1NSXeLLZ9Dyu6+EJVQKEoD+yM+zqUo3YDZ7medKJWY6fIOKiPX/N7XbLdBYwajb15Q7IL8KkeA==} engines: {node: '>=18.0.0'} '@aws-sdk/util-arn-parser@3.804.0': resolution: {integrity: sha512-wmBJqn1DRXnZu3b4EkE6CWnoWMo1ZMvlfkqU5zPz67xx1GMaXlDCchFvKAXMjk4jn/L1O3tKnoFDNsoLV1kgNQ==} engines: {node: '>=18.0.0'} - '@aws-sdk/util-endpoints@3.806.0': - resolution: {integrity: sha512-3YRRgZ+qFuWDdm5uAbxKsr65UAil4KkrFKua9f4m7Be3v24ETiFOOqhanFUIk9/WOtvzF7oFEiDjYKDGlwV2xg==} + '@aws-sdk/util-endpoints@3.840.0': + resolution: {integrity: sha512-eqE9ROdg/Kk0rj3poutyRCFauPDXIf/WSvCqFiRDDVi6QOnCv/M0g2XW8/jSvkJlOyaXkNCptapIp6BeeFFGYw==} engines: {node: '>=18.0.0'} '@aws-sdk/util-locate-window@3.804.0': resolution: {integrity: sha512-zVoRfpmBVPodYlnMjgVjfGoEZagyRF5IPn3Uo6ZvOZp24chnW/FRstH7ESDHDDRga4z3V+ElUQHKpFDXWyBW5A==} engines: {node: '>=18.0.0'} - '@aws-sdk/util-user-agent-browser@3.804.0': - resolution: {integrity: sha512-KfW6T6nQHHM/vZBBdGn6fMyG/MgX5lq82TDdX4HRQRRuHKLgBWGpKXqqvBwqIaCdXwWHgDrg2VQups6GqOWW2A==} + '@aws-sdk/util-user-agent-browser@3.840.0': + resolution: {integrity: sha512-JdyZM3EhhL4PqwFpttZu1afDpPJCCc3eyZOLi+srpX11LsGj6sThf47TYQN75HT1CarZ7cCdQHGzP2uy3/xHfQ==} - '@aws-sdk/util-user-agent-node@3.806.0': - resolution: {integrity: sha512-Az2e4/gmPZ4BpB7QRj7U76I+fctXhNcxlcgsaHnMhvt+R30nvzM2EhsyBUvsWl8+r9bnLeYt9BpvEZeq2ANDzA==} + '@aws-sdk/util-user-agent-node@3.840.0': + resolution: {integrity: sha512-Fy5JUEDQU1tPm2Yw/YqRYYc27W5+QD/J4mYvQvdWjUGZLB5q3eLFMGD35Uc28ZFoGMufPr4OCxK/bRfWROBRHQ==} engines: {node: '>=18.0.0'} peerDependencies: aws-crt: '>=1.0.0' @@ -508,36 +542,40 @@ packages: aws-crt: optional: true - '@aws-sdk/xml-builder@3.804.0': - resolution: {integrity: sha512-JbGWp36IG9dgxtvC6+YXwt5WDZYfuamWFtVfK6fQpnmL96dx+GUPOXPKRWdw67WLKf2comHY28iX2d3z35I53Q==} + '@aws-sdk/xml-builder@3.821.0': + resolution: {integrity: sha512-DIIotRnefVL6DiaHtO6/21DhJ4JZnnIwdNbpwiAhdt/AVbttcE4yw925gsjur0OGv5BTYXQXU3YnANBYnZjuQA==} engines: {node: '>=18.0.0'} '@babel/code-frame@7.27.1': resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==} engines: {node: '>=6.9.0'} - '@babel/compat-data@7.27.2': - resolution: {integrity: sha512-TUtMJYRPyUb/9aU8f3K0mjmjf6M9N5Woshn2CS6nqJSeJtTtQcpLUXjGt9vbF8ZGff0El99sWkLgzwW3VXnxZQ==} + '@babel/compat-data@7.28.0': + resolution: {integrity: sha512-60X7qkglvrap8mn1lh2ebxXdZYtUcpd7gsmy9kLaBJ4i/WdY8PqTSdxyA8qraikqKQK5C1KRBKXqznrVapyNaw==} engines: {node: '>=6.9.0'} - '@babel/core@7.27.1': - resolution: {integrity: sha512-IaaGWsQqfsQWVLqMn9OB92MNN7zukfVA4s7KKAI0KfrrDsZ0yhi5uV4baBuLuN7n3vsZpwP8asPPcVwApxvjBQ==} + '@babel/core@7.28.0': + resolution: {integrity: sha512-UlLAnTPrFdNGoFtbSXwcGFQBtQZJCNjaN6hQNP3UPvuNXT1i82N26KL3dZeIpNalWywr9IuQuncaAfUaS1g6sQ==} engines: {node: '>=6.9.0'} - '@babel/generator@7.27.1': - resolution: {integrity: sha512-UnJfnIpc/+JO0/+KRVQNGU+y5taA5vCbwN8+azkX6beii/ZF+enZJSOKo11ZSzGJjlNfJHfQtmQT8H+9TXPG2w==} + '@babel/generator@7.28.0': + resolution: {integrity: sha512-lJjzvrbEeWrhB4P3QBsH7tey117PjLZnDbLiQEKjQ/fNJTjuq4HSqgFA+UNSwZT8D7dxxbnuSBMsa1lrWzKlQg==} engines: {node: '>=6.9.0'} '@babel/helper-compilation-targets@7.27.2': resolution: {integrity: sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==} engines: {node: '>=6.9.0'} + '@babel/helper-globals@7.28.0': + resolution: {integrity: sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==} + engines: {node: '>=6.9.0'} + '@babel/helper-module-imports@7.27.1': resolution: {integrity: sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==} engines: {node: '>=6.9.0'} - '@babel/helper-module-transforms@7.27.1': - resolution: {integrity: sha512-9yHn519/8KvTU5BjTVEEeIM3w9/2yXNKoD82JifINImhpKkARMJKPP59kLo+BafpdN5zgNeIcS4jsGDmd3l58g==} + '@babel/helper-module-transforms@7.27.3': + resolution: {integrity: sha512-dSOvYwvyLsWBeIRyOeHXp5vPj5l1I011r52FM1+r1jCERv+aFXYk4whgQccYEGYxK2H3ZAIA8nuPkQ0HaUo3qg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 @@ -558,12 +596,12 @@ packages: resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==} engines: {node: '>=6.9.0'} - '@babel/helpers@7.27.1': - resolution: {integrity: sha512-FCvFTm0sWV8Fxhpp2McP5/W53GPllQ9QeQ7SiqGWjMf/LVG07lFa5+pgK05IRhVwtvafT22KF+ZSnM9I545CvQ==} + '@babel/helpers@7.27.6': + resolution: {integrity: sha512-muE8Tt8M22638HU31A3CgfSUciwz1fhATfoVai05aPXGor//CdWDCbnlY1yvBPo07njuVOCNGCSp/GTt12lIug==} engines: {node: '>=6.9.0'} - '@babel/parser@7.27.2': - resolution: {integrity: sha512-QYLs8299NA7WM/bZAdp+CviYYkVoYXlDW2rzliy3chxd1PQjej7JORuMJDJXJUb9g0TT+B99EwaVLKmX+sPXWw==} + '@babel/parser@7.28.0': + resolution: {integrity: sha512-jVZGvOxOuNSsuQuLRTh13nU0AogFlw32w/MT+LV6D3sP5WdbW61E77RnkbaO2dUvmPAYrBDJXGn5gGS6tH4j8g==} engines: {node: '>=6.0.0'} hasBin: true @@ -658,25 +696,33 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/runtime@7.27.1': - resolution: {integrity: sha512-1x3D2xEk2fRo3PAhwQwu5UubzgiVWSXTBfWpVd2Mx2AzRqJuDJCsgaDVZ7HB5iGzDW1Hl1sWN2mFyKjmR9uAog==} + '@babel/runtime@7.27.6': + resolution: {integrity: sha512-vbavdySgbTTrmFE+EsiqUTzlOr5bzlnJtUv9PynGCAKvfQqjIXbvFdumPM/GxMDfyuGMJaJAU6TO4zc1Jf1i8Q==} engines: {node: '>=6.9.0'} '@babel/template@7.27.2': resolution: {integrity: sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==} engines: {node: '>=6.9.0'} - '@babel/traverse@7.27.1': - resolution: {integrity: sha512-ZCYtZciz1IWJB4U61UPu4KEaqyfj+r5T1Q5mqPo+IBpcG9kHv30Z0aD8LXPgC1trYa6rK0orRyAhqUgk4MjmEg==} + '@babel/traverse@7.28.0': + resolution: {integrity: sha512-mGe7UK5wWyh0bKRfupsUchrQGqvDbZDbKJw+kcRGSmdHVYrv+ltd0pnpDTVpiTqnaBru9iEvA8pz8W46v0Amwg==} engines: {node: '>=6.9.0'} - '@babel/types@7.27.1': - resolution: {integrity: sha512-+EzkxvLNfiUeKMgy/3luqfsCWFRXLb7U6wNQTk60tovuckwB15B191tJWvpp4HjiQWdJkCxO3Wbvc6jlk3Xb2Q==} + '@babel/types@7.28.0': + resolution: {integrity: sha512-jYnje+JyZG5YThjHiF28oT4SIZLnYOcSBb6+SDaFIyzDVSkXQmQQYclJ2R+YxcdmK0AX6x1E5OQNtuh3jHDrUg==} engines: {node: '>=6.9.0'} '@bcoe/v8-coverage@0.2.3': resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==} + '@blockfrost/blockfrost-js@5.7.0': + resolution: {integrity: sha512-Rzw+Ya+LlKJNv9k5g7xW0uM33Xf6Lt3MXANtuwtm7+R9xuMFc7iKocwHSgrGUTTZ1EKou4n4Znai18MdvqG2bw==} + engines: {node: '>=16'} + + '@blockfrost/openapi@0.1.70-beta.0': + resolution: {integrity: sha512-js+ZpOWJHRHE+C1bVTDRen/MKVuaA8Bygjlil8O55bN3MzWfwQ0jzzZCYOAHhkbgEwE+j6ziCbP2+1xwFmtR+Q==} + engines: {node: '>=20'} + '@bundlr-network/client@0.7.17': resolution: {integrity: sha512-1qTDrwgmgeh0pO24JbeGt2W8GlpWYkVnQ8AhEZ02Lm00J7RALSyma3C5pNlKuvAQBczL1r9KhLr9KHK1og3J0g==} deprecated: Bundlr is now Irys - please switch to @irys/sdk - this package will remain compatible with Irys for the foreseeable future. @@ -726,6 +772,12 @@ packages: '@dabh/diagnostics@2.0.3': resolution: {integrity: sha512-hrlQOIi7hAfzsMqlGSFyVucrx38O+j6wiGOf//H2ecvIEqYN4ADBSS2iLMh5UFyDunCNniUIPk/q3riFv45xRA==} + '@emurgo/cardano-serialization-lib-nodejs@11.5.0': + resolution: {integrity: sha512-IlVABlRgo9XaTR1NunwZpWcxnfEv04ba2l1vkUz4S1W7Jt36F4CtffP+jPeqBZGnAe+fnUwo0XjIJC3ZTNToNQ==} + + '@emurgo/cip14-js@3.0.1': + resolution: {integrity: sha512-u0XobeajNSlmeGBmY3ntA+NE/Vns7hKP0xrFzWyAO7YubETOifTjUddJN4gpvXE4S08DPUcNBVe3sx1m5GPIOg==} + '@eslint-community/eslint-utils@4.7.0': resolution: {integrity: sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -948,6 +1000,14 @@ packages: peerDependencies: google-protobuf: ^3.2.0 + '@isaacs/balanced-match@4.0.1': + resolution: {integrity: sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==} + engines: {node: 20 || >=22} + + '@isaacs/brace-expansion@5.0.0': + resolution: {integrity: sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA==} + engines: {node: 20 || >=22} + '@isaacs/cliui@8.0.2': resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} engines: {node: '>=12'} @@ -1046,23 +1106,18 @@ packages: resolution: {integrity: sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - '@jridgewell/gen-mapping@0.3.8': - resolution: {integrity: sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==} - engines: {node: '>=6.0.0'} + '@jridgewell/gen-mapping@0.3.12': + resolution: {integrity: sha512-OuLGC46TjB5BbN1dH8JULVVZY4WTdkF7tV9Ys6wLL1rubZnCMstOhNHueU5bLCrnRuDhKPDM4g6sw4Bel5Gzqg==} '@jridgewell/resolve-uri@3.1.2': resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} engines: {node: '>=6.0.0'} - '@jridgewell/set-array@1.2.1': - resolution: {integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==} - engines: {node: '>=6.0.0'} - - '@jridgewell/sourcemap-codec@1.5.0': - resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==} + '@jridgewell/sourcemap-codec@1.5.4': + resolution: {integrity: sha512-VT2+G1VQs/9oz078bLrYbecdZKs912zQlkelYpuf+SXF+QvZDYJlbx/LSx+meSAwdDFnF8FVXW92AVjjkVmgFw==} - '@jridgewell/trace-mapping@0.3.25': - resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==} + '@jridgewell/trace-mapping@0.3.29': + resolution: {integrity: sha512-uw6guiW/gcAGPDhLmd77/6lW8QLeiV5RUTsAX46Db6oLhGaVj4lhnPwb184s1bkc8kdVg/+h988dro8GRDpmYQ==} '@jridgewell/trace-mapping@0.3.9': resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} @@ -1116,6 +1171,9 @@ packages: '@meteora-ag/dlmm@1.3.12': resolution: {integrity: sha512-uoBjrl8yLVqKmpdcoC9Jj6Zg5mmo/2CeDEsWFrk6OiAoQ6g1+WBnr8lX/RWxXZ6r18YeP+QAKQbo1Tjf3HU0Cg==} + '@minswap/tiny-invariant@1.2.0': + resolution: {integrity: sha512-m4CMTsZ4MDB2WLND6rV0eti+f2WcMPhKvXf9ZHXlQMqvNmgoX1z//84FpEX0D1vVTPfJtNS8XIoIQ9pm6X590A==} + '@mrmlnc/readdir-enhanced@2.2.1': resolution: {integrity: sha512-bPHp6Ji8b41szTOcaP63VlnbbO5Ny6dwAATtY6JTjh5N2OLrb5Qk/Th5cRkRQhkWCt+EJsYrNB0MiL+Gpn6e3g==} engines: {node: '>=4'} @@ -1130,8 +1188,8 @@ packages: resolution: {integrity: sha512-vnI7V6lFNe0tLAuJMu+2sX+FcL14TaCWy1qiczg1VwRmPrpQCdq5ESXQMqUc2tluRNf6irBXrWbl1mGN8uaU/g==} engines: {node: ^14.21.3 || >=16} - '@noble/curves@1.9.0': - resolution: {integrity: sha512-7YDlXiNMdO1YZeH6t/kvopHHbIZzlxrCV9WLqCY6QhcXOoXiNCMDqJIglZ9Yjx5+w7Dz30TITFrlTjnRg7sKEg==} + '@noble/curves@1.9.2': + resolution: {integrity: sha512-HxngEd2XUcg9xi20JkwlLCtYwfoFw4JGkuZpT+WlsPD4gB/cxkvTD8fSsoAnphGZhFdZYKeQIPCuFlWPm1uE0g==} engines: {node: ^14.21.3 || >=16} '@noble/ed25519@1.7.5': @@ -1174,36 +1232,36 @@ packages: resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} engines: {node: '>= 8'} - '@nomicfoundation/edr-darwin-arm64@0.11.0': - resolution: {integrity: sha512-aYTVdcSs27XG7ayTzvZ4Yn9z/ABSaUwicrtrYK2NR8IH0ik4N4bWzo/qH8rax6rewVLbHUkGyGYnsy5ZN4iiMw==} + '@nomicfoundation/edr-darwin-arm64@0.11.3': + resolution: {integrity: sha512-w0tksbdtSxz9nuzHKsfx4c2mwaD0+l5qKL2R290QdnN9gi9AV62p9DHkOgfBdyg6/a6ZlnQqnISi7C9avk/6VA==} engines: {node: '>= 18'} - '@nomicfoundation/edr-darwin-x64@0.11.0': - resolution: {integrity: sha512-RxX7UYgvJrfcyT/uHUn44Nsy1XaoW+Q1khKMdHKxeW7BrgIi+Lz+siz3bX5vhSoAnKilDPhIVLrnC8zxQhjR2A==} + '@nomicfoundation/edr-darwin-x64@0.11.3': + resolution: {integrity: sha512-QR4jAFrPbOcrO7O2z2ESg+eUeIZPe2bPIlQYgiJ04ltbSGW27FblOzdd5+S3RoOD/dsZGKAvvy6dadBEl0NgoA==} engines: {node: '>= 18'} - '@nomicfoundation/edr-linux-arm64-gnu@0.11.0': - resolution: {integrity: sha512-J0j+rs0s11FuSipt/ymqrFmpJ7c0FSz1/+FohCIlUXDxFv//+1R/8lkGPjEYFmy8DPpk/iO8mcpqHTGckREbqA==} + '@nomicfoundation/edr-linux-arm64-gnu@0.11.3': + resolution: {integrity: sha512-Ktjv89RZZiUmOFPspuSBVJ61mBZQ2+HuLmV67InNlh9TSUec/iDjGIwAn59dx0bF/LOSrM7qg5od3KKac4LJDQ==} engines: {node: '>= 18'} - '@nomicfoundation/edr-linux-arm64-musl@0.11.0': - resolution: {integrity: sha512-4r32zkGMN7WT/CMEuW0VjbuEdIeCskHNDMW4SSgQSJOE/N9L1KSLJCSsAbPD3aYE+e4WRDTyOwmuLjeUTcLZKQ==} + '@nomicfoundation/edr-linux-arm64-musl@0.11.3': + resolution: {integrity: sha512-B3sLJx1rL2E9pfdD4mApiwOZSrX0a/KQSBWdlq1uAhFKqkl00yZaY4LejgZndsJAa4iKGQJlGnw4HCGeVt0+jA==} engines: {node: '>= 18'} - '@nomicfoundation/edr-linux-x64-gnu@0.11.0': - resolution: {integrity: sha512-SmdncQHLYtVNWLIMyGaY6LpAfamzTDe3fxjkirmJv3CWR5tcEyC6LMui/GsIVnJzXeNJBXAzwl8hTUAxHTM6kQ==} + '@nomicfoundation/edr-linux-x64-gnu@0.11.3': + resolution: {integrity: sha512-D/4cFKDXH6UYyKPu6J3Y8TzW11UzeQI0+wS9QcJzjlrrfKj0ENW7g9VihD1O2FvXkdkTjcCZYb6ai8MMTCsaVw==} engines: {node: '>= 18'} - '@nomicfoundation/edr-linux-x64-musl@0.11.0': - resolution: {integrity: sha512-w6hUqpn/trwiH6SRuRGysj37LsQVCX5XDCA3Xi81sbOaLhbHrNvK9TXWyZmcuzbdTKQQW6VNywcSxDdOiChcJg==} + '@nomicfoundation/edr-linux-x64-musl@0.11.3': + resolution: {integrity: sha512-ergXuIb4nIvmf+TqyiDX5tsE49311DrBky6+jNLgsGDTBaN1GS3OFwFS8I6Ri/GGn6xOaT8sKu3q7/m+WdlFzg==} engines: {node: '>= 18'} - '@nomicfoundation/edr-win32-x64-msvc@0.11.0': - resolution: {integrity: sha512-BLmULjRKoH9BsX+c4Na2ypV7NGeJ+M6Zpqj/faPOwleVscDdSr/IhriyPaXCe8dyfwbge7lWsbekiADtPSnB2Q==} + '@nomicfoundation/edr-win32-x64-msvc@0.11.3': + resolution: {integrity: sha512-snvEf+WB3OV0wj2A7kQ+ZQqBquMcrozSLXcdnMdEl7Tmn+KDCbmFKBt3Tk0X3qOU4RKQpLPnTxdM07TJNVtung==} engines: {node: '>= 18'} - '@nomicfoundation/edr@0.11.0': - resolution: {integrity: sha512-36WERf8ldvyHR6UAbcYsa+vpbW7tCrJGBwF4gXSsb8+STj1n66Hz85Y/O7B9+8AauX3PhglvV5dKl91tk43mWw==} + '@nomicfoundation/edr@0.11.3': + resolution: {integrity: sha512-kqILRkAd455Sd6v8mfP3C1/0tCOynJWY+Ir+k/9Boocu2kObCrsFgG+ZWB7fSBVdd9cPVSNrnhWS+V+PEo637g==} engines: {node: '>= 18'} '@nomicfoundation/solidity-analyzer-darwin-arm64@0.1.2': @@ -1262,8 +1320,8 @@ packages: resolution: {integrity: sha512-dL6atBH0zCZl1A1IXCKJgLPrM/wR7K+Wi401E/IvqsK8m2iCHW+0TEOGrans/cuN3oTW+uxIyJFHJ8Im0k4qBw==} engines: {node: '>=14.0.0'} - '@oclif/core@4.3.0': - resolution: {integrity: sha512-lIzHY+JMP6evrS5E/sGijNnwrCoNtGy8703jWXcMuPOYKiFhWoAqnIm1BGgoRgmxczkbSfRsHUL/lwsSgh74Lw==} + '@oclif/core@4.4.1': + resolution: {integrity: sha512-RYonV4IJZcGAoi3pdo5CPl5hVH1YdtQMEX77TLdgTPVrMmIjbiB0Borfguj/mdDF2TjLXp+Z+RbmLUejuhSYTA==} engines: {node: '>=18.0.0'} '@oclif/errors@1.3.6': @@ -1284,16 +1342,16 @@ packages: engines: {node: '>=8.0.0'} deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info. - '@oclif/plugin-autocomplete@3.2.28': - resolution: {integrity: sha512-6CaLO/SHMx1GVn8gAVGOZ3TPoj+hf88BvLTafp86MnNGxdYr5+YrSbh29py1j+ROIuUIj1KIodJB3yNTd0o6ow==} + '@oclif/plugin-autocomplete@3.2.32': + resolution: {integrity: sha512-j1+eoeJf6pf8WQD5U4PPCz+mlBqc9sfiRnBrcrh+wNd5zhL0cmjY4sWxpLBD+2OoQ/GnnRwoalDb0GyInakIow==} engines: {node: '>=18.0.0'} - '@oclif/plugin-help@6.2.28': - resolution: {integrity: sha512-eFLP2yjiK+xMRGcv9k9jOWV08HB+/Cgg1ND91zS4Uwgp1krMoL39Is+hIqnZOKkmiEMtiv8k5EDqCVv+DTRywg==} + '@oclif/plugin-help@6.2.30': + resolution: {integrity: sha512-D8qY2F0TYoM1MuLnaYEVo2MQVwdOKJtw7T9MqNrqn4Hh/9cjJxzKKgaesTdRrL5SxjgGBbqftirnje8rNyJ2Kw==} engines: {node: '>=18.0.0'} - '@oclif/plugin-plugins@5.4.37': - resolution: {integrity: sha512-sgpksPriMyXqhVUcV0v3YaEm6JxRma0DiLDTXjG+8u8LiQDvIW5qoLDSuEq3JYOTBueAxR5rM1hcUBfOnTVDZQ==} + '@oclif/plugin-plugins@5.4.44': + resolution: {integrity: sha512-jroNZjUph19Ns+bsMH33Yjof38LxNtVxT2JuYx6o2Rxuh8Q8CzgZcUqSthmw1sXT6gNJ5NRS8tJGlssdQ6b5jA==} engines: {node: '>=18.0.0'} '@openzeppelin/contracts@4.9.6': @@ -1308,12 +1366,23 @@ packages: '@paralleldrive/cuid2@2.2.2': resolution: {integrity: sha512-ZOBkgDwEdoYVlSeRbYYXs0S9MejQofiVYoTbKzy/6GQa39/q5tQU2IX46+shYnUkpEl3wc+J6wRlar7r2EK2xA==} + '@peculiar/asn1-schema@2.3.15': + resolution: {integrity: sha512-QPeD8UA8axQREpgR5UTAfu2mqQmm97oUqahDtNdBcfj3qAnoXzFdQW+aNf/tD2WVXF8Fhmftxoj0eMIT++gX2w==} + + '@peculiar/json-schema@1.1.12': + resolution: {integrity: sha512-coUfuoMeIB7B8/NMekxaDzLhaYmp0HZNPEjYRm9goRou8UZIC3z21s0sL9AWoCw4EG876QyO3kYrc61WNF9B/w==} + engines: {node: '>=8.0.0'} + + '@peculiar/webcrypto@1.5.0': + resolution: {integrity: sha512-BRs5XUAwiyCDQMsVA9IDvDa7UBR9gAvPHgugOeGng3YN6vJ9JYonyDc0lNczErgtCWtucjR5N7VtaonboD/ezg==} + engines: {node: '>=10.12.0'} + '@pkgjs/parseargs@0.11.0': resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} engines: {node: '>=14'} - '@pkgr/core@0.2.4': - resolution: {integrity: sha512-ROFF39F6ZrnzSUEmQQZUar0Jt4xVoP9WnDRdWwF4NNcXs3xBTLgBUDoOwW141y1jP+S8nahIbdxbFC7IShw9Iw==} + '@pkgr/core@0.2.7': + resolution: {integrity: sha512-YLT9Zo3oNPJoBjBc4q8G2mjU4tqIbf5CEOORbUUr48dCD9q3umJ3IPlVqOqDakPfd2HuwccBaqlGhN4Gmr5OWg==} engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} '@project-serum/anchor@0.11.1': @@ -1345,8 +1414,8 @@ packages: '@scure/base@1.1.9': resolution: {integrity: sha512-8YKhl8GHiNI/pU2VMaofa2Tor7PJRAjwQLBBuilkJ9L5+13yVbC7JO/wS7piioAvPSwR3JKM1IJ/u4xQzbcXKg==} - '@scure/base@1.2.5': - resolution: {integrity: sha512-9rE6EOVeIQzt5TSu4v+K523F8u6DhBsoZWPGKlnCshhlDhy0kJzUX4V+tr2dWmzF1GdekvThABoEQBGBQI7xZw==} + '@scure/base@1.2.6': + resolution: {integrity: sha512-g/nm5FgUa//MCj1gV09zTJTaM6KBAHqLN907YVQqf7zC49+DcO4B1so4ZX07Ef10Twr6nuqYEH9GEggFXA4Fmg==} '@scure/bip32@1.1.5': resolution: {integrity: sha512-XyNh1rB0SkEqd3tXcXMi+Xe1fvg+kUIcoRIEujP1Jgv7DqW2r9lg3Ah0NkFaCs9sTkQAQA8kw7xiRXzENi9Rtw==} @@ -1409,14 +1478,18 @@ packages: '@sinclair/typebox@0.33.22': resolution: {integrity: sha512-auUj4k+f4pyrIVf4GW5UKquSZFHJWri06QgARy9C0t9ZTjJLIuNIrr1yl9bWcJWJ1Gz1vOvYN1D+QPaIlNMVkQ==} + '@sindresorhus/is@4.6.0': + resolution: {integrity: sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==} + engines: {node: '>=10'} + '@sinonjs/commons@3.0.1': resolution: {integrity: sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==} '@sinonjs/fake-timers@10.3.0': resolution: {integrity: sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==} - '@smithy/abort-controller@4.0.2': - resolution: {integrity: sha512-Sl/78VDtgqKxN2+1qduaVE140XF+Xg+TafkncspwM4jFP/LHr76ZHmIY/y3V1M0mMLNk+Je6IGbzxy23RSToMw==} + '@smithy/abort-controller@4.0.4': + resolution: {integrity: sha512-gJnEjZMvigPDQWHrW3oPrFhQtkrgqBkyjj3pCIdF3A5M6vsZODG93KNlfJprv6bp4245bdT32fsHK4kkH3KYDA==} engines: {node: '>=18.0.0'} '@smithy/chunked-blob-reader-native@4.0.0': @@ -1427,56 +1500,56 @@ packages: resolution: {integrity: sha512-+sKqDBQqb036hh4NPaUiEkYFkTUGYzRsn3EuFhyfQfMy6oGHEUJDurLP9Ufb5dasr/XiAmPNMr6wa9afjQB+Gw==} engines: {node: '>=18.0.0'} - '@smithy/config-resolver@4.1.1': - resolution: {integrity: sha512-FZUtpiDnPZQmuIl4lfbdO+u3foNLmRCKct/2w2nRwgB99Yvaq4SHcfxyzMfxkyBrBmgnF1kdXzhHNXN7ycDvWg==} + '@smithy/config-resolver@4.1.4': + resolution: {integrity: sha512-prmU+rDddxHOH0oNcwemL+SwnzcG65sBF2yXRO7aeXIn/xTlq2pX7JLVbkBnVLowHLg4/OL4+jBmv9hVrVGS+w==} engines: {node: '>=18.0.0'} - '@smithy/core@3.3.1': - resolution: {integrity: sha512-W7AppgQD3fP1aBmo8wWo0id5zeR2/aYRy067vZsDVaa6v/mdhkg6DxXwEVuSPjZl+ZnvWAQbUMCd5ckw38+tHQ==} + '@smithy/core@3.6.0': + resolution: {integrity: sha512-Pgvfb+TQ4wUNLyHzvgCP4aYZMh16y7GcfF59oirRHcgGgkH1e/s9C0nv/v3WP+Quymyr5je71HeFQCwh+44XLg==} engines: {node: '>=18.0.0'} - '@smithy/credential-provider-imds@4.0.3': - resolution: {integrity: sha512-UdNvGjZnunS9+45gHYtVXDynoWH1X0tYY0pS368k1zUZum6Mm4ivU4Se0WhFJf8jNocD+p94khzTtrx4ha3OOQ==} + '@smithy/credential-provider-imds@4.0.6': + resolution: {integrity: sha512-hKMWcANhUiNbCJouYkZ9V3+/Qf9pteR1dnwgdyzR09R4ODEYx8BbUysHwRSyex4rZ9zapddZhLFTnT4ZijR4pw==} engines: {node: '>=18.0.0'} - '@smithy/eventstream-codec@4.0.2': - resolution: {integrity: sha512-p+f2kLSK7ZrXVfskU/f5dzksKTewZk8pJLPvER3aFHPt76C2MxD9vNatSfLzzQSQB4FNO96RK4PSXfhD1TTeMQ==} + '@smithy/eventstream-codec@4.0.4': + resolution: {integrity: sha512-7XoWfZqWb/QoR/rAU4VSi0mWnO2vu9/ltS6JZ5ZSZv0eovLVfDfu0/AX4ub33RsJTOth3TiFWSHS5YdztvFnig==} engines: {node: '>=18.0.0'} - '@smithy/eventstream-serde-browser@4.0.2': - resolution: {integrity: sha512-CepZCDs2xgVUtH7ZZ7oDdZFH8e6Y2zOv8iiX6RhndH69nlojCALSKK+OXwZUgOtUZEUaZ5e1hULVCHYbCn7pug==} + '@smithy/eventstream-serde-browser@4.0.4': + resolution: {integrity: sha512-3fb/9SYaYqbpy/z/H3yIi0bYKyAa89y6xPmIqwr2vQiUT2St+avRt8UKwsWt9fEdEasc5d/V+QjrviRaX1JRFA==} engines: {node: '>=18.0.0'} - '@smithy/eventstream-serde-config-resolver@4.1.0': - resolution: {integrity: sha512-1PI+WPZ5TWXrfj3CIoKyUycYynYJgZjuQo8U+sphneOtjsgrttYybdqESFReQrdWJ+LKt6NEdbYzmmfDBmjX2A==} + '@smithy/eventstream-serde-config-resolver@4.1.2': + resolution: {integrity: sha512-JGtambizrWP50xHgbzZI04IWU7LdI0nh/wGbqH3sJesYToMi2j/DcoElqyOcqEIG/D4tNyxgRuaqBXWE3zOFhQ==} engines: {node: '>=18.0.0'} - '@smithy/eventstream-serde-node@4.0.2': - resolution: {integrity: sha512-C5bJ/C6x9ENPMx2cFOirspnF9ZsBVnBMtP6BdPl/qYSuUawdGQ34Lq0dMcf42QTjUZgWGbUIZnz6+zLxJlb9aw==} + '@smithy/eventstream-serde-node@4.0.4': + resolution: {integrity: sha512-RD6UwNZ5zISpOWPuhVgRz60GkSIp0dy1fuZmj4RYmqLVRtejFqQ16WmfYDdoSoAjlp1LX+FnZo+/hkdmyyGZ1w==} engines: {node: '>=18.0.0'} - '@smithy/eventstream-serde-universal@4.0.2': - resolution: {integrity: sha512-St8h9JqzvnbB52FtckiHPN4U/cnXcarMniXRXTKn0r4b4XesZOGiAyUdj1aXbqqn1icSqBlzzUsCl6nPB018ng==} + '@smithy/eventstream-serde-universal@4.0.4': + resolution: {integrity: sha512-UeJpOmLGhq1SLox79QWw/0n2PFX+oPRE1ZyRMxPIaFEfCqWaqpB7BU9C8kpPOGEhLF7AwEqfFbtwNxGy4ReENA==} engines: {node: '>=18.0.0'} - '@smithy/fetch-http-handler@5.0.2': - resolution: {integrity: sha512-+9Dz8sakS9pe7f2cBocpJXdeVjMopUDLgZs1yWeu7h++WqSbjUYv/JAJwKwXw1HV6gq1jyWjxuyn24E2GhoEcQ==} + '@smithy/fetch-http-handler@5.0.4': + resolution: {integrity: sha512-AMtBR5pHppYMVD7z7G+OlHHAcgAN7v0kVKEpHuTO4Gb199Gowh0taYi9oDStFeUhetkeP55JLSVlTW1n9rFtUw==} engines: {node: '>=18.0.0'} - '@smithy/hash-blob-browser@4.0.2': - resolution: {integrity: sha512-3g188Z3DyhtzfBRxpZjU8R9PpOQuYsbNnyStc/ZVS+9nVX1f6XeNOa9IrAh35HwwIZg+XWk8bFVtNINVscBP+g==} + '@smithy/hash-blob-browser@4.0.4': + resolution: {integrity: sha512-WszRiACJiQV3QG6XMV44i5YWlkrlsM5Yxgz4jvsksuu7LDXA6wAtypfPajtNTadzpJy3KyJPoWehYpmZGKUFIQ==} engines: {node: '>=18.0.0'} - '@smithy/hash-node@4.0.2': - resolution: {integrity: sha512-VnTpYPnRUE7yVhWozFdlxcYknv9UN7CeOqSrMH+V877v4oqtVYuoqhIhtSjmGPvYrYnAkaM61sLMKHvxL138yg==} + '@smithy/hash-node@4.0.4': + resolution: {integrity: sha512-qnbTPUhCVnCgBp4z4BUJUhOEkVwxiEi1cyFM+Zj6o+aY8OFGxUQleKWq8ltgp3dujuhXojIvJWdoqpm6dVO3lQ==} engines: {node: '>=18.0.0'} - '@smithy/hash-stream-node@4.0.2': - resolution: {integrity: sha512-POWDuTznzbIwlEXEvvXoPMS10y0WKXK790soe57tFRfvf4zBHyzE529HpZMqmDdwG9MfFflnyzndUQ8j78ZdSg==} + '@smithy/hash-stream-node@4.0.4': + resolution: {integrity: sha512-wHo0d8GXyVmpmMh/qOR0R7Y46/G1y6OR8U+bSTB4ppEzRxd1xVAQ9xOE9hOc0bSjhz0ujCPAbfNLkLrpa6cevg==} engines: {node: '>=18.0.0'} - '@smithy/invalid-dependency@4.0.2': - resolution: {integrity: sha512-GatB4+2DTpgWPday+mnUkoumP54u/MDM/5u44KF9hIu8jF0uafZtQLcdfIKkIcUNuF/fBojpLEHZS/56JqPeXQ==} + '@smithy/invalid-dependency@4.0.4': + resolution: {integrity: sha512-bNYMi7WKTJHu0gn26wg8OscncTt1t2b8KcsZxvOv56XA6cyXtOAAAaNP7+m45xfppXfOatXF3Sb1MNsLUgVLTw==} engines: {node: '>=18.0.0'} '@smithy/is-array-buffer@2.2.0': @@ -1487,76 +1560,76 @@ packages: resolution: {integrity: sha512-saYhF8ZZNoJDTvJBEWgeBccCg+yvp1CX+ed12yORU3NilJScfc6gfch2oVb4QgxZrGUx3/ZJlb+c/dJbyupxlw==} engines: {node: '>=18.0.0'} - '@smithy/md5-js@4.0.2': - resolution: {integrity: sha512-Hc0R8EiuVunUewCse2syVgA2AfSRco3LyAv07B/zCOMa+jpXI9ll+Q21Nc6FAlYPcpNcAXqBzMhNs1CD/pP2bA==} + '@smithy/md5-js@4.0.4': + resolution: {integrity: sha512-uGLBVqcOwrLvGh/v/jw423yWHq/ofUGK1W31M2TNspLQbUV1Va0F5kTxtirkoHawODAZcjXTSGi7JwbnPcDPJg==} engines: {node: '>=18.0.0'} - '@smithy/middleware-content-length@4.0.2': - resolution: {integrity: sha512-hAfEXm1zU+ELvucxqQ7I8SszwQ4znWMbNv6PLMndN83JJN41EPuS93AIyh2N+gJ6x8QFhzSO6b7q2e6oClDI8A==} + '@smithy/middleware-content-length@4.0.4': + resolution: {integrity: sha512-F7gDyfI2BB1Kc+4M6rpuOLne5LOcEknH1n6UQB69qv+HucXBR1rkzXBnQTB2q46sFy1PM/zuSJOB532yc8bg3w==} engines: {node: '>=18.0.0'} - '@smithy/middleware-endpoint@4.1.3': - resolution: {integrity: sha512-w7fJjCSqdTVTs1o1O7SRZm+Umf6r/FzkdlO5OH6tboASeUeugnMgQAs7gnc2dXvJVJtEGrmrBgPZFPxq3wWyzw==} + '@smithy/middleware-endpoint@4.1.13': + resolution: {integrity: sha512-xg3EHV/Q5ZdAO5b0UiIMj3RIOCobuS40pBBODguUDVdko6YK6QIzCVRrHTogVuEKglBWqWenRnZ71iZnLL3ZAQ==} engines: {node: '>=18.0.0'} - '@smithy/middleware-retry@4.1.4': - resolution: {integrity: sha512-QtWuD7bd7AAEFKvBmLQdOax25bXv4BACLQNWi3ddvpWwUUSAkAku9mzI+28jbjg48qw28lbzJ+YoYbbaXhLUjw==} + '@smithy/middleware-retry@4.1.14': + resolution: {integrity: sha512-eoXaLlDGpKvdmvt+YBfRXE7HmIEtFF+DJCbTPwuLunP0YUnrydl+C4tS+vEM0+nyxXrX3PSUFqC+lP1+EHB1Tw==} engines: {node: '>=18.0.0'} - '@smithy/middleware-serde@4.0.3': - resolution: {integrity: sha512-rfgDVrgLEVMmMn0BI8O+8OVr6vXzjV7HZj57l0QxslhzbvVfikZbVfBVthjLHqib4BW44QhcIgJpvebHlRaC9A==} + '@smithy/middleware-serde@4.0.8': + resolution: {integrity: sha512-iSSl7HJoJaGyMIoNn2B7czghOVwJ9nD7TMvLhMWeSB5vt0TnEYyRRqPJu/TqW76WScaNvYYB8nRoiBHR9S1Ddw==} engines: {node: '>=18.0.0'} - '@smithy/middleware-stack@4.0.2': - resolution: {integrity: sha512-eSPVcuJJGVYrFYu2hEq8g8WWdJav3sdrI4o2c6z/rjnYDd3xH9j9E7deZQCzFn4QvGPouLngH3dQ+QVTxv5bOQ==} + '@smithy/middleware-stack@4.0.4': + resolution: {integrity: sha512-kagK5ggDrBUCCzI93ft6DjteNSfY8Ulr83UtySog/h09lTIOAJ/xUSObutanlPT0nhoHAkpmW9V5K8oPyLh+QA==} engines: {node: '>=18.0.0'} - '@smithy/node-config-provider@4.1.0': - resolution: {integrity: sha512-gmPsv6L3ZRlBinv+vtSGUwfhTMh4+SgjbgGdX7bqYEs3Ys5RYVQtLuZ/WgZZdxn8QrDSUqLmTWunLM96WyM7UQ==} + '@smithy/node-config-provider@4.1.3': + resolution: {integrity: sha512-HGHQr2s59qaU1lrVH6MbLlmOBxadtzTsoO4c+bF5asdgVik3I8o7JIOzoeqWc5MjVa+vD36/LWE0iXKpNqooRw==} engines: {node: '>=18.0.0'} - '@smithy/node-http-handler@4.0.4': - resolution: {integrity: sha512-/mdqabuAT3o/ihBGjL94PUbTSPSRJ0eeVTdgADzow0wRJ0rN4A27EOrtlK56MYiO1fDvlO3jVTCxQtQmK9dZ1g==} + '@smithy/node-http-handler@4.0.6': + resolution: {integrity: sha512-NqbmSz7AW2rvw4kXhKGrYTiJVDHnMsFnX4i+/FzcZAfbOBauPYs2ekuECkSbtqaxETLLTu9Rl/ex6+I2BKErPA==} engines: {node: '>=18.0.0'} - '@smithy/property-provider@4.0.2': - resolution: {integrity: sha512-wNRoQC1uISOuNc2s4hkOYwYllmiyrvVXWMtq+TysNRVQaHm4yoafYQyjN/goYZS+QbYlPIbb/QRjaUZMuzwQ7A==} + '@smithy/property-provider@4.0.4': + resolution: {integrity: sha512-qHJ2sSgu4FqF4U/5UUp4DhXNmdTrgmoAai6oQiM+c5RZ/sbDwJ12qxB1M6FnP+Tn/ggkPZf9ccn4jqKSINaquw==} engines: {node: '>=18.0.0'} - '@smithy/protocol-http@5.1.0': - resolution: {integrity: sha512-KxAOL1nUNw2JTYrtviRRjEnykIDhxc84qMBzxvu1MUfQfHTuBlCG7PA6EdVwqpJjH7glw7FqQoFxUJSyBQgu7g==} + '@smithy/protocol-http@5.1.2': + resolution: {integrity: sha512-rOG5cNLBXovxIrICSBm95dLqzfvxjEmuZx4KK3hWwPFHGdW3lxY0fZNXfv2zebfRO7sJZ5pKJYHScsqopeIWtQ==} engines: {node: '>=18.0.0'} - '@smithy/querystring-builder@4.0.2': - resolution: {integrity: sha512-NTOs0FwHw1vimmQM4ebh+wFQvOwkEf/kQL6bSM1Lock+Bv4I89B3hGYoUEPkmvYPkDKyp5UdXJYu+PoTQ3T31Q==} + '@smithy/querystring-builder@4.0.4': + resolution: {integrity: sha512-SwREZcDnEYoh9tLNgMbpop+UTGq44Hl9tdj3rf+yeLcfH7+J8OXEBaMc2kDxtyRHu8BhSg9ADEx0gFHvpJgU8w==} engines: {node: '>=18.0.0'} - '@smithy/querystring-parser@4.0.2': - resolution: {integrity: sha512-v6w8wnmZcVXjfVLjxw8qF7OwESD9wnpjp0Dqry/Pod0/5vcEA3qxCr+BhbOHlxS8O+29eLpT3aagxXGwIoEk7Q==} + '@smithy/querystring-parser@4.0.4': + resolution: {integrity: sha512-6yZf53i/qB8gRHH/l2ZwUG5xgkPgQF15/KxH0DdXMDHjesA9MeZje/853ifkSY0x4m5S+dfDZ+c4x439PF0M2w==} engines: {node: '>=18.0.0'} - '@smithy/service-error-classification@4.0.3': - resolution: {integrity: sha512-FTbcajmltovWMjj3tksDQdD23b2w6gH+A0DYA1Yz3iSpjDj8fmkwy62UnXcWMy4d5YoMoSyLFHMfkEVEzbiN8Q==} + '@smithy/service-error-classification@4.0.6': + resolution: {integrity: sha512-RRoTDL//7xi4tn5FrN2NzH17jbgmnKidUqd4KvquT0954/i6CXXkh1884jBiunq24g9cGtPBEXlU40W6EpNOOg==} engines: {node: '>=18.0.0'} - '@smithy/shared-ini-file-loader@4.0.2': - resolution: {integrity: sha512-J9/gTWBGVuFZ01oVA6vdb4DAjf1XbDhK6sLsu3OS9qmLrS6KB5ygpeHiM3miIbj1qgSJ96GYszXFWv6ErJ8QEw==} + '@smithy/shared-ini-file-loader@4.0.4': + resolution: {integrity: sha512-63X0260LoFBjrHifPDs+nM9tV0VMkOTl4JRMYNuKh/f5PauSjowTfvF3LogfkWdcPoxsA9UjqEOgjeYIbhb7Nw==} engines: {node: '>=18.0.0'} - '@smithy/signature-v4@5.1.0': - resolution: {integrity: sha512-4t5WX60sL3zGJF/CtZsUQTs3UrZEDO2P7pEaElrekbLqkWPYkgqNW1oeiNYC6xXifBnT9dVBOnNQRvOE9riU9w==} + '@smithy/signature-v4@5.1.2': + resolution: {integrity: sha512-d3+U/VpX7a60seHziWnVZOHuEgJlclufjkS6zhXvxcJgkJq4UWdH5eOBLzHRMx6gXjsdT9h6lfpmLzbrdupHgQ==} engines: {node: '>=18.0.0'} - '@smithy/smithy-client@4.2.3': - resolution: {integrity: sha512-j/RRx6N007rJQ3qyjN4yuX9B0bxTn9ynDVxYQ43mcs7fluVJXmQGquy0TrWJfOPZcIikpY377GunZ2UK90GHYQ==} + '@smithy/smithy-client@4.4.5': + resolution: {integrity: sha512-+lynZjGuUFJaMdDYSTMnP/uPBBXXukVfrJlP+1U/Dp5SFTEI++w6NMga8DjOENxecOF71V9Z2DllaVDYRnGlkg==} engines: {node: '>=18.0.0'} - '@smithy/types@4.2.0': - resolution: {integrity: sha512-7eMk09zQKCO+E/ivsjQv+fDlOupcFUCSC/L2YUPgwhvowVGWbPQHjEFcmjt7QQ4ra5lyowS92SV53Zc6XD4+fg==} + '@smithy/types@4.3.1': + resolution: {integrity: sha512-UqKOQBL2x6+HWl3P+3QqFD4ncKq0I8Nuz9QItGv5WuKuMHuuwlhvqcZCoXGfc+P1QmfJE7VieykoYYmrOoFJxA==} engines: {node: '>=18.0.0'} - '@smithy/url-parser@4.0.2': - resolution: {integrity: sha512-Bm8n3j2ScqnT+kJaClSVCMeiSenK6jVAzZCNewsYWuZtnBehEz4r2qP0riZySZVfzB+03XZHJeqfmJDkeeSLiQ==} + '@smithy/url-parser@4.0.4': + resolution: {integrity: sha512-eMkc144MuN7B0TDA4U2fKs+BqczVbk3W+qIvcoCY6D1JY3hnAdCuhCZODC+GAeaxj0p6Jroz4+XMUn3PCxQQeQ==} engines: {node: '>=18.0.0'} '@smithy/util-base64@4.0.0': @@ -1583,32 +1656,32 @@ packages: resolution: {integrity: sha512-L1RBVzLyfE8OXH+1hsJ8p+acNUSirQnWQ6/EgpchV88G6zGBTDPdXiiExei6Z1wR2RxYvxY/XLw6AMNCCt8H3w==} engines: {node: '>=18.0.0'} - '@smithy/util-defaults-mode-browser@4.0.11': - resolution: {integrity: sha512-Z49QNUSKbEj7JVZqaSUZkTkexRciQBbmonJ8AMar4fA0S2kvVpgjeVyGXnZYWTFzkgEwStacjFq4cQKbaQ8AnQ==} + '@smithy/util-defaults-mode-browser@4.0.21': + resolution: {integrity: sha512-wM0jhTytgXu3wzJoIqpbBAG5U6BwiubZ6QKzSbP7/VbmF1v96xlAbX2Am/mz0Zep0NLvLh84JT0tuZnk3wmYQA==} engines: {node: '>=18.0.0'} - '@smithy/util-defaults-mode-node@4.0.11': - resolution: {integrity: sha512-y9UYcXjz4ry5sDPX40Vy6224Cw2/dch+wET6giaRoeXpyh56DCUVxW+Mgc/gO2uczAKktWd4ZWs2LWcW+PHz3Q==} + '@smithy/util-defaults-mode-node@4.0.21': + resolution: {integrity: sha512-/F34zkoU0GzpUgLJydHY8Rxu9lBn8xQC/s/0M0U9lLBkYbA1htaAFjWYJzpzsbXPuri5D1H8gjp2jBum05qBrA==} engines: {node: '>=18.0.0'} - '@smithy/util-endpoints@3.0.3': - resolution: {integrity: sha512-284PZFhCMdudqq61/E67zJ3i10gCYrMBjXcMg3h048qI39gTXQCCeNZvtJhL4vrj9yMpJ/y9M+Ek7V0o5tak3w==} + '@smithy/util-endpoints@3.0.6': + resolution: {integrity: sha512-YARl3tFL3WgPuLzljRUnrS2ngLiUtkwhQtj8PAL13XZSyUiNLQxwG3fBBq3QXFqGFUXepIN73pINp3y8c2nBmA==} engines: {node: '>=18.0.0'} '@smithy/util-hex-encoding@4.0.0': resolution: {integrity: sha512-Yk5mLhHtfIgW2W2WQZWSg5kuMZCVbvhFmC7rV4IO2QqnZdbEFPmQnCcGMAX2z/8Qj3B9hYYNjZOhWym+RwhePw==} engines: {node: '>=18.0.0'} - '@smithy/util-middleware@4.0.2': - resolution: {integrity: sha512-6GDamTGLuBQVAEuQ4yDQ+ti/YINf/MEmIegrEeg7DdB/sld8BX1lqt9RRuIcABOhAGTA50bRbPzErez7SlDtDQ==} + '@smithy/util-middleware@4.0.4': + resolution: {integrity: sha512-9MLKmkBmf4PRb0ONJikCbCwORACcil6gUWojwARCClT7RmLzF04hUR4WdRprIXal7XVyrddadYNfp2eF3nrvtQ==} engines: {node: '>=18.0.0'} - '@smithy/util-retry@4.0.3': - resolution: {integrity: sha512-DPuYjZQDXmKr/sNvy9Spu8R/ESa2e22wXZzSAY6NkjOLj6spbIje/Aq8rT97iUMdDj0qHMRIe+bTxvlU74d9Ng==} + '@smithy/util-retry@4.0.6': + resolution: {integrity: sha512-+YekoF2CaSMv6zKrA6iI/N9yva3Gzn4L6n35Luydweu5MMPYpiGZlWqehPHDHyNbnyaYlz/WJyYAZnC+loBDZg==} engines: {node: '>=18.0.0'} - '@smithy/util-stream@4.2.0': - resolution: {integrity: sha512-Vj1TtwWnuWqdgQI6YTUF5hQ/0jmFiOYsc51CSMgj7QfyO+RF4EnT2HNjoviNlOOmgzgvf3f5yno+EiC4vrnaWQ==} + '@smithy/util-stream@4.2.2': + resolution: {integrity: sha512-aI+GLi7MJoVxg24/3J1ipwLoYzgkB4kUfogZfnslcYlynj3xsQ0e7vk4TnTro9hhsS5PvX1mwmkRqqHQjwcU7w==} engines: {node: '>=18.0.0'} '@smithy/util-uri-escape@4.0.0': @@ -1623,8 +1696,8 @@ packages: resolution: {integrity: sha512-b+zebfKCfRdgNJDknHCob3O7FpeYQN6ZG6YLExMcasDHsCXlsXCEuiPZeLnJLpwa5dvPetGlnGCiMHuLwGvFow==} engines: {node: '>=18.0.0'} - '@smithy/util-waiter@4.0.3': - resolution: {integrity: sha512-JtaY3FxmD+te+KSI2FJuEcfNC9T/DGGVf551babM7fAaXhjJUt7oSYurH1Devxd2+BOSUACCgt3buinx4UnmEA==} + '@smithy/util-waiter@4.0.6': + resolution: {integrity: sha512-slcr1wdRbX7NFphXZOxtxRNA7hXAAtJAXJDE/wdoMAos27SIquVCKiSqfB6/28YzQ8FCsB5NKkhdM5gMADbqxg==} engines: {node: '>=18.0.0'} '@solana/buffer-layout-utils@0.2.0': @@ -1645,11 +1718,11 @@ packages: peerDependencies: typescript: '>=5' - '@solana/codecs-core@2.1.0': - resolution: {integrity: sha512-SR7pKtmJBg2mhmkel2NeHA1pz06QeQXdMv8WJoIR9m8F/hw80K/612uaYbwTt2nkK0jg/Qn/rNSd7EcJ4SBGjw==} + '@solana/codecs-core@2.1.1': + resolution: {integrity: sha512-iPQW3UZ2Vi7QFBo2r9tw0NubtH8EdrhhmZulx6lC8V5a+qjaxovtM/q/UW2BTNpqqHLfO0tIcLyBLrNH4HTWPg==} engines: {node: '>=20.18.0'} peerDependencies: - typescript: '>=5' + typescript: '>=5.3.3' '@solana/codecs-data-structures@2.0.0-preview.4': resolution: {integrity: sha512-nt2k2eTeyzlI/ccutPcG36M/J8NAYfxBPI9h/nQjgJ+M+IgOKi31JV8StDDlG/1XvY0zyqugV3I0r3KAbZRJpA==} @@ -1671,11 +1744,11 @@ packages: peerDependencies: typescript: '>=5' - '@solana/codecs-numbers@2.1.0': - resolution: {integrity: sha512-XMu4yw5iCgQnMKsxSWPPOrGgtaohmupN3eyAtYv3K3C/MJEc5V90h74k5B1GUCiHvcrdUDO9RclNjD9lgbjFag==} + '@solana/codecs-numbers@2.1.1': + resolution: {integrity: sha512-m20IUPJhPUmPkHSlZ2iMAjJ7PaYUvlMtFhCQYzm9BEBSI6OCvXTG3GAPpAnSGRBfg5y+QNqqmKn4QHU3B6zzCQ==} engines: {node: '>=20.18.0'} peerDependencies: - typescript: '>=5' + typescript: '>=5.3.3' '@solana/codecs-strings@2.0.0-preview.4': resolution: {integrity: sha512-YDbsQePRWm+xnrfS64losSGRg8Wb76cjK1K6qfR8LPmdwIC3787x9uW5/E4icl/k+9nwgbIRXZ65lpF+ucZUnw==} @@ -1711,12 +1784,12 @@ packages: peerDependencies: typescript: '>=5' - '@solana/errors@2.1.0': - resolution: {integrity: sha512-l+GxAv0Ar4d3c3PlZdA9G++wFYZREEbbRyAFP8+n8HSg0vudCuzogh/13io6hYuUhG/9Ve8ARZNamhV7UScKNw==} + '@solana/errors@2.1.1': + resolution: {integrity: sha512-sj6DaWNbSJFvLzT8UZoabMefQUfSW/8tXK7NTiagsDmh+Q87eyQDDC9L3z+mNmx9b6dEf6z660MOIplDD2nfEw==} engines: {node: '>=20.18.0'} hasBin: true peerDependencies: - typescript: '>=5' + typescript: '>=5.3.3' '@solana/options@2.0.0-preview.4': resolution: {integrity: sha512-tv2O/Frxql/wSe3jbzi5nVicIWIus/BftH+5ZR+r9r3FO0/htEllZS5Q9XdbmSboHu+St87584JXeDx3xm4jaA==} @@ -1768,8 +1841,8 @@ packages: resolution: {integrity: sha512-JBMGB0oR4lPttOZ5XiUGyvylwLQjt1CPJa6qQ5oM+MBCndfjz2TKKkw0eATlLLcYmq1jBVsNlJ2cD6ns2GR7lA==} engines: {node: '>=16'} - '@solana/wallet-adapter-base@0.9.26': - resolution: {integrity: sha512-1RcmfesJ8bTT+zfg4w+Z+wisj11HR+vWwl/pS6v/zwQPe0LSzWDpkXRv9JuDSCuTcmlglEfjEqFAW+5EubK/Jg==} + '@solana/wallet-adapter-base@0.9.27': + resolution: {integrity: sha512-kXjeNfNFVs/NE9GPmysBRKQ/nf+foSaq3kfVSeMcO/iVgigyRmB551OjU3WyAolLG/1jeEfKLqF9fKwMCRkUqg==} engines: {node: '>=20'} peerDependencies: '@solana/web3.js': ^1.98.0 @@ -1786,6 +1859,22 @@ packages: peerDependencies: '@solana/web3.js': '*' + '@sundaeswap/asset@1.0.10': + resolution: {integrity: sha512-/NK5BX43ybJqQL1rCOu80h80Vdia83uvqPkfhG2I/EqQ6UrsKfAUdD0GdRfkGWuPMG/V/tXlX12p7xCXF5V5lw==} + + '@sundaeswap/bigint-math@0.6.3': + resolution: {integrity: sha512-FTXBd8F9LAvZsTZII7SBbZTEnjJc4JOSHp0XM+byAMsIDXglrYKotZT8z4QnYBxq1EcuhONsKdutibTfst4sgg==} + + '@sundaeswap/cpp@1.0.11': + resolution: {integrity: sha512-H5ZbPYY09fdyi5hqPalfVcOws9iAxWVgEDmNRBOxdDmPfhhf2V0GOq1X5XqMGYasAMw5yQgx1y2JZgep6+p32A==} + peerDependencies: + '@sundaeswap/asset': ^1.0.0 + '@sundaeswap/bigint-math': ^0.6.0 + '@sundaeswap/fraction': ^1.0.0 + + '@sundaeswap/fraction@1.0.7': + resolution: {integrity: sha512-/baQAGDLCFbdWTyEkDEyUHS2UKNf06VltHy5paan53xcagI+9+6HGrGc4/RHDYsDEYu0uPLFWyx97t2OuHVlCw==} + '@supercharge/promise-pool@2.4.0': resolution: {integrity: sha512-O9CMipBlq5OObdt1uKJGIzm9cdjpPWfj+a+Zw9EgWKxaMNHKC7EU7X9taj3H0EGQNLOSq2jAcOa3EzxlfHsD6w==} engines: {node: '>=8'} @@ -1793,6 +1882,10 @@ packages: '@swc/helpers@0.5.17': resolution: {integrity: sha512-5IKx/Y13RsYd+sauPb2x+U/xZikHjolzfuDgTAl/Tdf3Q8rslRvC19NKDLgAJQ6wsqADk10ntlv08nPFw/gO/A==} + '@szmarczak/http-timer@4.0.6': + resolution: {integrity: sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==} + engines: {node: '>=10'} + '@tsconfig/node10@1.0.11': resolution: {integrity: sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==} @@ -1826,8 +1919,8 @@ packages: '@types/bn.js@5.1.6': resolution: {integrity: sha512-Xh8vSwUeMKeYYrj3cX4lGQgFSF/N03r+tv4AiLl1SucqV+uTQpxRcnM8AkXKHwYP9ZPXOYXRr2KPXpVlIvqh9w==} - '@types/body-parser@1.19.5': - resolution: {integrity: sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==} + '@types/body-parser@1.19.6': + resolution: {integrity: sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g==} '@types/brotli@1.3.4': resolution: {integrity: sha512-cKYjgaS2DMdCKF7R0F5cgx1nfBYObN2ihIuPGQ4/dlIY6RpV7OWNwe9L8V4tTVKL2eZqOkNM9FM/rgTvLf4oXw==} @@ -1835,6 +1928,9 @@ packages: '@types/bs58@4.0.4': resolution: {integrity: sha512-0IEpMFXXQi2zXaXl9GJ3sRwQo0uEkD+yFOv+FnAU5lkPtcu6h61xb7jc2CFPEZ5BUOaiP13ThuGc9HD4R8lR5g==} + '@types/cacheable-request@6.0.3': + resolution: {integrity: sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw==} + '@types/cli-progress@3.11.6': resolution: {integrity: sha512-cE3+jb9WRlu+uOSAugewNpITJDt1VF8dHOopPO4IABFc3SXYL5WE/+PTz/FCdZRRfIujiWW3n3aMbv1eIGVRWA==} @@ -1850,8 +1946,8 @@ packages: '@types/express-serve-static-core@4.19.6': resolution: {integrity: sha512-N4LZ2xG7DatVqhCZzOGb1Yi5lMbXSZcmdLDe9EzSndPV2HpWYWzRbaerl2n27irrm94EPpprqa8KpskPT085+A==} - '@types/express@4.17.21': - resolution: {integrity: sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==} + '@types/express@4.17.23': + resolution: {integrity: sha512-Crp6WY9aTYP3qPi2wGDo9iUe/rceX01UMhnF1jmwDcKCFM6cx7YhGP/Mpr3y9AASpfHixIG0E6azCcL5OcDHsQ==} '@types/fs-extra@9.0.13': resolution: {integrity: sha512-nEnwB++1u5lVDM2UI4c1+5R+FYaKfaAzS4OococimjVm3nQw3TuzH5UNsocrcTBbhnerblyHj4A49qXbIiZdpA==} @@ -1859,8 +1955,11 @@ packages: '@types/graceful-fs@4.1.9': resolution: {integrity: sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==} - '@types/http-errors@2.0.4': - resolution: {integrity: sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==} + '@types/http-cache-semantics@4.0.4': + resolution: {integrity: sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA==} + + '@types/http-errors@2.0.5': + resolution: {integrity: sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg==} '@types/istanbul-lib-coverage@2.0.6': resolution: {integrity: sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==} @@ -1883,6 +1982,9 @@ packages: '@types/json5@0.0.29': resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} + '@types/keyv@3.1.4': + resolution: {integrity: sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==} + '@types/level-codec@9.0.4': resolution: {integrity: sha512-N6v5EhpvF00Wv+1ixzqca9YD2wdK76JceSnUoiKfQh/vex+VFG852wzqohnlYf67nzKQoXeRzYd8W57fIkYCvg==} @@ -1926,20 +2028,23 @@ packages: '@types/pbkdf2@3.1.2': resolution: {integrity: sha512-uRwJqmiXmh9++aSu1VNEn3iIxWOhd8AHXNSdlaLfdAAdSTY9jYVeGWnzejM3dvrkbqE3/hyQkQQ29IFATEGlew==} - '@types/qs@6.9.18': - resolution: {integrity: sha512-kK7dgTYDyGqS+e2Q4aK9X3D7q234CIZ1Bv0q/7Z5IwRDoADNU81xXJK/YVyLbLTZCoIwUoDoffFeF+p/eIklAA==} + '@types/qs@6.14.0': + resolution: {integrity: sha512-eOunJqu0K1923aExK6y8p6fsihYEn/BYuQ4g0CxAAgFc4b/ZLN4CrsRZ55srTdqoiLzU2B2evC+apEIxprEzkQ==} '@types/range-parser@1.2.7': resolution: {integrity: sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==} + '@types/responselike@1.0.3': + resolution: {integrity: sha512-H/+L+UkTV33uf49PH5pCAUBVPNj2nDBXTN+qS1dOwyyg24l3CcicicCA7ca+HMvJBZcFgl5r8e+RR6elsb4Lyw==} + '@types/secp256k1@4.0.6': resolution: {integrity: sha512-hHxJU6PAEUn0TP4S/ZOzuTUvJWuZ6eIKeNKb5RBpODvSl6hp1Wrw4s7ATY50rklRCScUDpHzVA/DQdSjJ3UoYQ==} - '@types/send@0.17.4': - resolution: {integrity: sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==} + '@types/send@0.17.5': + resolution: {integrity: sha512-z6F2D3cOStZvuk2SaP6YrwkNO65iTZcwA2ZkSABegdkAh/lf+Aa/YQndZVfmEXT5vgAp6zv06VQ3ejSVjAny4w==} - '@types/serve-static@1.15.7': - resolution: {integrity: sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw==} + '@types/serve-static@1.15.8': + resolution: {integrity: sha512-roei0UY3LhpOJvjbIP6ZZFngyLKl5dskOtDhxY5THRSpO+ZI+nzJ+m5yUMzGrp89YRa7lvknKkMYjqQFGwA7Sg==} '@types/stack-utils@1.0.1': resolution: {integrity: sha512-l42BggppR6zLmpfU6fq9HEa2oGPEI8yrSPL3GITjfRInppYFahObbIQOQK3UGxEnyQpltZLaPe75046NOZQikw==} @@ -1959,6 +2064,9 @@ packages: '@types/uuid@8.3.4': resolution: {integrity: sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw==} + '@types/uuid@9.0.8': + resolution: {integrity: sha512-jg+97EGIcY9AGHJJRaaPVgetKDsrTgbRjQ5Msgjh/DQKEFl0DtyRr/VCOyD1T2R1MNeWPK/u7JoGhlDZnKBAfA==} + '@types/ws@7.4.7': resolution: {integrity: sha512-JQbbmxZTZehdc2iszGKs5oC3NFnjeay7mtAWrdt7qNtAVK0g19muApzAy4bm9byz79xa2ZnO/BOBC2R8RC5Lww==} @@ -2178,8 +2286,8 @@ packages: resolution: {integrity: sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==} engines: {node: '>=0.4.0'} - acorn@8.14.1: - resolution: {integrity: sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==} + acorn@8.15.0: + resolution: {integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==} engines: {node: '>=0.4.0'} hasBin: true @@ -2335,8 +2443,8 @@ packages: array-flatten@1.1.1: resolution: {integrity: sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==} - array-includes@3.1.8: - resolution: {integrity: sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==} + array-includes@3.1.9: + resolution: {integrity: sha512-FmeCCAenzH0KH381SPT5FZmiA/TmpndpcaShhfgEN9eCVjnFBqq3l1xrI42y8+PPLI6hypzou4GXw00WHmPBLQ==} engines: {node: '>= 0.4'} array-union@2.1.0: @@ -2378,6 +2486,10 @@ packages: asn1.js@5.4.1: resolution: {integrity: sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==} + asn1js@3.0.6: + resolution: {integrity: sha512-UOCGPYbl0tv8+006qks/dTgV9ajs97X2p0FAbyS2iyCRrmLSRolDaHdp+v/CLgnzHc3fVB+CwYiUmei7ndFcgA==} + engines: {node: '>=12.0.0'} + assert@2.1.0: resolution: {integrity: sha512-eLHpSK/Y4nhMJ07gDaAzoX/XAKS8PSaojml3M0DM4JpV1LAi5JOJ/p6H/XWrl8L+DzVEvVCW1z3vWAaB9oTsQw==} @@ -2439,8 +2551,8 @@ packages: axios@0.27.2: resolution: {integrity: sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==} - axios@1.9.0: - resolution: {integrity: sha512-re4CqKTJaURpzbLHtIi6XpDv20/CnpXOtjRY5/CU32L8gU8ek9UIivcfvSWvmKEngmVbrUtPpdDwWDWL7DNHvg==} + axios@1.10.0: + resolution: {integrity: sha512-/1xYAC4MP/HEG+3duIhFr4ZQXR4sQXOIe+o6sdqzeykGLx6Upp/1p8MHqhINOvGeP7xyNHe7tsiJByc4SSVUxw==} babel-jest@29.7.0: resolution: {integrity: sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==} @@ -2493,6 +2605,9 @@ packages: bech32@1.1.4: resolution: {integrity: sha512-s0IrSOzLlbvX7yp4WBfPITzpAU8sqQcpsmwXDiKwrG4r491vwCO/XpejasRNl0piBMe/DvP4Tz0mIS/X1DPJBQ==} + bech32@2.0.0: + resolution: {integrity: sha512-LcknSilhIGatDAsY1ak2I8VtGaHNhgMSYVxFrGLXv+xLHytaKZKcaUJJUE7qmBr7h33o5YQwP55pMI0xmkpJwg==} + big.js@5.2.2: resolution: {integrity: sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==} @@ -2522,6 +2637,12 @@ packages: bl@4.1.0: resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} + blake2b-wasm@1.1.7: + resolution: {integrity: sha512-oFIHvXhlz/DUgF0kq5B1CqxIDjIJwh9iDeUUGQUcvgiGz7Wdw03McEO7CfLBy7QKGdsydcMCgO9jFNBAFCtFcA==} + + blake2b@2.1.3: + resolution: {integrity: sha512-pkDss4xFVbMb4270aCyGD3qLv92314Et+FsKzilCLxDz5DuZ2/1g3w4nmBbu6nKApPspnjG7JcwTjGZnduB1yg==} + blakejs@1.2.1: resolution: {integrity: sha512-QXUSXI3QVc/gJME0dBpXrag1kbzOqCjCX8/b54ntNyW6sjtoqxqRk3LTmXzaJoh71zMsDCjM+47jS7XiwN/+fQ==} @@ -2541,6 +2662,9 @@ packages: borsh@0.7.0: resolution: {integrity: sha512-CLCsZGIBCFnPtkNnieW/a8wmreDmfUtjU2m9yHrzPXIlNbqVs0AQrSatSG6vdNYUqdc83tkQi2eHfF98ubzQLA==} + bottleneck@2.19.5: + resolution: {integrity: sha512-VHiNCbI1lKdl44tGrhNfU3lup0Tj/ZBMJB5/2ZbNXRCPuRCO7ed2mgcK4r17y+KB2EfuYuRaVlwNbAeaWGSpbw==} + bowser@2.11.0: resolution: {integrity: sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA==} @@ -2548,11 +2672,11 @@ packages: resolution: {integrity: sha512-9gYgQKXx+1nP8mP7CzFyaUARhg7D3n1dF/FnErWmu9l6JvGpNUN278h0aSb+QjoiKSWG+iZ3uHrcqk0qrY9RQQ==} engines: {node: '>=10'} - brace-expansion@1.1.11: - resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} + brace-expansion@1.1.12: + resolution: {integrity: sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==} - brace-expansion@2.0.1: - resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} + brace-expansion@2.0.2: + resolution: {integrity: sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==} braces@2.3.2: resolution: {integrity: sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==} @@ -2580,8 +2704,8 @@ packages: browserify-aes@1.2.0: resolution: {integrity: sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==} - browserslist@4.24.5: - resolution: {integrity: sha512-FDToo4Wo82hIdgc1CQ+NQD0hEhmpPjrZ3hiUgwgOG6IuTdlpr8jdjyG24P6cNP1yJpTLzS5OcGgSw0xmDU1/Tw==} + browserslist@4.25.1: + resolution: {integrity: sha512-KGj0KoOMXLpSNkkEI6Z6mShmQy0bc1I+T7K9N81k4WWMrfz+6fQ6es80B/YLAeRoKvjYE1YSHHOW1qe9xIVzHw==} engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true @@ -2657,6 +2781,14 @@ packages: resolution: {integrity: sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==} engines: {node: '>=0.10.0'} + cacheable-lookup@5.0.4: + resolution: {integrity: sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==} + engines: {node: '>=10.6.0'} + + cacheable-request@7.0.4: + resolution: {integrity: sha512-v+p6ongsrp0yTGbJXjgxPow2+DL93DASP4kXCDKb8/bwRtt9OEF3whggkkDkGNzgcWy2XaF4a8nZglC7uElscg==} + engines: {node: '>=8'} + call-bind-apply-helpers@1.0.2: resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} engines: {node: '>= 0.4'} @@ -2684,8 +2816,8 @@ packages: resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==} engines: {node: '>=10'} - caniuse-lite@1.0.30001717: - resolution: {integrity: sha512-auPpttCq6BDEG8ZAuHJIplGw6GODhjw+/11e7IjpnYCxZcW/ONgPs0KVBJ0d1bY3e2+7PRe5RCLyP+PfwVgkYw==} + caniuse-lite@1.0.30001727: + resolution: {integrity: sha512-pB68nIHmbN6L/4C6MH1DokyR3bYqFwjaSs/sWDHGj4CTcFtQUQMuJftVwWkXq7mNWOybD3KhUv3oWHoGxgP14Q==} capability@0.2.5: resolution: {integrity: sha512-rsJZYVCgXd08sPqwmaIqjAd5SUTfonV0z/gDJ8D6cN8wQphky1kkAYEqQ+hmDxTw7UihvBfjUVUSY+DBEe44jg==} @@ -2698,6 +2830,10 @@ packages: resolution: {integrity: sha512-K7Qy8O9p76sL3/3m7/zLKbRkyOlSZAgzEaLhyj2mXS8PsCud2Eo4hAb8aLtZqHh0QGqLcb9dlJSu6lHRVENm1w==} engines: {node: '>=6'} + cbor@9.0.2: + resolution: {integrity: sha512-JPypkxsB10s9QOWwa6zwPzqE1Md3vqpPc+cai4sAecuCsRyAtAl/pMyhPlMbT/xtPnm2dznJZYRLui57qiRhaQ==} + engines: {node: '>=16'} + chai@4.5.0: resolution: {integrity: sha512-RITGBfijLkBddZvnn8jdqoTypxvqbOLYQkGGxXzeFjVHvudaPw0HNFD9x928/eUwYWd2dPCugVqspGALTZZQKw==} engines: {node: '>=4'} @@ -2800,6 +2936,9 @@ packages: resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} engines: {node: '>=12'} + clone-response@1.0.3: + resolution: {integrity: sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==} + clone@1.0.4: resolution: {integrity: sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==} engines: {node: '>=0.8'} @@ -2925,9 +3064,15 @@ packages: resolution: {integrity: sha512-fereAvAvxDrQDOXybk3Qu3dPbOoKoysFMWtkY3mv5BsL8//OSZVL5DCLYqgRfY5cWirgRzlC+WSrxp6Bo3eNZg==} hasBin: true + core-js@3.43.0: + resolution: {integrity: sha512-N6wEbTTZSYOY2rYAn85CuvWWkCK6QweMn7/4Nr3w+gDBeBhk/x4EJeY6FPo4QzDoJZxVTv8U7CMvgWk6pOHHqA==} + core-util-is@1.0.3: resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} + create-hash@1.1.3: + resolution: {integrity: sha512-snRpch/kwQhcdlnZKYanNF1m0RDlrCdSKQaH87w1FCFPVPNCQ/Il9QJKAX2jVBZddRdaHBMC+zXa9Gw9tmkNUA==} + create-hash@1.2.0: resolution: {integrity: sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==} @@ -2976,6 +3121,10 @@ packages: resolution: {integrity: sha512-a8bhT76Q546jOElHcTrkzWY7Py925mfLO/jqquseH61ThOebYwOjLbWHBqdRB4K1VpU36sTyIei6Jwj7QdEZ7g==} engines: {node: '>= 0.1.90'} + data-uri-to-buffer@4.0.1: + resolution: {integrity: sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==} + engines: {node: '>= 12'} + data-view-buffer@1.0.2: resolution: {integrity: sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==} engines: {node: '>= 0.4'} @@ -3027,8 +3176,8 @@ packages: supports-color: optional: true - debug@4.4.0: - resolution: {integrity: sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==} + debug@4.4.1: + resolution: {integrity: sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==} engines: {node: '>=6.0'} peerDependencies: supports-color: '*' @@ -3047,13 +3196,17 @@ packages: decimal.js-light@2.5.1: resolution: {integrity: sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg==} - decimal.js@10.5.0: - resolution: {integrity: sha512-8vDa8Qxvr/+d94hSh5P3IJwI5t8/c0KsMp+g8bNw9cY2icONa5aPfvKeieW1WlG0WQYwwhJ7mjui2xtiePQSXw==} + decimal.js@10.6.0: + resolution: {integrity: sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==} decode-uri-component@0.2.2: resolution: {integrity: sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==} engines: {node: '>=0.10'} + decompress-response@6.0.0: + resolution: {integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==} + engines: {node: '>=10'} + dedent@1.6.0: resolution: {integrity: sha512-F1Z+5UCFpmQUzJa11agbyPVMbpgT/qA3/SKyJ1jyBgm7dUcUEa8v9JwDkerSQXfakBwFljIxhOJqGkjUwZ9FSA==} peerDependencies: @@ -3076,6 +3229,10 @@ packages: defaults@1.0.4: resolution: {integrity: sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==} + defer-to-connect@2.0.1: + resolution: {integrity: sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==} + engines: {node: '>=10'} + define-data-property@1.1.4: resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} engines: {node: '>= 0.4'} @@ -3169,8 +3326,8 @@ packages: resolution: {integrity: sha512-vwEppIphpFdvaMCaHfCEv9IgwcxMljMw2TnAQBB4VWPvzXQLTb82jwmdOKzlEVUL3gNFT4l4TPKO+Bn+sqcrVQ==} engines: {node: '>=12'} - dotenv@16.5.0: - resolution: {integrity: sha512-m/C+AwOAr9/W1UOIZUo232ejMNnJAJtYQjUbHoNTBNTJSvqzzDh7vnrei3o3r3m9blf6ZoDkvcw0VmozNRFJxg==} + dotenv@16.6.1: + resolution: {integrity: sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==} engines: {node: '>=12'} dtrace-provider@0.8.8: @@ -3195,8 +3352,8 @@ packages: engines: {node: '>=0.10.0'} hasBin: true - electron-to-chromium@1.5.151: - resolution: {integrity: sha512-Rl6uugut2l9sLojjS4H4SAr3A4IgACMLgpuEMPYCVcKydzfyPrn5absNRju38IhQOf/NwjJY8OGWjlteqYeBCA==} + electron-to-chromium@1.5.179: + resolution: {integrity: sha512-UWKi/EbBopgfFsc5k61wFpV7WrnnSlSzW/e2XcBmS6qKYTivZlLtoll5/rdqRTxGglGHkmkW0j0pFNJG10EUIQ==} elliptic@6.6.1: resolution: {integrity: sha512-RaddvvMatK2LJHqFJ+YA4WysVN5Ita9E35botqIYspQ4TkRAlCicdzKOjlyv/1Za5RyTNn7di//eEV0uTAfe3g==} @@ -3225,8 +3382,8 @@ packages: encoding@0.1.13: resolution: {integrity: sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==} - end-of-stream@1.4.4: - resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==} + end-of-stream@1.4.5: + resolution: {integrity: sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==} enquirer@2.4.1: resolution: {integrity: sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==} @@ -3245,8 +3402,8 @@ packages: error-polyfill@0.1.3: resolution: {integrity: sha512-XHJk60ufE+TG/ydwp4lilOog549iiQF2OAPhkk9DdiYWMrltz5yhDz/xnKuenNwP7gy3dsibssO5QpVhkrSzzg==} - es-abstract@1.23.9: - resolution: {integrity: sha512-py07lI0wjxAC/DcfK1S6G7iANonniZwTISvdPzk9hzeH0IZIshbuuFxLIU96OyF89Yb9hiqWn8M/bY83KY5vzA==} + es-abstract@1.24.0: + resolution: {integrity: sha512-WSzPgsdLtTcQwm4CROfS5ju2Wa1QQcVeT37jFjYzdFz1r9ahadC8B8/a4qxJxM+09F18iumCdRmlr96ZYkQvEg==} engines: {node: '>= 0.4'} es-define-property@1.0.1: @@ -3329,8 +3486,8 @@ packages: eslint-import-resolver-node@0.3.9: resolution: {integrity: sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==} - eslint-module-utils@2.12.0: - resolution: {integrity: sha512-wALZ0HFoytlyh/1+4wuZ9FJCD/leWHQzzrxJ8+rebyReSLk7LApMyd3WJaLVoN+D5+WIdJyDK1c6JnE65V4Zyg==} + eslint-module-utils@2.12.1: + resolution: {integrity: sha512-L8jSWTze7K2mTg0vos/RuLRS5soomksDPoJLXIslC7c8Wmut3bx7CPpJijDcBZtxQ5lrbUdM+s0OlNbz0DCDNw==} engines: {node: '>=4'} peerDependencies: '@typescript-eslint/parser': '*' @@ -3356,8 +3513,8 @@ packages: peerDependencies: eslint: '>=8' - eslint-plugin-import@2.31.0: - resolution: {integrity: sha512-ixmkI62Rbc2/w8Vfxyh1jQRTdRTF52VxwRVHl/ykPAmqG+Nb7/kNn+byLP0LxPgI7zWA16Jt82SybJInmMia3A==} + eslint-plugin-import@2.32.0: + resolution: {integrity: sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==} engines: {node: '>=4'} peerDependencies: '@typescript-eslint/parser': '*' @@ -3372,8 +3529,8 @@ packages: peerDependencies: eslint: '>=7.0.0' - eslint-plugin-prettier@5.4.0: - resolution: {integrity: sha512-BvQOvUhkVQM1i63iMETK9Hjud9QhqBnbtT1Zc642p9ynzBuCe5pybkOnvqZIBypXmMlsGcnU4HZ8sCTPfpAexA==} + eslint-plugin-prettier@5.5.1: + resolution: {integrity: sha512-dobTkHT6XaEVOo8IO90Q4DOSxnm3Y151QxPJlM/vKC0bVy+d6cVWQZLlFiuZPP0wS6vZwSKeJgKkcS+KfMBlRw==} engines: {node: ^14.18.0 || >=16.0.0} peerDependencies: '@types/eslint': '>=8.0.0' @@ -3615,8 +3772,8 @@ packages: fb-watchman@2.0.2: resolution: {integrity: sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==} - fdir@6.4.4: - resolution: {integrity: sha512-1NZP+GK4GfuAv3PqKvxQRDMjdSRZjnkq7KfhlNrCNNlZ0ygQFpebfrnfnq/W7fpUnAv9aGWmY1zKx7FYL3gwhg==} + fdir@6.4.6: + resolution: {integrity: sha512-hiFoqpyZcfNm1yc4u8oWCf9A2c4D3QjCrks3zmoVKVxpQRzmPNar1hUJcBG2RQHvEVGDN+Jm81ZheVLAQMK6+w==} peerDependencies: picomatch: ^3 || ^4 peerDependenciesMeta: @@ -3626,6 +3783,10 @@ packages: fecha@4.2.3: resolution: {integrity: sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==} + fetch-blob@3.2.0: + resolution: {integrity: sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==} + engines: {node: ^12.20 || >= 14.13} + figures@3.2.0: resolution: {integrity: sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==} engines: {node: '>=8'} @@ -3713,10 +3874,14 @@ packages: resolution: {integrity: sha512-q5YBMeWy6E2Un0nMGWMgI65MAKtaylxfNJGJxpGh45YDciZB4epbWpaAfImil6CPAPTYB4sh0URQNDRIZG5F2w==} engines: {node: '>= 6'} - form-data@4.0.2: - resolution: {integrity: sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w==} + form-data@4.0.3: + resolution: {integrity: sha512-qsITQPfmvMOSAdeyZ+12I1c+CKSstAFAwu+97zrnWAbIr5u8wfsExUzCesVLC8NgHuRUqNN4Zy6UPWUTRGslcA==} engines: {node: '>= 6'} + formdata-polyfill@4.0.10: + resolution: {integrity: sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==} + engines: {node: '>=12.20.0'} + formidable@3.5.4: resolution: {integrity: sha512-YikH+7CUTOtP44ZTnUhR7Ic2UASBPOqmaRkRKxRbywPTe5VxF7RRCck4af9wutiZ/QKM5nME9Bie2fFaPz5Gug==} engines: {node: '>=14.0.0'} @@ -3814,6 +3979,10 @@ packages: resolution: {integrity: sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==} engines: {node: '>=6'} + get-stream@5.2.0: + resolution: {integrity: sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==} + engines: {node: '>=8'} + get-stream@6.0.1: resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} engines: {node: '>=10'} @@ -3822,8 +3991,8 @@ packages: resolution: {integrity: sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==} engines: {node: '>= 0.4'} - get-tsconfig@4.10.0: - resolution: {integrity: sha512-kGzZ3LWWQcGIAmg6iWvXn0ei6WDtV26wzHRMwDSzmAbcXrTEXxHy6IehI6/4eT6VRKyMP1eF1VqwrVUmE/LR7A==} + get-tsconfig@4.10.1: + resolution: {integrity: sha512-auHyJ4AgMz7vgS8Hp3N6HXSmlMdUyhSUrfBF16w153rxtLIEOE+HGqaBppczZvnHLqQJfiHotCYpNhl0lUROFQ==} get-value@2.0.6: resolution: {integrity: sha512-Ln0UQDlxH1BapMu3GPtf7CuYNwRZf2gwCuPqbyG6pB8WfmFpzqcy4xtAaAMUhnNqjMKTiCPZG2oMT3YSx8U2NA==} @@ -3847,6 +4016,11 @@ packages: resolution: {integrity: sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==} hasBin: true + glob@11.0.3: + resolution: {integrity: sha512-2Nim7dha1KVkaiF4q6Dj+ngPPMdfvLJEOpZk/jKiUAkqKebpGAWQXAq9z1xu9HKu5lWfqw/FASuccEjyznjPaA==} + engines: {node: 20 || >=22} + hasBin: true + glob@6.0.4: resolution: {integrity: sha512-MKZeRNyYZAVVVG1oZeLaWie1uweH40m9AZwIwxyPbTSX4hHrVYSzLg0Ro5Z5R7XKkIX+Cc6oD1rqeDJnwsB8/A==} deprecated: Glob versions prior to v9 are no longer supported @@ -3864,10 +4038,6 @@ packages: engines: {node: '>=12'} deprecated: Glob versions prior to v9 are no longer supported - globals@11.12.0: - resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==} - engines: {node: '>=4'} - globals@13.24.0: resolution: {integrity: sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==} engines: {node: '>=8'} @@ -3890,6 +4060,10 @@ packages: resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} engines: {node: '>= 0.4'} + got@11.8.6: + resolution: {integrity: sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g==} + engines: {node: '>=10.19.0'} + graceful-fs@4.2.11: resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} @@ -3918,8 +4092,8 @@ packages: peerDependencies: hardhat: ^2.0.0 - hardhat@2.24.0: - resolution: {integrity: sha512-wDkD5GPmttYv21MR7tGDkyQ22tO2V86OEV8pA7NcXWYUpibe8XZ2EanXCeRHO61vwEx0f7/M+NqrhJwasaNMJg==} + hardhat@2.25.0: + resolution: {integrity: sha512-yBiA74Yj3VnTRj7lhnn8GalvBdvsMOqTKRrRATSy/2v0VIR2hR0Jcnmfn4aQBLtGAnr3Q2c8CxL0g3LYegUp+g==} hasBin: true peerDependencies: ts-node: '*' @@ -3977,6 +4151,9 @@ packages: resolution: {integrity: sha512-ODYZC64uqzmtfGMEAX/FvZiRyWLpAC3vYnNunURUnkGVTS+mI0smVsWaPydRBsE3g+ok7h960jChO8mFcWlHaQ==} engines: {node: '>=0.10.0'} + hash-base@2.0.2: + resolution: {integrity: sha512-0TROgQ1/SxE6KmxWSvXHvRj90/Xo1JvZShofnYF+f6ZsGtR4eES7WfrQzPalmyagfKZCXpVnitiRebZulWsbiw==} + hash-base@3.1.0: resolution: {integrity: sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==} engines: {node: '>=4'} @@ -4027,6 +4204,10 @@ packages: resolution: {integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==} engines: {node: '>= 14'} + http2-wrapper@1.0.3: + resolution: {integrity: sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==} + engines: {node: '>=10.19.0'} + https-proxy-agent@5.0.1: resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==} engines: {node: '>= 6'} @@ -4257,6 +4438,10 @@ packages: resolution: {integrity: sha512-E+zBKpQ2t6MEo1VsonYmluk9NxGrbzpeeLC2xIViuO2EjU2xsXsBPwTr3Ykv9l08UYEVEdWeRZNouaZqF6RN0w==} engines: {node: '>= 0.4'} + is-negative-zero@2.0.3: + resolution: {integrity: sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==} + engines: {node: '>= 0.4'} + is-number-object@1.1.1: resolution: {integrity: sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==} engines: {node: '>= 0.4'} @@ -4401,6 +4586,10 @@ packages: jackspeak@3.4.3: resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==} + jackspeak@4.1.1: + resolution: {integrity: sha512-zptv57P3GpL+O0I7VdMJNBZCu+BPHVQUk55Ft8/QCJjTVxrnJHuVuX/0Bl2A6/+2oyR/ZMEuFKwmzqqZ/U5nPQ==} + engines: {node: 20 || >=22} + jacoco-parse@2.0.1: resolution: {integrity: sha512-YGhIb2iXuQ4/zNh2zgHd6Z6dqlYwLYH1wfsxtTNQ+jnHH9PhhuMwqOFihXymSI41trxok48LdKkSeDIWs28tYg==} @@ -4773,9 +4962,17 @@ packages: lower-case@2.0.2: resolution: {integrity: sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==} + lowercase-keys@2.0.0: + resolution: {integrity: sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==} + engines: {node: '>=8'} + lru-cache@10.4.3: resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} + lru-cache@11.1.0: + resolution: {integrity: sha512-QIXZUBJUx+2zHUdQujWejBkcD9+cs94tLn0+YL8UrCh+D5sCXZ4c7LaEH48pNwRY3MLDgqUFyhlCyjJPf1WP0A==} + engines: {node: 20 || >=22} + lru-cache@5.1.1: resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} @@ -4894,12 +5091,24 @@ packages: resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} engines: {node: '>=6'} + mimic-response@1.0.1: + resolution: {integrity: sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==} + engines: {node: '>=4'} + + mimic-response@3.1.0: + resolution: {integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==} + engines: {node: '>=10'} + minimalistic-assert@1.0.1: resolution: {integrity: sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==} minimalistic-crypto-utils@1.0.1: resolution: {integrity: sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==} + minimatch@10.0.3: + resolution: {integrity: sha512-IPZ167aShDZZUMdRk66cyQAW3qr0WzbHkPdMYa8bzZhlHhO3jALbKdxcaak7W9FfT2rZNpQuUu4Od7ILEpXSaw==} + engines: {node: 20 || >=22} + minimatch@3.0.4: resolution: {integrity: sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==} @@ -5012,6 +5221,9 @@ packages: nan@2.22.2: resolution: {integrity: sha512-DANghxFkS1plDdRsX0X9pm0Z6SJNN6gBdtXfanwoZ8hooC5gosGFSBGRYHUVPz1asKA/kMRqDRdHrluZ61SpBQ==} + nanoassert@1.1.0: + resolution: {integrity: sha512-C40jQ3NzfkP53NsO8kEOFd79p4b9kDXQMwgiY1z8ZwrDZgUyom0AHwGegF4Dm99L+YoYhuaB0ceerUcXmqr1rQ==} + nanomatch@1.2.13: resolution: {integrity: sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==} engines: {node: '>=0.10.0'} @@ -5066,6 +5278,11 @@ packages: resolution: {integrity: sha512-t1QzWwnk4sjLWaQAS8CHgOJ+RAfmHpxFWmc36IWTiWHQfs0w5JDMBS1b1ZxQteo0vVVuWJvIUKHDkkeK7vIGCg==} engines: {node: '>= 8.0.0'} + node-domexception@1.0.0: + resolution: {integrity: sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==} + engines: {node: '>=10.5.0'} + deprecated: Use your platform's native DOMException instead + node-fetch@2.6.1: resolution: {integrity: sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==} engines: {node: 4.x || >=6.0.0} @@ -5079,6 +5296,10 @@ packages: encoding: optional: true + node-fetch@3.3.2: + resolution: {integrity: sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + node-gyp-build@4.8.4: resolution: {integrity: sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==} hasBin: true @@ -5099,6 +5320,10 @@ packages: engines: {node: '>=8.10.0'} hasBin: true + nofilter@3.1.0: + resolution: {integrity: sha512-l2NNj07e9afPnhAhvgVrCD/oy2Ai1yfLpuo3EpiO1jFTsB4sFz6oIfAfSZyQzVpkZQ9xS8ZS5g1jCBgq4Hwo0g==} + engines: {node: '>=12.19'} + noms@0.0.0: resolution: {integrity: sha512-lNDU9VJaOPxUmXcLb+HQFeUgQQPtMI24Gt6hgfuMHRJgMRHMF/qZ4HJD3GDru4sSw9IQl2jPjAYnQrdIeLbwow==} @@ -5111,6 +5336,10 @@ packages: resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} engines: {node: '>=0.10.0'} + normalize-url@6.1.0: + resolution: {integrity: sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==} + engines: {node: '>=10'} + npm-package-arg@11.0.3: resolution: {integrity: sha512-sHGJy8sOC1YraBywpzQlIKBE4pBbGbiF95U6Auspzyem956E0+FtDtsx1ZxlOJkQCZ1AFXAY/yuvtFYrOxF+Bw==} engines: {node: ^16.14.0 || >=18.0.0} @@ -5127,8 +5356,8 @@ packages: resolution: {integrity: sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - npm@10.9.2: - resolution: {integrity: sha512-iriPEPIkoMYUy3F6f3wwSZAU93E0Eg6cHwIR6jzzOXWSy+SD/rOODEs74cVONHKSx2obXtuUoyidVEhISrisgQ==} + npm@10.9.3: + resolution: {integrity: sha512-6Eh1u5Q+kIVXeA8e7l2c/HpnFFcwrkt37xDMujD5be1gloWa9p6j3Fsv3mByXXmqJHy+2cElRMML8opNT7xIJQ==} engines: {node: ^18.17.0 || >=20.5.0} hasBin: true bundledDependencies: @@ -5308,6 +5537,10 @@ packages: resolution: {integrity: sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==} engines: {node: '>= 0.4'} + p-cancelable@2.1.1: + resolution: {integrity: sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==} + engines: {node: '>=8'} + p-defer@1.0.0: resolution: {integrity: sha512-wB3wfAxZpk2AzOfUMJNL+d36xothRSyj8EXOa4f6GMqYDN9BJaaSISbsk+wS9abmnebVw95C2Kb5t85UmpCxuw==} engines: {node: '>=4'} @@ -5411,6 +5644,10 @@ packages: resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} engines: {node: '>=16 || 14 >=14.18'} + path-scurry@2.0.0: + resolution: {integrity: sha512-ypGJsmGtdXUOeM5u93TyeIEfEhM6s+ljAhrk5vAvSx8uyY/02OvrZnA0YNGUrPXfpJMgI1ODd3nwz8Npx4O4cg==} + engines: {node: 20 || >=22} + path-to-regexp@0.1.12: resolution: {integrity: sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==} @@ -5424,8 +5661,8 @@ packages: pause-stream@0.0.11: resolution: {integrity: sha512-e3FBlXLmN/D1S+zHzanP4E/4Z60oFAa3O051qt1pxa7DEJWKAyil6upYVXCWadEnuoqa4Pkc9oUx9zsxYeRv8A==} - pbkdf2@3.1.2: - resolution: {integrity: sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==} + pbkdf2@3.1.3: + resolution: {integrity: sha512-wfRLBZ0feWRhCIkoMB6ete7czJcnNnqRpcoWQBLqatqXXmelSRqfdDK4F3u9T2s2cXas/hQJcryI/4lAL+XTlA==} engines: {node: '>=0.12'} picocolors@1.1.1: @@ -5449,8 +5686,8 @@ packages: pino-std-serializers@7.0.0: resolution: {integrity: sha512-e906FRY0+tV27iq4juKzSYPbUj2do2X2JX4EzSca1631EB2QJQUqGbDuERal7LCtOpxl6x3+nvo9NPZcmjkiFA==} - pino@9.6.0: - resolution: {integrity: sha512-i85pKRCt4qMjZ1+L7sy2Ag4t1atFcdbEt76+7iRJn1g2BvsnRMGu9p8pivl9fs63M2kF/A0OacFZhTub+m/qMg==} + pino@9.7.0: + resolution: {integrity: sha512-vnMCM6xZTb1WDmLvtG2lE/2p+t9hDEIvTWJsu6FejkE62vB7gDhvzrpFR4Cw2to+9JNQxVnkAKVPA1KPB98vWg==} hasBin: true pirates@4.0.7: @@ -5461,8 +5698,8 @@ packages: resolution: {integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==} engines: {node: '>=8'} - pnpm@10.10.0: - resolution: {integrity: sha512-1hXbJG/nDyXc/qbY1z3ueCziPiJF48T2+Igkn7VoFJMYY33Kc8LFyO8qTKDVZX+5VnGIv6tH9WbR7mzph4FcOQ==} + pnpm@10.12.4: + resolution: {integrity: sha512-Xqiw3u2U7WhpHJutTJVUknBcXuuKh++GvGLHSiawN7CP+VcPEIsuTb0d0akYb+qSXlJ/FBxkjoWvRWMQdGgBhA==} engines: {node: '>=18.12'} hasBin: true @@ -5482,8 +5719,8 @@ packages: resolution: {integrity: sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==} engines: {node: '>=6.0.0'} - prettier@3.5.3: - resolution: {integrity: sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw==} + prettier@3.6.2: + resolution: {integrity: sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==} engines: {node: '>=14'} hasBin: true @@ -5512,8 +5749,8 @@ packages: process-warning@3.0.0: resolution: {integrity: sha512-mqn0kFRl0EoqhnL0GQ0veqFHyIN1yig9RHh/InzORTUiZHFRAur+aMtRkELNwGs9aNwKS6tg/An4NYBPGwvtzQ==} - process-warning@4.0.1: - resolution: {integrity: sha512-3c2LzQ3rY9d0hc1emcsHhfT9Jwz0cChib/QN89oME2R451w5fy3f0afAhERFZAwrbDU43wk12d0ORBpDVME50Q==} + process-warning@5.0.0: + resolution: {integrity: sha512-a39t9ApHNx2L4+HBnQKqxxHNs1r7KF+Intd8Q/g1bUh6q0WIp9voPXJ/x0j+ZL45KF1pJd9+q2jLIRMfvEshkA==} process@0.11.10: resolution: {integrity: sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==} @@ -5542,8 +5779,8 @@ packages: pstree.remy@1.1.8: resolution: {integrity: sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==} - pump@3.0.2: - resolution: {integrity: sha512-tUPXtzlGM8FE3P0ZL6DVs/3P58k9nk8/jZeQCurTJylQA8qFYzHFfhBJkuqyE0FifOsQ0uKWekiZ5g8wtr28cw==} + pump@3.0.3: + resolution: {integrity: sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==} punycode@2.3.1: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} @@ -5552,16 +5789,31 @@ packages: pure-rand@6.1.0: resolution: {integrity: sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==} + pvtsutils@1.3.6: + resolution: {integrity: sha512-PLgQXQ6H2FWCaeRak8vvk1GW462lMxB5s3Jm673N82zI4vqtVUPuZdffdZbPDFRoU8kAhItWFtPCWiPpp4/EDg==} + + pvutils@1.1.3: + resolution: {integrity: sha512-pMpnA0qRdFp32b1sJl1wOJNxZLQ2cbQx+k6tjNtZ8CpvVhNqEPRgivZ2WOUev2YMajecdH7ctUPDvEe87nariQ==} + engines: {node: '>=6.0.0'} + qs@6.13.0: resolution: {integrity: sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==} engines: {node: '>=0.6'} + qs@6.14.0: + resolution: {integrity: sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==} + engines: {node: '>=0.6'} + queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} quick-format-unescaped@4.0.4: resolution: {integrity: sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==} + quick-lru@5.1.1: + resolution: {integrity: sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==} + engines: {node: '>=10'} + randombytes@2.1.0: resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==} @@ -5652,6 +5904,9 @@ packages: require-main-filename@1.0.1: resolution: {integrity: sha512-IqSUtOVP4ksd1C/ej5zeEh/BIP2ajqpn8c5x+q99gvcIG/Qf0cud5raVnE/Dwd0ua9TXYDoDc0RE5hBSdz22Ug==} + resolve-alpn@1.2.1: + resolution: {integrity: sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==} + resolve-cwd@3.0.0: resolution: {integrity: sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==} engines: {node: '>=8'} @@ -5683,6 +5938,9 @@ packages: engines: {node: '>= 0.4'} hasBin: true + responselike@2.0.1: + resolution: {integrity: sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw==} + restore-cursor@3.1.0: resolution: {integrity: sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==} engines: {node: '>=8'} @@ -5720,6 +5978,14 @@ packages: deprecated: Rimraf versions prior to v4 are no longer supported hasBin: true + rimraf@6.0.1: + resolution: {integrity: sha512-9dkvaxAsk/xNXSJzMgFqqMCuFgt2+KsOFek3TMLfo8NCPfWpBmqwyNn5Y+NX56QUYfCtsyhF3ayiboEoUmJk/A==} + engines: {node: 20 || >=22} + hasBin: true + + ripemd160@2.0.1: + resolution: {integrity: sha512-J7f4wutN8mdbV08MJnXibYpCOPHR+yzy+iQ/AsjMv2j8cLavQ8VGagDFUwwTAdF8FmRKVeNpbTTEwNHCW1g94w==} + ripemd160@2.0.2: resolution: {integrity: sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==} @@ -5811,8 +6077,8 @@ packages: resolution: {integrity: sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==} hasBin: true - semver@7.7.1: - resolution: {integrity: sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==} + semver@7.7.2: + resolution: {integrity: sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==} engines: {node: '>=10'} hasBin: true @@ -5855,10 +6121,14 @@ packages: setprototypeof@1.2.0: resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} - sha.js@2.4.11: - resolution: {integrity: sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==} + sha.js@2.4.12: + resolution: {integrity: sha512-8LzC5+bvI45BjpfXU8V5fdU2mfeKiQe1D1gIMn7XUlF3OTUrpdJpPPH4EMAnF0DsHHdSZqCdSss5qCmJKuiO3w==} + engines: {node: '>= 0.10'} hasBin: true + sha3@2.1.4: + resolution: {integrity: sha512-S8cNxbyb0UGUM2VhRD4Poe5N58gJnJsLJ5vC7FYWGUmGhcsj4++WaIOBFVDxlG0W3To6xBuiRh+i0Qp2oNCOtg==} + shebang-command@1.2.0: resolution: {integrity: sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==} engines: {node: '>=0.10.0'} @@ -5947,8 +6217,8 @@ packages: resolution: {integrity: sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw==} engines: {node: '>= 14'} - socks@2.8.4: - resolution: {integrity: sha512-D3YaD0aRxR3mEcqnidIs7ReYJFVzWdd6fXJYUM8ixcQcJRGTka/b3saV0KflYhyVJXKhb947GndU35SxYNResQ==} + socks@2.8.5: + resolution: {integrity: sha512-iF+tNDQla22geJdTyJB1wM/qrX9DMRwWrciEPwWLPRWAUEM8sQiyxgckLxWT1f7+9VabJS0jTGGr4QgBuvi6Ww==} engines: {node: '>= 10.0.0', npm: '>= 3.0.0'} solc@0.8.26: @@ -6038,6 +6308,10 @@ packages: resolution: {integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==} engines: {node: '>= 0.8'} + stop-iteration-iterator@1.1.0: + resolution: {integrity: sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==} + engines: {node: '>= 0.4'} + stream-blackhole@1.0.3: resolution: {integrity: sha512-7NWl3dkmCd12mPkEwTbBPGxwvxj7L4O9DTjJudn02Fmk9K+RuPaDF8zeGo3kmjbsffU5E1aGpZ1dTR9AaRg6AQ==} @@ -6141,8 +6415,8 @@ packages: strnum@1.1.2: resolution: {integrity: sha512-vrN+B7DBIoTTZjnPNewwhx6cBA/H+IS7rfW68n7XxC1y7uoiGQBxaKzqucGUgavX15dJgiGztLJ8vxuEzwqBdA==} - superagent@9.0.2: - resolution: {integrity: sha512-xuW7dzkUpcJq7QnhOsnNUgtYp3xRwpt2F7abdRYIpCsAt0hhUqia0EdxyXZQQpNmGtsCzYHryaKSV3q3GJnq7w==} + superagent@10.2.1: + resolution: {integrity: sha512-O+PCv11lgTNJUzy49teNAWLjBZfc+A1enOwTpLlH6/rsvKcTwcdTT8m9azGkVqM7HBl5jpyZ7KTPhHweokBcdg==} engines: {node: '>=14.18.0'} superstruct@0.15.5: @@ -6152,8 +6426,8 @@ packages: resolution: {integrity: sha512-uV+TFRZdXsqXTL2pRvujROjdZQ4RAlBUS5BTh9IGm+jTqQntYThciG/qu57Gs69yjnVUSqdxF9YLmSnpupBW9A==} engines: {node: '>=14.0.0'} - supertest@7.1.0: - resolution: {integrity: sha512-5QeSO8hSrKghtcWEoPiO036fxH0Ii2wVQfFZSP0oqQhmjk8bOLhDFXr4JrvaFmPuEWUoq4znY3uSi8UzLKxGqw==} + supertest@7.1.1: + resolution: {integrity: sha512-aI59HBTlG9e2wTjxGJV+DygfNLgnWbGdZxiA/sgrnNNikIW8lbDvCtF6RnhZoJ82nU7qv7ZLjrvWqCEm52fAmw==} engines: {node: '>=14.18.0'} supports-color@4.4.0: @@ -6184,8 +6458,8 @@ packages: resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} engines: {node: '>= 0.4'} - synckit@0.11.4: - resolution: {integrity: sha512-Q/XQKRaJiLiFIBNN+mndW7S/RHxvwzuZS6ZwmRzUBqJBv/5QIKCEwkBC8GBf8EQJKYnaFs0wOZbKTXBPj8L9oQ==} + synckit@0.11.8: + resolution: {integrity: sha512-+XZ+r1XGIJGeQk3VvXhT6xx/VpbHsRzsTkGgF6E5RX9TTXD0118l87puaEBZ566FhqblC6U0d4XnubznJDm30A==} engines: {node: ^14.18.0 || >=16.0.0} table@6.9.0: @@ -6227,8 +6501,8 @@ packages: tiny-warning@1.0.3: resolution: {integrity: sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==} - tinyglobby@0.2.13: - resolution: {integrity: sha512-mEwzpUgrLySlveBwEVDMKk5B57bhLPYovRfPAXD5gA/98Opn0rCDj3GtLwFvCvH5RK9uPCExUROW5NjDwvqkxw==} + tinyglobby@0.2.14: + resolution: {integrity: sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==} engines: {node: '>=12.0.0'} tmp-promise@3.0.3: @@ -6245,6 +6519,10 @@ packages: tmpl@1.0.5: resolution: {integrity: sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==} + to-buffer@1.2.1: + resolution: {integrity: sha512-tB82LpAIWjhLYbqjx3X4zEeHN6M8CiuOEy2JY8SEQVdYRe3CCHOFaqrBW1doLDrfpWhplcW7BL+bO3/6S3pcDQ==} + engines: {node: '>= 0.4'} + to-object-path@0.3.0: resolution: {integrity: sha512-9mWHdnGRuh3onocaHzukyvCZhzvr6tiflAy/JRFXcJX0TjgfWA9pk9t8CMbzmBE4Jfw58pXbkngtBtqYxzNEyg==} engines: {node: '>=0.10.0'} @@ -6299,17 +6577,18 @@ packages: peerDependencies: typescript: '>=4.2.0' - ts-jest@29.3.2: - resolution: {integrity: sha512-bJJkrWc6PjFVz5g2DGCNUo8z7oFEYaz1xP1NpeDU7KNLMWPpEyV8Chbpkn8xjzgRDpQhnGMyvyldoL7h8JXyug==} + ts-jest@29.4.0: + resolution: {integrity: sha512-d423TJMnJGu80/eSgfQ5w/R+0zFJvdtTxwtF9KzFFunOpSeD+79lHJQIiAhluJoyGRbvj9NZJsl9WjCUo0ND7Q==} engines: {node: ^14.15.0 || ^16.10.0 || ^18.0.0 || >=20.0.0} hasBin: true peerDependencies: '@babel/core': '>=7.0.0-beta.0 <8' - '@jest/transform': ^29.0.0 - '@jest/types': ^29.0.0 - babel-jest: ^29.0.0 + '@jest/transform': ^29.0.0 || ^30.0.0 + '@jest/types': ^29.0.0 || ^30.0.0 + babel-jest: ^29.0.0 || ^30.0.0 esbuild: '*' - jest: ^29.0.0 + jest: ^29.0.0 || ^30.0.0 + jest-util: ^29.0.0 || ^30.0.0 typescript: '>=4.3 <6' peerDependenciesMeta: '@babel/core': @@ -6322,6 +6601,8 @@ packages: optional: true esbuild: optional: true + jest-util: + optional: true ts-node@10.9.2: resolution: {integrity: sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==} @@ -6529,10 +6810,17 @@ packages: wcwidth@1.0.1: resolution: {integrity: sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==} + web-streams-polyfill@3.3.3: + resolution: {integrity: sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==} + engines: {node: '>= 8'} + web3-utils@1.7.3: resolution: {integrity: sha512-g6nQgvb/bUpVUIxJE+ezVN+rYwYmlFyMvMIRSuqpi1dk6ApDD00YNArrk7sPcZnjvxOJ76813Xs2vIN2rgh4lg==} engines: {node: '>=8.0.0'} + webcrypto-core@1.8.1: + resolution: {integrity: sha512-P+x1MvlNCXlKbLSOY4cYrdreqPG5hbzkmawbcXLKN/mf6DZW0SdNNkZ+sjwsqVkI4A4Ko2sPZmkZtCKY58w83A==} + webidl-conversions@3.0.1: resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} @@ -6676,8 +6964,8 @@ packages: utf-8-validate: optional: true - ws@8.18.2: - resolution: {integrity: sha512-DMricUmwGZUVr++AEAe2uiVM7UoO9MAVZMDu05UQOaUII0lp+zOzLLU4Xqh/JvTqklB1T4uELaaPBKyjE1r4fQ==} + ws@8.18.3: + resolution: {integrity: sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==} engines: {node: '>=10.0.0'} peerDependencies: bufferutil: ^4.0.1 @@ -6724,9 +7012,9 @@ packages: resolution: {integrity: sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==} engines: {node: '>=18'} - yaml@2.7.1: - resolution: {integrity: sha512-10ULxpnOCQXxJvBgxsn9ptjq6uviG/htZKk9veJGhlqn3w/DxQ631zFF+nlQXLwmImeS5amR2dl2U8sg6U9jsQ==} - engines: {node: '>= 14'} + yaml@2.8.0: + resolution: {integrity: sha512-4lLa/EcQCB0cJkyts+FpIRx5G/llPxfP6VQU5KByHEhLxY3IJCH0f0Hy1MHI8sClTvsIb8qwRJ6R/ZdlDJ/leQ==} + engines: {node: '>= 14.6'} hasBin: true yargs-parser@11.1.1: @@ -6768,40 +7056,68 @@ packages: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} - zod-to-json-schema@3.24.5: - resolution: {integrity: sha512-/AuWwMP+YqiPbsJx5D6TfgRTc4kTLjsh5SOcd4bLsfUg2RcEXrFMJl1DGgdHy2aCfsIA/cr/1JM0xcB2GZji8g==} + zod-to-json-schema@3.24.6: + resolution: {integrity: sha512-h/z3PKvcTcTetyjl1fkj79MHNEjm+HpD6NXheWjzOekY7kV+lwDYnHw+ivHkijnCSMz1yJaWBD9vu/Fcmk+vEg==} peerDependencies: zod: ^3.24.1 - zod@3.24.4: - resolution: {integrity: sha512-OdqJE9UDRPwWsrHjLN2F8bPxvwJBK22EHLWtanu0LSYr5YqzsaaW3RMgmjwr8Rypg5k+meEJdSPXJZXE/yqOMg==} + zod@3.25.74: + resolution: {integrity: sha512-J8poo92VuhKjNknViHRAIuuN6li/EwFbAC8OedzI8uxpEPGiXHGQu9wemIAioIpqgfB4SySaJhdk0mH5Y4ICBg==} snapshots: '@adraffy/ens-normalize@1.9.0': {} + '@aiquant/lucid-cardano@0.10.11(bufferutil@4.0.9)(utf-8-validate@5.0.10)': + dependencies: + '@peculiar/webcrypto': 1.5.0 + node-fetch: 3.3.2 + ws: 8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10) + transitivePeerDependencies: + - bufferutil + - utf-8-validate + + '@aiquant/minswap-sdk@0.0.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)': + dependencies: + '@aiquant/lucid-cardano': 0.10.11(bufferutil@4.0.9)(utf-8-validate@5.0.10) + '@blockfrost/blockfrost-js': 5.7.0 + '@minswap/tiny-invariant': 1.2.0 + big.js: 6.2.2 + sha3: 2.1.4 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + + '@aiquant/sundaeswap-core@1.2.10(@aiquant/lucid-cardano@0.10.11(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@sundaeswap/asset@1.0.10)(@sundaeswap/bigint-math@0.6.3)(@sundaeswap/cpp@1.0.11(@sundaeswap/asset@1.0.10)(@sundaeswap/bigint-math@0.6.3)(@sundaeswap/fraction@1.0.7))(@sundaeswap/fraction@1.0.7)': + dependencies: + '@aiquant/lucid-cardano': 0.10.11(bufferutil@4.0.9)(utf-8-validate@5.0.10) + '@sundaeswap/asset': 1.0.10 + '@sundaeswap/bigint-math': 0.6.3 + '@sundaeswap/cpp': 1.0.11(@sundaeswap/asset@1.0.10)(@sundaeswap/bigint-math@0.6.3)(@sundaeswap/fraction@1.0.7) + '@sundaeswap/fraction': 1.0.7 + '@ampproject/remapping@2.3.0': dependencies: - '@jridgewell/gen-mapping': 0.3.8 - '@jridgewell/trace-mapping': 0.3.25 + '@jridgewell/gen-mapping': 0.3.12 + '@jridgewell/trace-mapping': 0.3.29 '@aws-crypto/crc32@5.2.0': dependencies: '@aws-crypto/util': 5.2.0 - '@aws-sdk/types': 3.804.0 + '@aws-sdk/types': 3.840.0 tslib: 2.8.1 '@aws-crypto/crc32c@5.2.0': dependencies: '@aws-crypto/util': 5.2.0 - '@aws-sdk/types': 3.804.0 + '@aws-sdk/types': 3.840.0 tslib: 2.8.1 '@aws-crypto/sha1-browser@5.2.0': dependencies: '@aws-crypto/supports-web-crypto': 5.2.0 '@aws-crypto/util': 5.2.0 - '@aws-sdk/types': 3.804.0 + '@aws-sdk/types': 3.840.0 '@aws-sdk/util-locate-window': 3.804.0 '@smithy/util-utf8': 2.3.0 tslib: 2.8.1 @@ -6811,7 +7127,7 @@ snapshots: '@aws-crypto/sha256-js': 5.2.0 '@aws-crypto/supports-web-crypto': 5.2.0 '@aws-crypto/util': 5.2.0 - '@aws-sdk/types': 3.804.0 + '@aws-sdk/types': 3.840.0 '@aws-sdk/util-locate-window': 3.804.0 '@smithy/util-utf8': 2.3.0 tslib: 2.8.1 @@ -6819,7 +7135,7 @@ snapshots: '@aws-crypto/sha256-js@5.2.0': dependencies: '@aws-crypto/util': 5.2.0 - '@aws-sdk/types': 3.804.0 + '@aws-sdk/types': 3.840.0 tslib: 2.8.1 '@aws-crypto/supports-web-crypto@5.2.0': @@ -6828,419 +7144,426 @@ snapshots: '@aws-crypto/util@5.2.0': dependencies: - '@aws-sdk/types': 3.804.0 + '@aws-sdk/types': 3.840.0 '@smithy/util-utf8': 2.3.0 tslib: 2.8.1 - '@aws-sdk/client-s3@3.806.0': + '@aws-sdk/client-s3@3.842.0': dependencies: '@aws-crypto/sha1-browser': 5.2.0 '@aws-crypto/sha256-browser': 5.2.0 '@aws-crypto/sha256-js': 5.2.0 - '@aws-sdk/core': 3.806.0 - '@aws-sdk/credential-provider-node': 3.806.0 - '@aws-sdk/middleware-bucket-endpoint': 3.806.0 - '@aws-sdk/middleware-expect-continue': 3.804.0 - '@aws-sdk/middleware-flexible-checksums': 3.806.0 - '@aws-sdk/middleware-host-header': 3.804.0 - '@aws-sdk/middleware-location-constraint': 3.804.0 - '@aws-sdk/middleware-logger': 3.804.0 - '@aws-sdk/middleware-recursion-detection': 3.804.0 - '@aws-sdk/middleware-sdk-s3': 3.806.0 - '@aws-sdk/middleware-ssec': 3.804.0 - '@aws-sdk/middleware-user-agent': 3.806.0 - '@aws-sdk/region-config-resolver': 3.806.0 - '@aws-sdk/signature-v4-multi-region': 3.806.0 - '@aws-sdk/types': 3.804.0 - '@aws-sdk/util-endpoints': 3.806.0 - '@aws-sdk/util-user-agent-browser': 3.804.0 - '@aws-sdk/util-user-agent-node': 3.806.0 - '@aws-sdk/xml-builder': 3.804.0 - '@smithy/config-resolver': 4.1.1 - '@smithy/core': 3.3.1 - '@smithy/eventstream-serde-browser': 4.0.2 - '@smithy/eventstream-serde-config-resolver': 4.1.0 - '@smithy/eventstream-serde-node': 4.0.2 - '@smithy/fetch-http-handler': 5.0.2 - '@smithy/hash-blob-browser': 4.0.2 - '@smithy/hash-node': 4.0.2 - '@smithy/hash-stream-node': 4.0.2 - '@smithy/invalid-dependency': 4.0.2 - '@smithy/md5-js': 4.0.2 - '@smithy/middleware-content-length': 4.0.2 - '@smithy/middleware-endpoint': 4.1.3 - '@smithy/middleware-retry': 4.1.4 - '@smithy/middleware-serde': 4.0.3 - '@smithy/middleware-stack': 4.0.2 - '@smithy/node-config-provider': 4.1.0 - '@smithy/node-http-handler': 4.0.4 - '@smithy/protocol-http': 5.1.0 - '@smithy/smithy-client': 4.2.3 - '@smithy/types': 4.2.0 - '@smithy/url-parser': 4.0.2 + '@aws-sdk/core': 3.840.0 + '@aws-sdk/credential-provider-node': 3.840.0 + '@aws-sdk/middleware-bucket-endpoint': 3.840.0 + '@aws-sdk/middleware-expect-continue': 3.840.0 + '@aws-sdk/middleware-flexible-checksums': 3.840.0 + '@aws-sdk/middleware-host-header': 3.840.0 + '@aws-sdk/middleware-location-constraint': 3.840.0 + '@aws-sdk/middleware-logger': 3.840.0 + '@aws-sdk/middleware-recursion-detection': 3.840.0 + '@aws-sdk/middleware-sdk-s3': 3.840.0 + '@aws-sdk/middleware-ssec': 3.840.0 + '@aws-sdk/middleware-user-agent': 3.840.0 + '@aws-sdk/region-config-resolver': 3.840.0 + '@aws-sdk/signature-v4-multi-region': 3.840.0 + '@aws-sdk/types': 3.840.0 + '@aws-sdk/util-endpoints': 3.840.0 + '@aws-sdk/util-user-agent-browser': 3.840.0 + '@aws-sdk/util-user-agent-node': 3.840.0 + '@aws-sdk/xml-builder': 3.821.0 + '@smithy/config-resolver': 4.1.4 + '@smithy/core': 3.6.0 + '@smithy/eventstream-serde-browser': 4.0.4 + '@smithy/eventstream-serde-config-resolver': 4.1.2 + '@smithy/eventstream-serde-node': 4.0.4 + '@smithy/fetch-http-handler': 5.0.4 + '@smithy/hash-blob-browser': 4.0.4 + '@smithy/hash-node': 4.0.4 + '@smithy/hash-stream-node': 4.0.4 + '@smithy/invalid-dependency': 4.0.4 + '@smithy/md5-js': 4.0.4 + '@smithy/middleware-content-length': 4.0.4 + '@smithy/middleware-endpoint': 4.1.13 + '@smithy/middleware-retry': 4.1.14 + '@smithy/middleware-serde': 4.0.8 + '@smithy/middleware-stack': 4.0.4 + '@smithy/node-config-provider': 4.1.3 + '@smithy/node-http-handler': 4.0.6 + '@smithy/protocol-http': 5.1.2 + '@smithy/smithy-client': 4.4.5 + '@smithy/types': 4.3.1 + '@smithy/url-parser': 4.0.4 '@smithy/util-base64': 4.0.0 '@smithy/util-body-length-browser': 4.0.0 '@smithy/util-body-length-node': 4.0.0 - '@smithy/util-defaults-mode-browser': 4.0.11 - '@smithy/util-defaults-mode-node': 4.0.11 - '@smithy/util-endpoints': 3.0.3 - '@smithy/util-middleware': 4.0.2 - '@smithy/util-retry': 4.0.3 - '@smithy/util-stream': 4.2.0 + '@smithy/util-defaults-mode-browser': 4.0.21 + '@smithy/util-defaults-mode-node': 4.0.21 + '@smithy/util-endpoints': 3.0.6 + '@smithy/util-middleware': 4.0.4 + '@smithy/util-retry': 4.0.6 + '@smithy/util-stream': 4.2.2 '@smithy/util-utf8': 4.0.0 - '@smithy/util-waiter': 4.0.3 + '@smithy/util-waiter': 4.0.6 + '@types/uuid': 9.0.8 tslib: 2.8.1 + uuid: 9.0.1 transitivePeerDependencies: - aws-crt - '@aws-sdk/client-sso@3.806.0': + '@aws-sdk/client-sso@3.840.0': dependencies: '@aws-crypto/sha256-browser': 5.2.0 '@aws-crypto/sha256-js': 5.2.0 - '@aws-sdk/core': 3.806.0 - '@aws-sdk/middleware-host-header': 3.804.0 - '@aws-sdk/middleware-logger': 3.804.0 - '@aws-sdk/middleware-recursion-detection': 3.804.0 - '@aws-sdk/middleware-user-agent': 3.806.0 - '@aws-sdk/region-config-resolver': 3.806.0 - '@aws-sdk/types': 3.804.0 - '@aws-sdk/util-endpoints': 3.806.0 - '@aws-sdk/util-user-agent-browser': 3.804.0 - '@aws-sdk/util-user-agent-node': 3.806.0 - '@smithy/config-resolver': 4.1.1 - '@smithy/core': 3.3.1 - '@smithy/fetch-http-handler': 5.0.2 - '@smithy/hash-node': 4.0.2 - '@smithy/invalid-dependency': 4.0.2 - '@smithy/middleware-content-length': 4.0.2 - '@smithy/middleware-endpoint': 4.1.3 - '@smithy/middleware-retry': 4.1.4 - '@smithy/middleware-serde': 4.0.3 - '@smithy/middleware-stack': 4.0.2 - '@smithy/node-config-provider': 4.1.0 - '@smithy/node-http-handler': 4.0.4 - '@smithy/protocol-http': 5.1.0 - '@smithy/smithy-client': 4.2.3 - '@smithy/types': 4.2.0 - '@smithy/url-parser': 4.0.2 + '@aws-sdk/core': 3.840.0 + '@aws-sdk/middleware-host-header': 3.840.0 + '@aws-sdk/middleware-logger': 3.840.0 + '@aws-sdk/middleware-recursion-detection': 3.840.0 + '@aws-sdk/middleware-user-agent': 3.840.0 + '@aws-sdk/region-config-resolver': 3.840.0 + '@aws-sdk/types': 3.840.0 + '@aws-sdk/util-endpoints': 3.840.0 + '@aws-sdk/util-user-agent-browser': 3.840.0 + '@aws-sdk/util-user-agent-node': 3.840.0 + '@smithy/config-resolver': 4.1.4 + '@smithy/core': 3.6.0 + '@smithy/fetch-http-handler': 5.0.4 + '@smithy/hash-node': 4.0.4 + '@smithy/invalid-dependency': 4.0.4 + '@smithy/middleware-content-length': 4.0.4 + '@smithy/middleware-endpoint': 4.1.13 + '@smithy/middleware-retry': 4.1.14 + '@smithy/middleware-serde': 4.0.8 + '@smithy/middleware-stack': 4.0.4 + '@smithy/node-config-provider': 4.1.3 + '@smithy/node-http-handler': 4.0.6 + '@smithy/protocol-http': 5.1.2 + '@smithy/smithy-client': 4.4.5 + '@smithy/types': 4.3.1 + '@smithy/url-parser': 4.0.4 '@smithy/util-base64': 4.0.0 '@smithy/util-body-length-browser': 4.0.0 '@smithy/util-body-length-node': 4.0.0 - '@smithy/util-defaults-mode-browser': 4.0.11 - '@smithy/util-defaults-mode-node': 4.0.11 - '@smithy/util-endpoints': 3.0.3 - '@smithy/util-middleware': 4.0.2 - '@smithy/util-retry': 4.0.3 + '@smithy/util-defaults-mode-browser': 4.0.21 + '@smithy/util-defaults-mode-node': 4.0.21 + '@smithy/util-endpoints': 3.0.6 + '@smithy/util-middleware': 4.0.4 + '@smithy/util-retry': 4.0.6 '@smithy/util-utf8': 4.0.0 tslib: 2.8.1 transitivePeerDependencies: - aws-crt - '@aws-sdk/core@3.806.0': - dependencies: - '@aws-sdk/types': 3.804.0 - '@smithy/core': 3.3.1 - '@smithy/node-config-provider': 4.1.0 - '@smithy/property-provider': 4.0.2 - '@smithy/protocol-http': 5.1.0 - '@smithy/signature-v4': 5.1.0 - '@smithy/smithy-client': 4.2.3 - '@smithy/types': 4.2.0 - '@smithy/util-middleware': 4.0.2 + '@aws-sdk/core@3.840.0': + dependencies: + '@aws-sdk/types': 3.840.0 + '@aws-sdk/xml-builder': 3.821.0 + '@smithy/core': 3.6.0 + '@smithy/node-config-provider': 4.1.3 + '@smithy/property-provider': 4.0.4 + '@smithy/protocol-http': 5.1.2 + '@smithy/signature-v4': 5.1.2 + '@smithy/smithy-client': 4.4.5 + '@smithy/types': 4.3.1 + '@smithy/util-base64': 4.0.0 + '@smithy/util-body-length-browser': 4.0.0 + '@smithy/util-middleware': 4.0.4 + '@smithy/util-utf8': 4.0.0 fast-xml-parser: 4.4.1 tslib: 2.8.1 - '@aws-sdk/credential-provider-env@3.806.0': + '@aws-sdk/credential-provider-env@3.840.0': dependencies: - '@aws-sdk/core': 3.806.0 - '@aws-sdk/types': 3.804.0 - '@smithy/property-provider': 4.0.2 - '@smithy/types': 4.2.0 + '@aws-sdk/core': 3.840.0 + '@aws-sdk/types': 3.840.0 + '@smithy/property-provider': 4.0.4 + '@smithy/types': 4.3.1 tslib: 2.8.1 - '@aws-sdk/credential-provider-http@3.806.0': - dependencies: - '@aws-sdk/core': 3.806.0 - '@aws-sdk/types': 3.804.0 - '@smithy/fetch-http-handler': 5.0.2 - '@smithy/node-http-handler': 4.0.4 - '@smithy/property-provider': 4.0.2 - '@smithy/protocol-http': 5.1.0 - '@smithy/smithy-client': 4.2.3 - '@smithy/types': 4.2.0 - '@smithy/util-stream': 4.2.0 + '@aws-sdk/credential-provider-http@3.840.0': + dependencies: + '@aws-sdk/core': 3.840.0 + '@aws-sdk/types': 3.840.0 + '@smithy/fetch-http-handler': 5.0.4 + '@smithy/node-http-handler': 4.0.6 + '@smithy/property-provider': 4.0.4 + '@smithy/protocol-http': 5.1.2 + '@smithy/smithy-client': 4.4.5 + '@smithy/types': 4.3.1 + '@smithy/util-stream': 4.2.2 tslib: 2.8.1 - '@aws-sdk/credential-provider-ini@3.806.0': - dependencies: - '@aws-sdk/core': 3.806.0 - '@aws-sdk/credential-provider-env': 3.806.0 - '@aws-sdk/credential-provider-http': 3.806.0 - '@aws-sdk/credential-provider-process': 3.806.0 - '@aws-sdk/credential-provider-sso': 3.806.0 - '@aws-sdk/credential-provider-web-identity': 3.806.0 - '@aws-sdk/nested-clients': 3.806.0 - '@aws-sdk/types': 3.804.0 - '@smithy/credential-provider-imds': 4.0.3 - '@smithy/property-provider': 4.0.2 - '@smithy/shared-ini-file-loader': 4.0.2 - '@smithy/types': 4.2.0 + '@aws-sdk/credential-provider-ini@3.840.0': + dependencies: + '@aws-sdk/core': 3.840.0 + '@aws-sdk/credential-provider-env': 3.840.0 + '@aws-sdk/credential-provider-http': 3.840.0 + '@aws-sdk/credential-provider-process': 3.840.0 + '@aws-sdk/credential-provider-sso': 3.840.0 + '@aws-sdk/credential-provider-web-identity': 3.840.0 + '@aws-sdk/nested-clients': 3.840.0 + '@aws-sdk/types': 3.840.0 + '@smithy/credential-provider-imds': 4.0.6 + '@smithy/property-provider': 4.0.4 + '@smithy/shared-ini-file-loader': 4.0.4 + '@smithy/types': 4.3.1 tslib: 2.8.1 transitivePeerDependencies: - aws-crt - '@aws-sdk/credential-provider-node@3.806.0': - dependencies: - '@aws-sdk/credential-provider-env': 3.806.0 - '@aws-sdk/credential-provider-http': 3.806.0 - '@aws-sdk/credential-provider-ini': 3.806.0 - '@aws-sdk/credential-provider-process': 3.806.0 - '@aws-sdk/credential-provider-sso': 3.806.0 - '@aws-sdk/credential-provider-web-identity': 3.806.0 - '@aws-sdk/types': 3.804.0 - '@smithy/credential-provider-imds': 4.0.3 - '@smithy/property-provider': 4.0.2 - '@smithy/shared-ini-file-loader': 4.0.2 - '@smithy/types': 4.2.0 + '@aws-sdk/credential-provider-node@3.840.0': + dependencies: + '@aws-sdk/credential-provider-env': 3.840.0 + '@aws-sdk/credential-provider-http': 3.840.0 + '@aws-sdk/credential-provider-ini': 3.840.0 + '@aws-sdk/credential-provider-process': 3.840.0 + '@aws-sdk/credential-provider-sso': 3.840.0 + '@aws-sdk/credential-provider-web-identity': 3.840.0 + '@aws-sdk/types': 3.840.0 + '@smithy/credential-provider-imds': 4.0.6 + '@smithy/property-provider': 4.0.4 + '@smithy/shared-ini-file-loader': 4.0.4 + '@smithy/types': 4.3.1 tslib: 2.8.1 transitivePeerDependencies: - aws-crt - '@aws-sdk/credential-provider-process@3.806.0': + '@aws-sdk/credential-provider-process@3.840.0': dependencies: - '@aws-sdk/core': 3.806.0 - '@aws-sdk/types': 3.804.0 - '@smithy/property-provider': 4.0.2 - '@smithy/shared-ini-file-loader': 4.0.2 - '@smithy/types': 4.2.0 + '@aws-sdk/core': 3.840.0 + '@aws-sdk/types': 3.840.0 + '@smithy/property-provider': 4.0.4 + '@smithy/shared-ini-file-loader': 4.0.4 + '@smithy/types': 4.3.1 tslib: 2.8.1 - '@aws-sdk/credential-provider-sso@3.806.0': + '@aws-sdk/credential-provider-sso@3.840.0': dependencies: - '@aws-sdk/client-sso': 3.806.0 - '@aws-sdk/core': 3.806.0 - '@aws-sdk/token-providers': 3.806.0 - '@aws-sdk/types': 3.804.0 - '@smithy/property-provider': 4.0.2 - '@smithy/shared-ini-file-loader': 4.0.2 - '@smithy/types': 4.2.0 + '@aws-sdk/client-sso': 3.840.0 + '@aws-sdk/core': 3.840.0 + '@aws-sdk/token-providers': 3.840.0 + '@aws-sdk/types': 3.840.0 + '@smithy/property-provider': 4.0.4 + '@smithy/shared-ini-file-loader': 4.0.4 + '@smithy/types': 4.3.1 tslib: 2.8.1 transitivePeerDependencies: - aws-crt - '@aws-sdk/credential-provider-web-identity@3.806.0': + '@aws-sdk/credential-provider-web-identity@3.840.0': dependencies: - '@aws-sdk/core': 3.806.0 - '@aws-sdk/nested-clients': 3.806.0 - '@aws-sdk/types': 3.804.0 - '@smithy/property-provider': 4.0.2 - '@smithy/types': 4.2.0 + '@aws-sdk/core': 3.840.0 + '@aws-sdk/nested-clients': 3.840.0 + '@aws-sdk/types': 3.840.0 + '@smithy/property-provider': 4.0.4 + '@smithy/types': 4.3.1 tslib: 2.8.1 transitivePeerDependencies: - aws-crt - '@aws-sdk/middleware-bucket-endpoint@3.806.0': + '@aws-sdk/middleware-bucket-endpoint@3.840.0': dependencies: - '@aws-sdk/types': 3.804.0 + '@aws-sdk/types': 3.840.0 '@aws-sdk/util-arn-parser': 3.804.0 - '@smithy/node-config-provider': 4.1.0 - '@smithy/protocol-http': 5.1.0 - '@smithy/types': 4.2.0 + '@smithy/node-config-provider': 4.1.3 + '@smithy/protocol-http': 5.1.2 + '@smithy/types': 4.3.1 '@smithy/util-config-provider': 4.0.0 tslib: 2.8.1 - '@aws-sdk/middleware-expect-continue@3.804.0': + '@aws-sdk/middleware-expect-continue@3.840.0': dependencies: - '@aws-sdk/types': 3.804.0 - '@smithy/protocol-http': 5.1.0 - '@smithy/types': 4.2.0 + '@aws-sdk/types': 3.840.0 + '@smithy/protocol-http': 5.1.2 + '@smithy/types': 4.3.1 tslib: 2.8.1 - '@aws-sdk/middleware-flexible-checksums@3.806.0': + '@aws-sdk/middleware-flexible-checksums@3.840.0': dependencies: '@aws-crypto/crc32': 5.2.0 '@aws-crypto/crc32c': 5.2.0 '@aws-crypto/util': 5.2.0 - '@aws-sdk/core': 3.806.0 - '@aws-sdk/types': 3.804.0 + '@aws-sdk/core': 3.840.0 + '@aws-sdk/types': 3.840.0 '@smithy/is-array-buffer': 4.0.0 - '@smithy/node-config-provider': 4.1.0 - '@smithy/protocol-http': 5.1.0 - '@smithy/types': 4.2.0 - '@smithy/util-middleware': 4.0.2 - '@smithy/util-stream': 4.2.0 + '@smithy/node-config-provider': 4.1.3 + '@smithy/protocol-http': 5.1.2 + '@smithy/types': 4.3.1 + '@smithy/util-middleware': 4.0.4 + '@smithy/util-stream': 4.2.2 '@smithy/util-utf8': 4.0.0 tslib: 2.8.1 - '@aws-sdk/middleware-host-header@3.804.0': + '@aws-sdk/middleware-host-header@3.840.0': dependencies: - '@aws-sdk/types': 3.804.0 - '@smithy/protocol-http': 5.1.0 - '@smithy/types': 4.2.0 + '@aws-sdk/types': 3.840.0 + '@smithy/protocol-http': 5.1.2 + '@smithy/types': 4.3.1 tslib: 2.8.1 - '@aws-sdk/middleware-location-constraint@3.804.0': + '@aws-sdk/middleware-location-constraint@3.840.0': dependencies: - '@aws-sdk/types': 3.804.0 - '@smithy/types': 4.2.0 + '@aws-sdk/types': 3.840.0 + '@smithy/types': 4.3.1 tslib: 2.8.1 - '@aws-sdk/middleware-logger@3.804.0': + '@aws-sdk/middleware-logger@3.840.0': dependencies: - '@aws-sdk/types': 3.804.0 - '@smithy/types': 4.2.0 + '@aws-sdk/types': 3.840.0 + '@smithy/types': 4.3.1 tslib: 2.8.1 - '@aws-sdk/middleware-recursion-detection@3.804.0': + '@aws-sdk/middleware-recursion-detection@3.840.0': dependencies: - '@aws-sdk/types': 3.804.0 - '@smithy/protocol-http': 5.1.0 - '@smithy/types': 4.2.0 + '@aws-sdk/types': 3.840.0 + '@smithy/protocol-http': 5.1.2 + '@smithy/types': 4.3.1 tslib: 2.8.1 - '@aws-sdk/middleware-sdk-s3@3.806.0': + '@aws-sdk/middleware-sdk-s3@3.840.0': dependencies: - '@aws-sdk/core': 3.806.0 - '@aws-sdk/types': 3.804.0 + '@aws-sdk/core': 3.840.0 + '@aws-sdk/types': 3.840.0 '@aws-sdk/util-arn-parser': 3.804.0 - '@smithy/core': 3.3.1 - '@smithy/node-config-provider': 4.1.0 - '@smithy/protocol-http': 5.1.0 - '@smithy/signature-v4': 5.1.0 - '@smithy/smithy-client': 4.2.3 - '@smithy/types': 4.2.0 + '@smithy/core': 3.6.0 + '@smithy/node-config-provider': 4.1.3 + '@smithy/protocol-http': 5.1.2 + '@smithy/signature-v4': 5.1.2 + '@smithy/smithy-client': 4.4.5 + '@smithy/types': 4.3.1 '@smithy/util-config-provider': 4.0.0 - '@smithy/util-middleware': 4.0.2 - '@smithy/util-stream': 4.2.0 + '@smithy/util-middleware': 4.0.4 + '@smithy/util-stream': 4.2.2 '@smithy/util-utf8': 4.0.0 tslib: 2.8.1 - '@aws-sdk/middleware-ssec@3.804.0': + '@aws-sdk/middleware-ssec@3.840.0': dependencies: - '@aws-sdk/types': 3.804.0 - '@smithy/types': 4.2.0 + '@aws-sdk/types': 3.840.0 + '@smithy/types': 4.3.1 tslib: 2.8.1 - '@aws-sdk/middleware-user-agent@3.806.0': + '@aws-sdk/middleware-user-agent@3.840.0': dependencies: - '@aws-sdk/core': 3.806.0 - '@aws-sdk/types': 3.804.0 - '@aws-sdk/util-endpoints': 3.806.0 - '@smithy/core': 3.3.1 - '@smithy/protocol-http': 5.1.0 - '@smithy/types': 4.2.0 + '@aws-sdk/core': 3.840.0 + '@aws-sdk/types': 3.840.0 + '@aws-sdk/util-endpoints': 3.840.0 + '@smithy/core': 3.6.0 + '@smithy/protocol-http': 5.1.2 + '@smithy/types': 4.3.1 tslib: 2.8.1 - '@aws-sdk/nested-clients@3.806.0': + '@aws-sdk/nested-clients@3.840.0': dependencies: '@aws-crypto/sha256-browser': 5.2.0 '@aws-crypto/sha256-js': 5.2.0 - '@aws-sdk/core': 3.806.0 - '@aws-sdk/middleware-host-header': 3.804.0 - '@aws-sdk/middleware-logger': 3.804.0 - '@aws-sdk/middleware-recursion-detection': 3.804.0 - '@aws-sdk/middleware-user-agent': 3.806.0 - '@aws-sdk/region-config-resolver': 3.806.0 - '@aws-sdk/types': 3.804.0 - '@aws-sdk/util-endpoints': 3.806.0 - '@aws-sdk/util-user-agent-browser': 3.804.0 - '@aws-sdk/util-user-agent-node': 3.806.0 - '@smithy/config-resolver': 4.1.1 - '@smithy/core': 3.3.1 - '@smithy/fetch-http-handler': 5.0.2 - '@smithy/hash-node': 4.0.2 - '@smithy/invalid-dependency': 4.0.2 - '@smithy/middleware-content-length': 4.0.2 - '@smithy/middleware-endpoint': 4.1.3 - '@smithy/middleware-retry': 4.1.4 - '@smithy/middleware-serde': 4.0.3 - '@smithy/middleware-stack': 4.0.2 - '@smithy/node-config-provider': 4.1.0 - '@smithy/node-http-handler': 4.0.4 - '@smithy/protocol-http': 5.1.0 - '@smithy/smithy-client': 4.2.3 - '@smithy/types': 4.2.0 - '@smithy/url-parser': 4.0.2 + '@aws-sdk/core': 3.840.0 + '@aws-sdk/middleware-host-header': 3.840.0 + '@aws-sdk/middleware-logger': 3.840.0 + '@aws-sdk/middleware-recursion-detection': 3.840.0 + '@aws-sdk/middleware-user-agent': 3.840.0 + '@aws-sdk/region-config-resolver': 3.840.0 + '@aws-sdk/types': 3.840.0 + '@aws-sdk/util-endpoints': 3.840.0 + '@aws-sdk/util-user-agent-browser': 3.840.0 + '@aws-sdk/util-user-agent-node': 3.840.0 + '@smithy/config-resolver': 4.1.4 + '@smithy/core': 3.6.0 + '@smithy/fetch-http-handler': 5.0.4 + '@smithy/hash-node': 4.0.4 + '@smithy/invalid-dependency': 4.0.4 + '@smithy/middleware-content-length': 4.0.4 + '@smithy/middleware-endpoint': 4.1.13 + '@smithy/middleware-retry': 4.1.14 + '@smithy/middleware-serde': 4.0.8 + '@smithy/middleware-stack': 4.0.4 + '@smithy/node-config-provider': 4.1.3 + '@smithy/node-http-handler': 4.0.6 + '@smithy/protocol-http': 5.1.2 + '@smithy/smithy-client': 4.4.5 + '@smithy/types': 4.3.1 + '@smithy/url-parser': 4.0.4 '@smithy/util-base64': 4.0.0 '@smithy/util-body-length-browser': 4.0.0 '@smithy/util-body-length-node': 4.0.0 - '@smithy/util-defaults-mode-browser': 4.0.11 - '@smithy/util-defaults-mode-node': 4.0.11 - '@smithy/util-endpoints': 3.0.3 - '@smithy/util-middleware': 4.0.2 - '@smithy/util-retry': 4.0.3 + '@smithy/util-defaults-mode-browser': 4.0.21 + '@smithy/util-defaults-mode-node': 4.0.21 + '@smithy/util-endpoints': 3.0.6 + '@smithy/util-middleware': 4.0.4 + '@smithy/util-retry': 4.0.6 '@smithy/util-utf8': 4.0.0 tslib: 2.8.1 transitivePeerDependencies: - aws-crt - '@aws-sdk/region-config-resolver@3.806.0': + '@aws-sdk/region-config-resolver@3.840.0': dependencies: - '@aws-sdk/types': 3.804.0 - '@smithy/node-config-provider': 4.1.0 - '@smithy/types': 4.2.0 + '@aws-sdk/types': 3.840.0 + '@smithy/node-config-provider': 4.1.3 + '@smithy/types': 4.3.1 '@smithy/util-config-provider': 4.0.0 - '@smithy/util-middleware': 4.0.2 + '@smithy/util-middleware': 4.0.4 tslib: 2.8.1 - '@aws-sdk/signature-v4-multi-region@3.806.0': + '@aws-sdk/signature-v4-multi-region@3.840.0': dependencies: - '@aws-sdk/middleware-sdk-s3': 3.806.0 - '@aws-sdk/types': 3.804.0 - '@smithy/protocol-http': 5.1.0 - '@smithy/signature-v4': 5.1.0 - '@smithy/types': 4.2.0 + '@aws-sdk/middleware-sdk-s3': 3.840.0 + '@aws-sdk/types': 3.840.0 + '@smithy/protocol-http': 5.1.2 + '@smithy/signature-v4': 5.1.2 + '@smithy/types': 4.3.1 tslib: 2.8.1 - '@aws-sdk/token-providers@3.806.0': + '@aws-sdk/token-providers@3.840.0': dependencies: - '@aws-sdk/nested-clients': 3.806.0 - '@aws-sdk/types': 3.804.0 - '@smithy/property-provider': 4.0.2 - '@smithy/shared-ini-file-loader': 4.0.2 - '@smithy/types': 4.2.0 + '@aws-sdk/core': 3.840.0 + '@aws-sdk/nested-clients': 3.840.0 + '@aws-sdk/types': 3.840.0 + '@smithy/property-provider': 4.0.4 + '@smithy/shared-ini-file-loader': 4.0.4 + '@smithy/types': 4.3.1 tslib: 2.8.1 transitivePeerDependencies: - aws-crt - '@aws-sdk/types@3.804.0': + '@aws-sdk/types@3.840.0': dependencies: - '@smithy/types': 4.2.0 + '@smithy/types': 4.3.1 tslib: 2.8.1 '@aws-sdk/util-arn-parser@3.804.0': dependencies: tslib: 2.8.1 - '@aws-sdk/util-endpoints@3.806.0': + '@aws-sdk/util-endpoints@3.840.0': dependencies: - '@aws-sdk/types': 3.804.0 - '@smithy/types': 4.2.0 - '@smithy/util-endpoints': 3.0.3 + '@aws-sdk/types': 3.840.0 + '@smithy/types': 4.3.1 + '@smithy/util-endpoints': 3.0.6 tslib: 2.8.1 '@aws-sdk/util-locate-window@3.804.0': dependencies: tslib: 2.8.1 - '@aws-sdk/util-user-agent-browser@3.804.0': + '@aws-sdk/util-user-agent-browser@3.840.0': dependencies: - '@aws-sdk/types': 3.804.0 - '@smithy/types': 4.2.0 + '@aws-sdk/types': 3.840.0 + '@smithy/types': 4.3.1 bowser: 2.11.0 tslib: 2.8.1 - '@aws-sdk/util-user-agent-node@3.806.0': + '@aws-sdk/util-user-agent-node@3.840.0': dependencies: - '@aws-sdk/middleware-user-agent': 3.806.0 - '@aws-sdk/types': 3.804.0 - '@smithy/node-config-provider': 4.1.0 - '@smithy/types': 4.2.0 + '@aws-sdk/middleware-user-agent': 3.840.0 + '@aws-sdk/types': 3.840.0 + '@smithy/node-config-provider': 4.1.3 + '@smithy/types': 4.3.1 tslib: 2.8.1 - '@aws-sdk/xml-builder@3.804.0': + '@aws-sdk/xml-builder@3.821.0': dependencies: - '@smithy/types': 4.2.0 + '@smithy/types': 4.3.1 tslib: 2.8.1 '@babel/code-frame@7.27.1': @@ -7249,57 +7572,59 @@ snapshots: js-tokens: 4.0.0 picocolors: 1.1.1 - '@babel/compat-data@7.27.2': {} + '@babel/compat-data@7.28.0': {} - '@babel/core@7.27.1': + '@babel/core@7.28.0': dependencies: '@ampproject/remapping': 2.3.0 '@babel/code-frame': 7.27.1 - '@babel/generator': 7.27.1 + '@babel/generator': 7.28.0 '@babel/helper-compilation-targets': 7.27.2 - '@babel/helper-module-transforms': 7.27.1(@babel/core@7.27.1) - '@babel/helpers': 7.27.1 - '@babel/parser': 7.27.2 + '@babel/helper-module-transforms': 7.27.3(@babel/core@7.28.0) + '@babel/helpers': 7.27.6 + '@babel/parser': 7.28.0 '@babel/template': 7.27.2 - '@babel/traverse': 7.27.1 - '@babel/types': 7.27.1 + '@babel/traverse': 7.28.0 + '@babel/types': 7.28.0 convert-source-map: 2.0.0 - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.1(supports-color@8.1.1) gensync: 1.0.0-beta.2 json5: 2.2.3 semver: 6.3.1 transitivePeerDependencies: - supports-color - '@babel/generator@7.27.1': + '@babel/generator@7.28.0': dependencies: - '@babel/parser': 7.27.2 - '@babel/types': 7.27.1 - '@jridgewell/gen-mapping': 0.3.8 - '@jridgewell/trace-mapping': 0.3.25 + '@babel/parser': 7.28.0 + '@babel/types': 7.28.0 + '@jridgewell/gen-mapping': 0.3.12 + '@jridgewell/trace-mapping': 0.3.29 jsesc: 3.1.0 '@babel/helper-compilation-targets@7.27.2': dependencies: - '@babel/compat-data': 7.27.2 + '@babel/compat-data': 7.28.0 '@babel/helper-validator-option': 7.27.1 - browserslist: 4.24.5 + browserslist: 4.25.1 lru-cache: 5.1.1 semver: 6.3.1 + '@babel/helper-globals@7.28.0': {} + '@babel/helper-module-imports@7.27.1': dependencies: - '@babel/traverse': 7.27.1 - '@babel/types': 7.27.1 + '@babel/traverse': 7.28.0 + '@babel/types': 7.28.0 transitivePeerDependencies: - supports-color - '@babel/helper-module-transforms@7.27.1(@babel/core@7.27.1)': + '@babel/helper-module-transforms@7.27.3(@babel/core@7.28.0)': dependencies: - '@babel/core': 7.27.1 + '@babel/core': 7.28.0 '@babel/helper-module-imports': 7.27.1 '@babel/helper-validator-identifier': 7.27.1 - '@babel/traverse': 7.27.1 + '@babel/traverse': 7.28.0 transitivePeerDependencies: - supports-color @@ -7311,137 +7636,154 @@ snapshots: '@babel/helper-validator-option@7.27.1': {} - '@babel/helpers@7.27.1': + '@babel/helpers@7.27.6': dependencies: '@babel/template': 7.27.2 - '@babel/types': 7.27.1 + '@babel/types': 7.28.0 - '@babel/parser@7.27.2': + '@babel/parser@7.28.0': dependencies: - '@babel/types': 7.27.1 + '@babel/types': 7.28.0 - '@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.27.1)': + '@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.28.0)': dependencies: - '@babel/core': 7.27.1 + '@babel/core': 7.28.0 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.27.1)': + '@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.28.0)': dependencies: - '@babel/core': 7.27.1 + '@babel/core': 7.28.0 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.27.1)': + '@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.28.0)': dependencies: - '@babel/core': 7.27.1 + '@babel/core': 7.28.0 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-syntax-class-static-block@7.14.5(@babel/core@7.27.1)': + '@babel/plugin-syntax-class-static-block@7.14.5(@babel/core@7.28.0)': dependencies: - '@babel/core': 7.27.1 + '@babel/core': 7.28.0 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-syntax-import-attributes@7.27.1(@babel/core@7.27.1)': + '@babel/plugin-syntax-import-attributes@7.27.1(@babel/core@7.28.0)': dependencies: - '@babel/core': 7.27.1 + '@babel/core': 7.28.0 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.27.1)': + '@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.28.0)': dependencies: - '@babel/core': 7.27.1 + '@babel/core': 7.28.0 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.27.1)': + '@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.28.0)': dependencies: - '@babel/core': 7.27.1 + '@babel/core': 7.28.0 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-syntax-jsx@7.27.1(@babel/core@7.27.1)': + '@babel/plugin-syntax-jsx@7.27.1(@babel/core@7.28.0)': dependencies: - '@babel/core': 7.27.1 + '@babel/core': 7.28.0 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.27.1)': + '@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.28.0)': dependencies: - '@babel/core': 7.27.1 + '@babel/core': 7.28.0 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.27.1)': + '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.28.0)': dependencies: - '@babel/core': 7.27.1 + '@babel/core': 7.28.0 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.27.1)': + '@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.28.0)': dependencies: - '@babel/core': 7.27.1 + '@babel/core': 7.28.0 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.27.1)': + '@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.28.0)': dependencies: - '@babel/core': 7.27.1 + '@babel/core': 7.28.0 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.27.1)': + '@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.28.0)': dependencies: - '@babel/core': 7.27.1 + '@babel/core': 7.28.0 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.27.1)': + '@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.28.0)': dependencies: - '@babel/core': 7.27.1 + '@babel/core': 7.28.0 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-syntax-private-property-in-object@7.14.5(@babel/core@7.27.1)': + '@babel/plugin-syntax-private-property-in-object@7.14.5(@babel/core@7.28.0)': dependencies: - '@babel/core': 7.27.1 + '@babel/core': 7.28.0 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.27.1)': + '@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.28.0)': dependencies: - '@babel/core': 7.27.1 + '@babel/core': 7.28.0 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-syntax-typescript@7.27.1(@babel/core@7.27.1)': + '@babel/plugin-syntax-typescript@7.27.1(@babel/core@7.28.0)': dependencies: - '@babel/core': 7.27.1 + '@babel/core': 7.28.0 '@babel/helper-plugin-utils': 7.27.1 - '@babel/runtime@7.27.1': {} + '@babel/runtime@7.27.6': {} '@babel/template@7.27.2': dependencies: '@babel/code-frame': 7.27.1 - '@babel/parser': 7.27.2 - '@babel/types': 7.27.1 + '@babel/parser': 7.28.0 + '@babel/types': 7.28.0 - '@babel/traverse@7.27.1': + '@babel/traverse@7.28.0': dependencies: '@babel/code-frame': 7.27.1 - '@babel/generator': 7.27.1 - '@babel/parser': 7.27.2 + '@babel/generator': 7.28.0 + '@babel/helper-globals': 7.28.0 + '@babel/parser': 7.28.0 '@babel/template': 7.27.2 - '@babel/types': 7.27.1 - debug: 4.4.0(supports-color@8.1.1) - globals: 11.12.0 + '@babel/types': 7.28.0 + debug: 4.4.1(supports-color@8.1.1) transitivePeerDependencies: - supports-color - '@babel/types@7.27.1': + '@babel/types@7.28.0': dependencies: '@babel/helper-string-parser': 7.27.1 '@babel/helper-validator-identifier': 7.27.1 '@bcoe/v8-coverage@0.2.3': {} - '@bundlr-network/client@0.7.17(bufferutil@4.0.9)(debug@4.4.0)(encoding@0.1.13)(typescript@5.8.3)(utf-8-validate@5.0.10)': + '@blockfrost/blockfrost-js@5.7.0': + dependencies: + '@blockfrost/openapi': 0.1.70-beta.0 + '@emurgo/cardano-serialization-lib-nodejs': 11.5.0 + '@emurgo/cip14-js': 3.0.1 + bottleneck: 2.19.5 + form-data: 4.0.3 + got: 11.8.6 + json-bigint: 1.0.0 + + '@blockfrost/openapi@0.1.70-beta.0': dependencies: - '@solana/wallet-adapter-base': 0.9.26(@solana/web3.js@1.98.2(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.8.3)(utf-8-validate@5.0.10)) + ajv: 8.17.1 + cbor: 9.0.2 + rimraf: 6.0.1 + yaml: 2.8.0 + + '@bundlr-network/client@0.7.17(bufferutil@4.0.9)(debug@4.4.1)(encoding@0.1.13)(typescript@5.8.3)(utf-8-validate@5.0.10)': + dependencies: + '@solana/wallet-adapter-base': 0.9.27(@solana/web3.js@1.98.2(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.8.3)(utf-8-validate@5.0.10)) '@solana/web3.js': 1.98.2(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.8.3)(utf-8-validate@5.0.10) '@supercharge/promise-pool': 2.4.0 algosdk: 1.24.1(encoding@0.1.13) - arbundles: 0.6.23(@solana/web3.js@1.98.2(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.8.3)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(debug@4.4.0)(encoding@0.1.13)(utf-8-validate@5.0.10) + arbundles: 0.6.23(@solana/web3.js@1.98.2(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.8.3)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(debug@4.4.1)(encoding@0.1.13)(utf-8-validate@5.0.10) arweave: 1.15.7 async-retry: 1.3.3 - axios: 0.25.0(debug@4.4.0) + axios: 0.25.0(debug@4.4.1) base64url: 3.0.1 bignumber.js: 9.3.0 bs58: 4.0.1 @@ -7565,6 +7907,13 @@ snapshots: enabled: 2.0.0 kuler: 2.0.0 + '@emurgo/cardano-serialization-lib-nodejs@11.5.0': {} + + '@emurgo/cip14-js@3.0.1': + dependencies: + bech32: 2.0.0 + blake2b: 2.1.3 + '@eslint-community/eslint-utils@4.7.0(eslint@8.57.1)': dependencies: eslint: 8.57.1 @@ -7575,7 +7924,7 @@ snapshots: '@eslint/eslintrc@2.1.4': dependencies: ajv: 6.12.6 - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.1(supports-color@8.1.1) espree: 9.6.1 globals: 13.24.0 ignore: 5.3.2 @@ -7649,7 +7998,7 @@ snapshots: lodash: 4.17.21 merkletreejs: 0.3.11 rlp: 2.2.7 - semver: 7.7.1 + semver: 7.7.2 transitivePeerDependencies: - bufferutil - encoding @@ -8051,7 +8400,7 @@ snapshots: fastify-plugin: 4.5.1 openapi-types: 12.1.3 rfdc: 1.4.1 - yaml: 2.7.1 + yaml: 2.8.0 '@fastify/swagger@8.15.0': dependencies: @@ -8059,7 +8408,7 @@ snapshots: json-schema-resolver: 2.0.0 openapi-types: 12.1.3 rfdc: 1.4.1 - yaml: 2.7.1 + yaml: 2.8.0 transitivePeerDependencies: - supports-color @@ -8076,7 +8425,7 @@ snapshots: '@humanwhocodes/config-array@0.13.0': dependencies: '@humanwhocodes/object-schema': 2.0.3 - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.1(supports-color@8.1.1) minimatch: 3.1.2 transitivePeerDependencies: - supports-color @@ -8090,6 +8439,12 @@ snapshots: browser-headers: 0.4.1 google-protobuf: 3.21.4 + '@isaacs/balanced-match@4.0.1': {} + + '@isaacs/brace-expansion@5.0.0': + dependencies: + '@isaacs/balanced-match': 4.0.1 + '@isaacs/cliui@8.0.2': dependencies: string-width: 5.1.2 @@ -8206,7 +8561,7 @@ snapshots: '@jest/test-result': 29.7.0 '@jest/transform': 29.7.0 '@jest/types': 29.6.3 - '@jridgewell/trace-mapping': 0.3.25 + '@jridgewell/trace-mapping': 0.3.29 '@types/node': 15.14.9 chalk: 4.1.2 collect-v8-coverage: 1.0.2 @@ -8240,7 +8595,7 @@ snapshots: '@jest/source-map@29.6.3': dependencies: - '@jridgewell/trace-mapping': 0.3.25 + '@jridgewell/trace-mapping': 0.3.29 callsites: 3.1.0 graceful-fs: 4.2.11 @@ -8266,9 +8621,9 @@ snapshots: '@jest/transform@29.7.0': dependencies: - '@babel/core': 7.27.1 + '@babel/core': 7.28.0 '@jest/types': 29.6.3 - '@jridgewell/trace-mapping': 0.3.25 + '@jridgewell/trace-mapping': 0.3.29 babel-plugin-istanbul: 6.1.1 chalk: 4.1.2 convert-source-map: 2.0.0 @@ -8299,27 +8654,24 @@ snapshots: '@types/yargs': 17.0.33 chalk: 4.1.2 - '@jridgewell/gen-mapping@0.3.8': + '@jridgewell/gen-mapping@0.3.12': dependencies: - '@jridgewell/set-array': 1.2.1 - '@jridgewell/sourcemap-codec': 1.5.0 - '@jridgewell/trace-mapping': 0.3.25 + '@jridgewell/sourcemap-codec': 1.5.4 + '@jridgewell/trace-mapping': 0.3.29 '@jridgewell/resolve-uri@3.1.2': {} - '@jridgewell/set-array@1.2.1': {} + '@jridgewell/sourcemap-codec@1.5.4': {} - '@jridgewell/sourcemap-codec@1.5.0': {} - - '@jridgewell/trace-mapping@0.3.25': + '@jridgewell/trace-mapping@0.3.29': dependencies: '@jridgewell/resolve-uri': 3.1.2 - '@jridgewell/sourcemap-codec': 1.5.0 + '@jridgewell/sourcemap-codec': 1.5.4 '@jridgewell/trace-mapping@0.3.9': dependencies: '@jridgewell/resolve-uri': 3.1.2 - '@jridgewell/sourcemap-codec': 1.5.0 + '@jridgewell/sourcemap-codec': 1.5.4 '@lukeed/ms@2.0.2': {} @@ -8336,10 +8688,10 @@ snapshots: '@metaplex-foundation/beet-solana@0.3.1(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.8.3)(utf-8-validate@5.0.10)': dependencies: - '@metaplex-foundation/beet': 0.6.1 + '@metaplex-foundation/beet': 0.4.0 '@solana/web3.js': 1.98.2(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.8.3)(utf-8-validate@5.0.10) bs58: 5.0.0 - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.1(supports-color@8.1.1) transitivePeerDependencies: - bufferutil - encoding @@ -8352,7 +8704,7 @@ snapshots: '@metaplex-foundation/beet': 0.7.2 '@solana/web3.js': 1.98.2(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.8.3)(utf-8-validate@5.0.10) bs58: 5.0.0 - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.1(supports-color@8.1.1) transitivePeerDependencies: - bufferutil - encoding @@ -8364,7 +8716,7 @@ snapshots: dependencies: ansicolors: 0.3.2 bn.js: 5.2.1 - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.1(supports-color@8.1.1) transitivePeerDependencies: - supports-color @@ -8372,7 +8724,7 @@ snapshots: dependencies: ansicolors: 0.3.2 bn.js: 5.2.1 - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.1(supports-color@8.1.1) transitivePeerDependencies: - supports-color @@ -8380,7 +8732,7 @@ snapshots: dependencies: ansicolors: 0.3.2 bn.js: 5.2.1 - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.1(supports-color@8.1.1) transitivePeerDependencies: - supports-color @@ -8389,7 +8741,7 @@ snapshots: ansicolors: 0.3.2 assert: 2.1.0 bn.js: 5.2.1 - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.1(supports-color@8.1.1) transitivePeerDependencies: - supports-color @@ -8397,8 +8749,8 @@ snapshots: '@metaplex-foundation/js@0.11.7(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3)(utf-8-validate@5.0.10)': dependencies: - '@aws-sdk/client-s3': 3.806.0 - '@bundlr-network/client': 0.7.17(bufferutil@4.0.9)(debug@4.4.0)(encoding@0.1.13)(typescript@5.8.3)(utf-8-validate@5.0.10) + '@aws-sdk/client-s3': 3.842.0 + '@bundlr-network/client': 0.7.17(bufferutil@4.0.9)(debug@4.4.1)(encoding@0.1.13)(typescript@5.8.3)(utf-8-validate@5.0.10) '@metaplex-foundation/beet': 0.2.0 '@metaplex-foundation/beet-solana': 0.1.1(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.8.3)(utf-8-validate@5.0.10) '@metaplex-foundation/mpl-auction-house': 2.5.1(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3)(utf-8-validate@5.0.10) @@ -8412,7 +8764,7 @@ snapshots: bs58: 5.0.0 buffer: 6.0.3 cross-fetch: 3.2.0(encoding@0.1.13) - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.1(supports-color@8.1.1) eventemitter3: 4.0.7 lodash.clonedeep: 4.5.0 mime: 3.0.0 @@ -8474,7 +8826,7 @@ snapshots: '@solana/spl-token': 0.3.11(@solana/web3.js@1.98.2(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.8.3)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3)(utf-8-validate@5.0.10) '@solana/web3.js': 1.98.2(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.8.3)(utf-8-validate@5.0.10) bn.js: 5.2.1 - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.1(supports-color@8.1.1) transitivePeerDependencies: - bufferutil - encoding @@ -8491,7 +8843,7 @@ snapshots: '@solana/spl-token': 0.4.8(@solana/web3.js@1.98.2(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.8.3)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3)(utf-8-validate@5.0.10) '@solana/web3.js': 1.98.2(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.8.3)(utf-8-validate@5.0.10) bn.js: 5.2.1 - decimal.js: 10.5.0 + decimal.js: 10.6.0 express: 4.21.2 gaussian: 1.3.0 transitivePeerDependencies: @@ -8502,6 +8854,8 @@ snapshots: - typescript - utf-8-validate + '@minswap/tiny-invariant@1.2.0': {} + '@mrmlnc/readdir-enhanced@2.2.1': dependencies: call-me-maybe: 1.0.2 @@ -8519,7 +8873,7 @@ snapshots: dependencies: '@noble/hashes': 1.7.2 - '@noble/curves@1.9.0': + '@noble/curves@1.9.2': dependencies: '@noble/hashes': 1.8.0 @@ -8551,29 +8905,29 @@ snapshots: '@nodelib/fs.scandir': 2.1.5 fastq: 1.19.1 - '@nomicfoundation/edr-darwin-arm64@0.11.0': {} + '@nomicfoundation/edr-darwin-arm64@0.11.3': {} - '@nomicfoundation/edr-darwin-x64@0.11.0': {} + '@nomicfoundation/edr-darwin-x64@0.11.3': {} - '@nomicfoundation/edr-linux-arm64-gnu@0.11.0': {} + '@nomicfoundation/edr-linux-arm64-gnu@0.11.3': {} - '@nomicfoundation/edr-linux-arm64-musl@0.11.0': {} + '@nomicfoundation/edr-linux-arm64-musl@0.11.3': {} - '@nomicfoundation/edr-linux-x64-gnu@0.11.0': {} + '@nomicfoundation/edr-linux-x64-gnu@0.11.3': {} - '@nomicfoundation/edr-linux-x64-musl@0.11.0': {} + '@nomicfoundation/edr-linux-x64-musl@0.11.3': {} - '@nomicfoundation/edr-win32-x64-msvc@0.11.0': {} + '@nomicfoundation/edr-win32-x64-msvc@0.11.3': {} - '@nomicfoundation/edr@0.11.0': + '@nomicfoundation/edr@0.11.3': dependencies: - '@nomicfoundation/edr-darwin-arm64': 0.11.0 - '@nomicfoundation/edr-darwin-x64': 0.11.0 - '@nomicfoundation/edr-linux-arm64-gnu': 0.11.0 - '@nomicfoundation/edr-linux-arm64-musl': 0.11.0 - '@nomicfoundation/edr-linux-x64-gnu': 0.11.0 - '@nomicfoundation/edr-linux-x64-musl': 0.11.0 - '@nomicfoundation/edr-win32-x64-msvc': 0.11.0 + '@nomicfoundation/edr-darwin-arm64': 0.11.3 + '@nomicfoundation/edr-darwin-x64': 0.11.3 + '@nomicfoundation/edr-linux-arm64-gnu': 0.11.3 + '@nomicfoundation/edr-linux-arm64-musl': 0.11.3 + '@nomicfoundation/edr-linux-x64-gnu': 0.11.3 + '@nomicfoundation/edr-linux-x64-musl': 0.11.3 + '@nomicfoundation/edr-win32-x64-msvc': 0.11.3 '@nomicfoundation/solidity-analyzer-darwin-arm64@0.1.2': optional: true @@ -8618,7 +8972,7 @@ snapshots: '@npmcli/fs@4.0.0': dependencies: - semver: 7.7.1 + semver: 7.7.2 '@oclif/command@1.8.36(@oclif/config@1.18.16)': dependencies: @@ -8626,8 +8980,8 @@ snapshots: '@oclif/errors': 1.3.6 '@oclif/help': 1.0.15 '@oclif/parser': 3.8.17 - debug: 4.4.0(supports-color@8.1.1) - semver: 7.7.1 + debug: 4.4.1(supports-color@8.1.1) + semver: 7.7.2 transitivePeerDependencies: - supports-color @@ -8635,7 +8989,7 @@ snapshots: dependencies: '@oclif/errors': 1.3.6 '@oclif/parser': 3.8.17 - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.1(supports-color@8.1.1) globby: 11.1.0 is-wsl: 2.2.0 tslib: 2.8.1 @@ -8651,7 +9005,7 @@ snapshots: chalk: 4.1.2 clean-stack: 3.0.1 cli-progress: 3.12.0 - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.1(supports-color@8.1.1) ejs: 3.1.10 get-package-type: 0.1.0 globby: 11.1.0 @@ -8678,23 +9032,23 @@ snapshots: - '@types/node' - typescript - '@oclif/core@4.3.0': + '@oclif/core@4.4.1': dependencies: ansi-escapes: 4.3.2 ansis: 3.17.0 clean-stack: 3.0.1 cli-spinners: 2.9.2 - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.1(supports-color@8.1.1) ejs: 3.1.10 get-package-type: 0.1.0 - globby: 11.1.0 indent-string: 4.0.0 is-wsl: 2.2.0 lilconfig: 3.1.3 minimatch: 9.0.5 - semver: 7.7.1 + semver: 7.7.2 string-width: 4.2.3 supports-color: 8.1.1 + tinyglobby: 0.2.14 widest-line: 3.1.0 wordwrap: 1.0.0 wrap-ansi: 7.0.0 @@ -8730,29 +9084,29 @@ snapshots: chalk: 4.1.2 tslib: 2.8.1 - '@oclif/plugin-autocomplete@3.2.28': + '@oclif/plugin-autocomplete@3.2.32': dependencies: - '@oclif/core': 4.3.0 + '@oclif/core': 4.4.1 ansis: 3.17.0 - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.1(supports-color@8.1.1) ejs: 3.1.10 transitivePeerDependencies: - supports-color - '@oclif/plugin-help@6.2.28': + '@oclif/plugin-help@6.2.30': dependencies: - '@oclif/core': 4.3.0 + '@oclif/core': 4.4.1 - '@oclif/plugin-plugins@5.4.37': + '@oclif/plugin-plugins@5.4.44': dependencies: - '@oclif/core': 4.3.0 + '@oclif/core': 4.4.1 ansis: 3.17.0 - debug: 4.4.0(supports-color@8.1.1) - npm: 10.9.2 + debug: 4.4.1(supports-color@8.1.1) + npm: 10.9.3 npm-package-arg: 11.0.3 npm-run-path: 5.3.0 object-treeify: 4.0.1 - semver: 7.7.1 + semver: 7.7.2 validate-npm-package-name: 5.0.1 which: 4.0.0 yarn: 1.22.22 @@ -8765,17 +9119,35 @@ snapshots: dependencies: '@solana/spl-token': 0.4.8(@solana/web3.js@1.98.2(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.8.3)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3)(utf-8-validate@5.0.10) '@solana/web3.js': 1.98.2(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.8.3)(utf-8-validate@5.0.10) - decimal.js: 10.5.0 + decimal.js: 10.6.0 tiny-invariant: 1.3.3 '@paralleldrive/cuid2@2.2.2': dependencies: '@noble/hashes': 1.8.0 + '@peculiar/asn1-schema@2.3.15': + dependencies: + asn1js: 3.0.6 + pvtsutils: 1.3.6 + tslib: 2.8.1 + + '@peculiar/json-schema@1.1.12': + dependencies: + tslib: 2.8.1 + + '@peculiar/webcrypto@1.5.0': + dependencies: + '@peculiar/asn1-schema': 2.3.15 + '@peculiar/json-schema': 1.1.12 + pvtsutils: 1.3.6 + tslib: 2.8.1 + webcrypto-core: 1.8.1 + '@pkgjs/parseargs@0.11.0': optional: true - '@pkgr/core@0.2.4': {} + '@pkgr/core@0.2.7': {} '@project-serum/anchor@0.11.1(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.8.3)(utf-8-validate@5.0.10)': dependencies: @@ -8830,7 +9202,7 @@ snapshots: '@solana/buffer-layout': 4.0.1 '@solana/spl-token': 0.4.8(@solana/web3.js@1.98.2(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.8.3)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3)(utf-8-validate@5.0.10) '@solana/web3.js': 1.98.2(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.8.3)(utf-8-validate@5.0.10) - axios: 1.9.0 + axios: 1.10.0 big.js: 6.2.2 bn.js: 5.2.1 buffer: 6.0.3 @@ -8850,7 +9222,7 @@ snapshots: '@scure/base@1.1.9': {} - '@scure/base@1.2.5': {} + '@scure/base@1.2.6': {} '@scure/bip32@1.1.5': dependencies: @@ -8946,6 +9318,8 @@ snapshots: '@sinclair/typebox@0.33.22': {} + '@sindresorhus/is@4.6.0': {} + '@sinonjs/commons@3.0.1': dependencies: type-detect: 4.0.8 @@ -8954,9 +9328,9 @@ snapshots: dependencies: '@sinonjs/commons': 3.0.1 - '@smithy/abort-controller@4.0.2': + '@smithy/abort-controller@4.0.4': dependencies: - '@smithy/types': 4.2.0 + '@smithy/types': 4.3.1 tslib: 2.8.1 '@smithy/chunked-blob-reader-native@4.0.0': @@ -8968,94 +9342,95 @@ snapshots: dependencies: tslib: 2.8.1 - '@smithy/config-resolver@4.1.1': + '@smithy/config-resolver@4.1.4': dependencies: - '@smithy/node-config-provider': 4.1.0 - '@smithy/types': 4.2.0 + '@smithy/node-config-provider': 4.1.3 + '@smithy/types': 4.3.1 '@smithy/util-config-provider': 4.0.0 - '@smithy/util-middleware': 4.0.2 + '@smithy/util-middleware': 4.0.4 tslib: 2.8.1 - '@smithy/core@3.3.1': + '@smithy/core@3.6.0': dependencies: - '@smithy/middleware-serde': 4.0.3 - '@smithy/protocol-http': 5.1.0 - '@smithy/types': 4.2.0 + '@smithy/middleware-serde': 4.0.8 + '@smithy/protocol-http': 5.1.2 + '@smithy/types': 4.3.1 + '@smithy/util-base64': 4.0.0 '@smithy/util-body-length-browser': 4.0.0 - '@smithy/util-middleware': 4.0.2 - '@smithy/util-stream': 4.2.0 + '@smithy/util-middleware': 4.0.4 + '@smithy/util-stream': 4.2.2 '@smithy/util-utf8': 4.0.0 tslib: 2.8.1 - '@smithy/credential-provider-imds@4.0.3': + '@smithy/credential-provider-imds@4.0.6': dependencies: - '@smithy/node-config-provider': 4.1.0 - '@smithy/property-provider': 4.0.2 - '@smithy/types': 4.2.0 - '@smithy/url-parser': 4.0.2 + '@smithy/node-config-provider': 4.1.3 + '@smithy/property-provider': 4.0.4 + '@smithy/types': 4.3.1 + '@smithy/url-parser': 4.0.4 tslib: 2.8.1 - '@smithy/eventstream-codec@4.0.2': + '@smithy/eventstream-codec@4.0.4': dependencies: '@aws-crypto/crc32': 5.2.0 - '@smithy/types': 4.2.0 + '@smithy/types': 4.3.1 '@smithy/util-hex-encoding': 4.0.0 tslib: 2.8.1 - '@smithy/eventstream-serde-browser@4.0.2': + '@smithy/eventstream-serde-browser@4.0.4': dependencies: - '@smithy/eventstream-serde-universal': 4.0.2 - '@smithy/types': 4.2.0 + '@smithy/eventstream-serde-universal': 4.0.4 + '@smithy/types': 4.3.1 tslib: 2.8.1 - '@smithy/eventstream-serde-config-resolver@4.1.0': + '@smithy/eventstream-serde-config-resolver@4.1.2': dependencies: - '@smithy/types': 4.2.0 + '@smithy/types': 4.3.1 tslib: 2.8.1 - '@smithy/eventstream-serde-node@4.0.2': + '@smithy/eventstream-serde-node@4.0.4': dependencies: - '@smithy/eventstream-serde-universal': 4.0.2 - '@smithy/types': 4.2.0 + '@smithy/eventstream-serde-universal': 4.0.4 + '@smithy/types': 4.3.1 tslib: 2.8.1 - '@smithy/eventstream-serde-universal@4.0.2': + '@smithy/eventstream-serde-universal@4.0.4': dependencies: - '@smithy/eventstream-codec': 4.0.2 - '@smithy/types': 4.2.0 + '@smithy/eventstream-codec': 4.0.4 + '@smithy/types': 4.3.1 tslib: 2.8.1 - '@smithy/fetch-http-handler@5.0.2': + '@smithy/fetch-http-handler@5.0.4': dependencies: - '@smithy/protocol-http': 5.1.0 - '@smithy/querystring-builder': 4.0.2 - '@smithy/types': 4.2.0 + '@smithy/protocol-http': 5.1.2 + '@smithy/querystring-builder': 4.0.4 + '@smithy/types': 4.3.1 '@smithy/util-base64': 4.0.0 tslib: 2.8.1 - '@smithy/hash-blob-browser@4.0.2': + '@smithy/hash-blob-browser@4.0.4': dependencies: '@smithy/chunked-blob-reader': 5.0.0 '@smithy/chunked-blob-reader-native': 4.0.0 - '@smithy/types': 4.2.0 + '@smithy/types': 4.3.1 tslib: 2.8.1 - '@smithy/hash-node@4.0.2': + '@smithy/hash-node@4.0.4': dependencies: - '@smithy/types': 4.2.0 + '@smithy/types': 4.3.1 '@smithy/util-buffer-from': 4.0.0 '@smithy/util-utf8': 4.0.0 tslib: 2.8.1 - '@smithy/hash-stream-node@4.0.2': + '@smithy/hash-stream-node@4.0.4': dependencies: - '@smithy/types': 4.2.0 + '@smithy/types': 4.3.1 '@smithy/util-utf8': 4.0.0 tslib: 2.8.1 - '@smithy/invalid-dependency@4.0.2': + '@smithy/invalid-dependency@4.0.4': dependencies: - '@smithy/types': 4.2.0 + '@smithy/types': 4.3.1 tslib: 2.8.1 '@smithy/is-array-buffer@2.2.0': @@ -9066,125 +9441,126 @@ snapshots: dependencies: tslib: 2.8.1 - '@smithy/md5-js@4.0.2': + '@smithy/md5-js@4.0.4': dependencies: - '@smithy/types': 4.2.0 + '@smithy/types': 4.3.1 '@smithy/util-utf8': 4.0.0 tslib: 2.8.1 - '@smithy/middleware-content-length@4.0.2': + '@smithy/middleware-content-length@4.0.4': dependencies: - '@smithy/protocol-http': 5.1.0 - '@smithy/types': 4.2.0 + '@smithy/protocol-http': 5.1.2 + '@smithy/types': 4.3.1 tslib: 2.8.1 - '@smithy/middleware-endpoint@4.1.3': + '@smithy/middleware-endpoint@4.1.13': dependencies: - '@smithy/core': 3.3.1 - '@smithy/middleware-serde': 4.0.3 - '@smithy/node-config-provider': 4.1.0 - '@smithy/shared-ini-file-loader': 4.0.2 - '@smithy/types': 4.2.0 - '@smithy/url-parser': 4.0.2 - '@smithy/util-middleware': 4.0.2 + '@smithy/core': 3.6.0 + '@smithy/middleware-serde': 4.0.8 + '@smithy/node-config-provider': 4.1.3 + '@smithy/shared-ini-file-loader': 4.0.4 + '@smithy/types': 4.3.1 + '@smithy/url-parser': 4.0.4 + '@smithy/util-middleware': 4.0.4 tslib: 2.8.1 - '@smithy/middleware-retry@4.1.4': + '@smithy/middleware-retry@4.1.14': dependencies: - '@smithy/node-config-provider': 4.1.0 - '@smithy/protocol-http': 5.1.0 - '@smithy/service-error-classification': 4.0.3 - '@smithy/smithy-client': 4.2.3 - '@smithy/types': 4.2.0 - '@smithy/util-middleware': 4.0.2 - '@smithy/util-retry': 4.0.3 + '@smithy/node-config-provider': 4.1.3 + '@smithy/protocol-http': 5.1.2 + '@smithy/service-error-classification': 4.0.6 + '@smithy/smithy-client': 4.4.5 + '@smithy/types': 4.3.1 + '@smithy/util-middleware': 4.0.4 + '@smithy/util-retry': 4.0.6 tslib: 2.8.1 uuid: 9.0.1 - '@smithy/middleware-serde@4.0.3': + '@smithy/middleware-serde@4.0.8': dependencies: - '@smithy/types': 4.2.0 + '@smithy/protocol-http': 5.1.2 + '@smithy/types': 4.3.1 tslib: 2.8.1 - '@smithy/middleware-stack@4.0.2': + '@smithy/middleware-stack@4.0.4': dependencies: - '@smithy/types': 4.2.0 + '@smithy/types': 4.3.1 tslib: 2.8.1 - '@smithy/node-config-provider@4.1.0': + '@smithy/node-config-provider@4.1.3': dependencies: - '@smithy/property-provider': 4.0.2 - '@smithy/shared-ini-file-loader': 4.0.2 - '@smithy/types': 4.2.0 + '@smithy/property-provider': 4.0.4 + '@smithy/shared-ini-file-loader': 4.0.4 + '@smithy/types': 4.3.1 tslib: 2.8.1 - '@smithy/node-http-handler@4.0.4': + '@smithy/node-http-handler@4.0.6': dependencies: - '@smithy/abort-controller': 4.0.2 - '@smithy/protocol-http': 5.1.0 - '@smithy/querystring-builder': 4.0.2 - '@smithy/types': 4.2.0 + '@smithy/abort-controller': 4.0.4 + '@smithy/protocol-http': 5.1.2 + '@smithy/querystring-builder': 4.0.4 + '@smithy/types': 4.3.1 tslib: 2.8.1 - '@smithy/property-provider@4.0.2': + '@smithy/property-provider@4.0.4': dependencies: - '@smithy/types': 4.2.0 + '@smithy/types': 4.3.1 tslib: 2.8.1 - '@smithy/protocol-http@5.1.0': + '@smithy/protocol-http@5.1.2': dependencies: - '@smithy/types': 4.2.0 + '@smithy/types': 4.3.1 tslib: 2.8.1 - '@smithy/querystring-builder@4.0.2': + '@smithy/querystring-builder@4.0.4': dependencies: - '@smithy/types': 4.2.0 + '@smithy/types': 4.3.1 '@smithy/util-uri-escape': 4.0.0 tslib: 2.8.1 - '@smithy/querystring-parser@4.0.2': + '@smithy/querystring-parser@4.0.4': dependencies: - '@smithy/types': 4.2.0 + '@smithy/types': 4.3.1 tslib: 2.8.1 - '@smithy/service-error-classification@4.0.3': + '@smithy/service-error-classification@4.0.6': dependencies: - '@smithy/types': 4.2.0 + '@smithy/types': 4.3.1 - '@smithy/shared-ini-file-loader@4.0.2': + '@smithy/shared-ini-file-loader@4.0.4': dependencies: - '@smithy/types': 4.2.0 + '@smithy/types': 4.3.1 tslib: 2.8.1 - '@smithy/signature-v4@5.1.0': + '@smithy/signature-v4@5.1.2': dependencies: '@smithy/is-array-buffer': 4.0.0 - '@smithy/protocol-http': 5.1.0 - '@smithy/types': 4.2.0 + '@smithy/protocol-http': 5.1.2 + '@smithy/types': 4.3.1 '@smithy/util-hex-encoding': 4.0.0 - '@smithy/util-middleware': 4.0.2 + '@smithy/util-middleware': 4.0.4 '@smithy/util-uri-escape': 4.0.0 '@smithy/util-utf8': 4.0.0 tslib: 2.8.1 - '@smithy/smithy-client@4.2.3': + '@smithy/smithy-client@4.4.5': dependencies: - '@smithy/core': 3.3.1 - '@smithy/middleware-endpoint': 4.1.3 - '@smithy/middleware-stack': 4.0.2 - '@smithy/protocol-http': 5.1.0 - '@smithy/types': 4.2.0 - '@smithy/util-stream': 4.2.0 + '@smithy/core': 3.6.0 + '@smithy/middleware-endpoint': 4.1.13 + '@smithy/middleware-stack': 4.0.4 + '@smithy/protocol-http': 5.1.2 + '@smithy/types': 4.3.1 + '@smithy/util-stream': 4.2.2 tslib: 2.8.1 - '@smithy/types@4.2.0': + '@smithy/types@4.3.1': dependencies: tslib: 2.8.1 - '@smithy/url-parser@4.0.2': + '@smithy/url-parser@4.0.4': dependencies: - '@smithy/querystring-parser': 4.0.2 - '@smithy/types': 4.2.0 + '@smithy/querystring-parser': 4.0.4 + '@smithy/types': 4.3.1 tslib: 2.8.1 '@smithy/util-base64@4.0.0': @@ -9215,50 +9591,50 @@ snapshots: dependencies: tslib: 2.8.1 - '@smithy/util-defaults-mode-browser@4.0.11': + '@smithy/util-defaults-mode-browser@4.0.21': dependencies: - '@smithy/property-provider': 4.0.2 - '@smithy/smithy-client': 4.2.3 - '@smithy/types': 4.2.0 + '@smithy/property-provider': 4.0.4 + '@smithy/smithy-client': 4.4.5 + '@smithy/types': 4.3.1 bowser: 2.11.0 tslib: 2.8.1 - '@smithy/util-defaults-mode-node@4.0.11': + '@smithy/util-defaults-mode-node@4.0.21': dependencies: - '@smithy/config-resolver': 4.1.1 - '@smithy/credential-provider-imds': 4.0.3 - '@smithy/node-config-provider': 4.1.0 - '@smithy/property-provider': 4.0.2 - '@smithy/smithy-client': 4.2.3 - '@smithy/types': 4.2.0 + '@smithy/config-resolver': 4.1.4 + '@smithy/credential-provider-imds': 4.0.6 + '@smithy/node-config-provider': 4.1.3 + '@smithy/property-provider': 4.0.4 + '@smithy/smithy-client': 4.4.5 + '@smithy/types': 4.3.1 tslib: 2.8.1 - '@smithy/util-endpoints@3.0.3': + '@smithy/util-endpoints@3.0.6': dependencies: - '@smithy/node-config-provider': 4.1.0 - '@smithy/types': 4.2.0 + '@smithy/node-config-provider': 4.1.3 + '@smithy/types': 4.3.1 tslib: 2.8.1 '@smithy/util-hex-encoding@4.0.0': dependencies: tslib: 2.8.1 - '@smithy/util-middleware@4.0.2': + '@smithy/util-middleware@4.0.4': dependencies: - '@smithy/types': 4.2.0 + '@smithy/types': 4.3.1 tslib: 2.8.1 - '@smithy/util-retry@4.0.3': + '@smithy/util-retry@4.0.6': dependencies: - '@smithy/service-error-classification': 4.0.3 - '@smithy/types': 4.2.0 + '@smithy/service-error-classification': 4.0.6 + '@smithy/types': 4.3.1 tslib: 2.8.1 - '@smithy/util-stream@4.2.0': + '@smithy/util-stream@4.2.2': dependencies: - '@smithy/fetch-http-handler': 5.0.2 - '@smithy/node-http-handler': 4.0.4 - '@smithy/types': 4.2.0 + '@smithy/fetch-http-handler': 5.0.4 + '@smithy/node-http-handler': 4.0.6 + '@smithy/types': 4.3.1 '@smithy/util-base64': 4.0.0 '@smithy/util-buffer-from': 4.0.0 '@smithy/util-hex-encoding': 4.0.0 @@ -9279,10 +9655,10 @@ snapshots: '@smithy/util-buffer-from': 4.0.0 tslib: 2.8.1 - '@smithy/util-waiter@4.0.3': + '@smithy/util-waiter@4.0.6': dependencies: - '@smithy/abort-controller': 4.0.2 - '@smithy/types': 4.2.0 + '@smithy/abort-controller': 4.0.4 + '@smithy/types': 4.3.1 tslib: 2.8.1 '@solana/buffer-layout-utils@0.2.0(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.8.3)(utf-8-validate@5.0.10)': @@ -9311,9 +9687,9 @@ snapshots: '@solana/errors': 2.0.0-rc.1(typescript@5.8.3) typescript: 5.8.3 - '@solana/codecs-core@2.1.0(typescript@5.8.3)': + '@solana/codecs-core@2.1.1(typescript@5.8.3)': dependencies: - '@solana/errors': 2.1.0(typescript@5.8.3) + '@solana/errors': 2.1.1(typescript@5.8.3) typescript: 5.8.3 '@solana/codecs-data-structures@2.0.0-preview.4(typescript@5.8.3)': @@ -9342,10 +9718,10 @@ snapshots: '@solana/errors': 2.0.0-rc.1(typescript@5.8.3) typescript: 5.8.3 - '@solana/codecs-numbers@2.1.0(typescript@5.8.3)': + '@solana/codecs-numbers@2.1.1(typescript@5.8.3)': dependencies: - '@solana/codecs-core': 2.1.0(typescript@5.8.3) - '@solana/errors': 2.1.0(typescript@5.8.3) + '@solana/codecs-core': 2.1.1(typescript@5.8.3) + '@solana/errors': 2.1.1(typescript@5.8.3) typescript: 5.8.3 '@solana/codecs-strings@2.0.0-preview.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3)': @@ -9398,7 +9774,7 @@ snapshots: commander: 12.1.0 typescript: 5.8.3 - '@solana/errors@2.1.0(typescript@5.8.3)': + '@solana/errors@2.1.1(typescript@5.8.3)': dependencies: chalk: 5.4.1 commander: 13.1.0 @@ -9449,7 +9825,7 @@ snapshots: '@solana/spl-token@0.1.8(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.8.3)(utf-8-validate@5.0.10)': dependencies: - '@babel/runtime': 7.27.1 + '@babel/runtime': 7.27.6 '@solana/web3.js': 1.98.2(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.8.3)(utf-8-validate@5.0.10) bn.js: 5.2.1 buffer: 6.0.3 @@ -9507,7 +9883,7 @@ snapshots: dependencies: buffer: 6.0.3 - '@solana/wallet-adapter-base@0.9.26(@solana/web3.js@1.98.2(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.8.3)(utf-8-validate@5.0.10))': + '@solana/wallet-adapter-base@0.9.27(@solana/web3.js@1.98.2(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.8.3)(utf-8-validate@5.0.10))': dependencies: '@solana/wallet-standard-features': 1.3.0 '@solana/web3.js': 1.98.2(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.8.3)(utf-8-validate@5.0.10) @@ -9522,11 +9898,11 @@ snapshots: '@solana/web3.js@1.98.2(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.8.3)(utf-8-validate@5.0.10)': dependencies: - '@babel/runtime': 7.27.1 - '@noble/curves': 1.9.0 + '@babel/runtime': 7.27.6 + '@noble/curves': 1.9.2 '@noble/hashes': 1.8.0 '@solana/buffer-layout': 4.0.1 - '@solana/codecs-numbers': 2.1.0(typescript@5.8.3) + '@solana/codecs-numbers': 2.1.1(typescript@5.8.3) agentkeepalive: 4.6.0 bn.js: 5.2.1 borsh: 0.7.0 @@ -9560,12 +9936,30 @@ snapshots: - typescript - utf-8-validate + '@sundaeswap/asset@1.0.10': + dependencies: + '@sundaeswap/fraction': 1.0.7 + + '@sundaeswap/bigint-math@0.6.3': {} + + '@sundaeswap/cpp@1.0.11(@sundaeswap/asset@1.0.10)(@sundaeswap/bigint-math@0.6.3)(@sundaeswap/fraction@1.0.7)': + dependencies: + '@sundaeswap/asset': 1.0.10 + '@sundaeswap/bigint-math': 0.6.3 + '@sundaeswap/fraction': 1.0.7 + + '@sundaeswap/fraction@1.0.7': {} + '@supercharge/promise-pool@2.4.0': {} '@swc/helpers@0.5.17': dependencies: tslib: 2.8.1 + '@szmarczak/http-timer@4.0.6': + dependencies: + defer-to-connect: 2.0.1 + '@tsconfig/node10@1.0.11': {} '@tsconfig/node12@1.0.11': {} @@ -9580,30 +9974,30 @@ snapshots: '@types/babel__core@7.20.5': dependencies: - '@babel/parser': 7.27.2 - '@babel/types': 7.27.1 + '@babel/parser': 7.28.0 + '@babel/types': 7.28.0 '@types/babel__generator': 7.27.0 '@types/babel__template': 7.4.4 '@types/babel__traverse': 7.20.7 '@types/babel__generator@7.27.0': dependencies: - '@babel/types': 7.27.1 + '@babel/types': 7.28.0 '@types/babel__template@7.4.4': dependencies: - '@babel/parser': 7.27.2 - '@babel/types': 7.27.1 + '@babel/parser': 7.28.0 + '@babel/types': 7.28.0 '@types/babel__traverse@7.20.7': dependencies: - '@babel/types': 7.27.1 + '@babel/types': 7.28.0 '@types/bn.js@5.1.6': dependencies: '@types/node': 15.14.9 - '@types/body-parser@1.19.5': + '@types/body-parser@1.19.6': dependencies: '@types/connect': 3.4.38 '@types/node': 15.14.9 @@ -9617,6 +10011,13 @@ snapshots: '@types/node': 15.14.9 base-x: 3.0.11 + '@types/cacheable-request@6.0.3': + dependencies: + '@types/http-cache-semantics': 4.0.4 + '@types/keyv': 3.1.4 + '@types/node': 15.14.9 + '@types/responselike': 1.0.3 + '@types/cli-progress@3.11.6': dependencies: '@types/node': 15.14.9 @@ -9635,16 +10036,16 @@ snapshots: '@types/express-serve-static-core@4.19.6': dependencies: '@types/node': 15.14.9 - '@types/qs': 6.9.18 + '@types/qs': 6.14.0 '@types/range-parser': 1.2.7 - '@types/send': 0.17.4 + '@types/send': 0.17.5 - '@types/express@4.17.21': + '@types/express@4.17.23': dependencies: - '@types/body-parser': 1.19.5 + '@types/body-parser': 1.19.6 '@types/express-serve-static-core': 4.19.6 - '@types/qs': 6.9.18 - '@types/serve-static': 1.15.7 + '@types/qs': 6.14.0 + '@types/serve-static': 1.15.8 '@types/fs-extra@9.0.13': dependencies: @@ -9654,7 +10055,9 @@ snapshots: dependencies: '@types/node': 15.14.9 - '@types/http-errors@2.0.4': {} + '@types/http-cache-semantics@4.0.4': {} + + '@types/http-errors@2.0.5': {} '@types/istanbul-lib-coverage@2.0.6': {} @@ -9680,6 +10083,10 @@ snapshots: '@types/json5@0.0.29': {} + '@types/keyv@3.1.4': + dependencies: + '@types/node': 15.14.9 + '@types/level-codec@9.0.4': {} '@types/level-errors@3.0.2': {} @@ -9711,7 +10118,7 @@ snapshots: '@types/node-fetch@2.6.12': dependencies: '@types/node': 15.14.9 - form-data: 4.0.2 + form-data: 4.0.3 '@types/node@11.11.6': {} @@ -9723,24 +10130,28 @@ snapshots: dependencies: '@types/node': 15.14.9 - '@types/qs@6.9.18': {} + '@types/qs@6.14.0': {} '@types/range-parser@1.2.7': {} + '@types/responselike@1.0.3': + dependencies: + '@types/node': 15.14.9 + '@types/secp256k1@4.0.6': dependencies: '@types/node': 15.14.9 - '@types/send@0.17.4': + '@types/send@0.17.5': dependencies: '@types/mime': 1.3.5 '@types/node': 15.14.9 - '@types/serve-static@1.15.7': + '@types/serve-static@1.15.8': dependencies: - '@types/http-errors': 2.0.4 + '@types/http-errors': 2.0.5 '@types/node': 15.14.9 - '@types/send': 0.17.4 + '@types/send': 0.17.5 '@types/stack-utils@1.0.1': {} @@ -9751,7 +10162,7 @@ snapshots: '@types/cookiejar': 2.1.5 '@types/methods': 1.1.4 '@types/node': 15.14.9 - form-data: 4.0.2 + form-data: 4.0.3 '@types/supertest@2.0.16': dependencies: @@ -9761,6 +10172,8 @@ snapshots: '@types/uuid@8.3.4': {} + '@types/uuid@9.0.8': {} + '@types/ws@7.4.7': dependencies: '@types/node': 15.14.9 @@ -9803,7 +10216,7 @@ snapshots: '@typescript-eslint/types': 7.18.0 '@typescript-eslint/typescript-estree': 7.18.0(typescript@5.8.3) '@typescript-eslint/visitor-keys': 7.18.0 - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.1(supports-color@8.1.1) eslint: 8.57.1 optionalDependencies: typescript: 5.8.3 @@ -9819,7 +10232,7 @@ snapshots: dependencies: '@typescript-eslint/typescript-estree': 7.18.0(typescript@5.8.3) '@typescript-eslint/utils': 7.18.0(eslint@8.57.1)(typescript@5.8.3) - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.1(supports-color@8.1.1) eslint: 8.57.1 ts-api-utils: 1.4.3(typescript@5.8.3) optionalDependencies: @@ -9833,11 +10246,11 @@ snapshots: dependencies: '@typescript-eslint/types': 7.18.0 '@typescript-eslint/visitor-keys': 7.18.0 - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.1(supports-color@8.1.1) globby: 11.1.0 is-glob: 4.0.3 minimatch: 9.0.5 - semver: 7.7.1 + semver: 7.7.2 ts-api-utils: 1.4.3(typescript@5.8.3) optionalDependencies: typescript: 5.8.3 @@ -9874,14 +10287,14 @@ snapshots: - bufferutil - utf-8-validate - '@uniswap/router-sdk@1.23.0(hardhat@2.24.0(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@15.14.9)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10))': + '@uniswap/router-sdk@1.23.0(hardhat@2.25.0(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@15.14.9)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10))': dependencies: '@ethersproject/abi': 5.8.0 '@uniswap/sdk-core': 7.7.2 - '@uniswap/swap-router-contracts': 1.3.1(hardhat@2.24.0(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@15.14.9)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10)) + '@uniswap/swap-router-contracts': 1.3.1(hardhat@2.25.0(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@15.14.9)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10)) '@uniswap/v2-sdk': 4.15.2 - '@uniswap/v3-sdk': 3.25.2(hardhat@2.24.0(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@15.14.9)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10)) - '@uniswap/v4-sdk': 1.21.4(hardhat@2.24.0(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@15.14.9)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10)) + '@uniswap/v3-sdk': 3.25.2(hardhat@2.25.0(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@15.14.9)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10)) + '@uniswap/v4-sdk': 1.21.4(hardhat@2.25.0(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@15.14.9)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10)) transitivePeerDependencies: - hardhat @@ -9924,21 +10337,21 @@ snapshots: tiny-warning: 1.0.3 toformat: 2.0.0 - '@uniswap/smart-order-router@3.59.0(bufferutil@4.0.9)(encoding@0.1.13)(hardhat@2.24.0(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@15.14.9)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10))(jsbi@3.2.5)(utf-8-validate@5.0.10)': + '@uniswap/smart-order-router@3.59.0(bufferutil@4.0.9)(encoding@0.1.13)(hardhat@2.25.0(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@15.14.9)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10))(jsbi@3.2.5)(utf-8-validate@5.0.10)': dependencies: '@eth-optimism/sdk': 3.3.3(bufferutil@4.0.9)(encoding@0.1.13)(ethers@5.8.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(utf-8-validate@5.0.10) '@types/brotli': 1.3.4 '@uniswap/default-token-list': 11.19.0 '@uniswap/permit2-sdk': 1.3.1(bufferutil@4.0.9)(utf-8-validate@5.0.10) - '@uniswap/router-sdk': 1.23.0(hardhat@2.24.0(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@15.14.9)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10)) + '@uniswap/router-sdk': 1.23.0(hardhat@2.25.0(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@15.14.9)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10)) '@uniswap/sdk-core': 5.9.0 - '@uniswap/swap-router-contracts': 1.3.1(hardhat@2.24.0(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@15.14.9)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10)) + '@uniswap/swap-router-contracts': 1.3.1(hardhat@2.25.0(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@15.14.9)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10)) '@uniswap/token-lists': 1.0.0-beta.34 '@uniswap/universal-router': 1.6.0 - '@uniswap/universal-router-sdk': 3.4.0(bufferutil@4.0.9)(hardhat@2.24.0(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@15.14.9)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10))(utf-8-validate@5.0.10) + '@uniswap/universal-router-sdk': 3.4.0(bufferutil@4.0.9)(hardhat@2.25.0(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@15.14.9)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10))(utf-8-validate@5.0.10) '@uniswap/v2-sdk': 4.15.2 - '@uniswap/v3-sdk': 3.25.2(hardhat@2.24.0(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@15.14.9)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10)) - '@uniswap/v4-sdk': 1.21.4(hardhat@2.24.0(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@15.14.9)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10)) + '@uniswap/v3-sdk': 3.25.2(hardhat@2.25.0(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@15.14.9)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10)) + '@uniswap/v4-sdk': 1.21.4(hardhat@2.25.0(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@15.14.9)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10)) async-retry: 1.3.3 await-timeout: 1.1.1 axios: 0.21.4 @@ -9960,31 +10373,31 @@ snapshots: - hardhat - utf-8-validate - '@uniswap/swap-router-contracts@1.3.1(hardhat@2.24.0(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@15.14.9)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10))': + '@uniswap/swap-router-contracts@1.3.1(hardhat@2.25.0(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@15.14.9)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10))': dependencies: '@openzeppelin/contracts': 4.9.6 '@uniswap/v2-core': 1.0.1 '@uniswap/v3-core': 1.0.1 '@uniswap/v3-periphery': 1.4.4 dotenv: 14.3.2 - hardhat-watcher: 2.5.0(hardhat@2.24.0(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@15.14.9)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10)) + hardhat-watcher: 2.5.0(hardhat@2.25.0(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@15.14.9)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10)) transitivePeerDependencies: - hardhat '@uniswap/token-lists@1.0.0-beta.34': {} - '@uniswap/universal-router-sdk@3.4.0(bufferutil@4.0.9)(hardhat@2.24.0(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@15.14.9)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10))(utf-8-validate@5.0.10)': + '@uniswap/universal-router-sdk@3.4.0(bufferutil@4.0.9)(hardhat@2.25.0(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@15.14.9)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10))(utf-8-validate@5.0.10)': dependencies: '@openzeppelin/contracts': 4.9.6 '@uniswap/permit2-sdk': 1.3.1(bufferutil@4.0.9)(utf-8-validate@5.0.10) - '@uniswap/router-sdk': 1.23.0(hardhat@2.24.0(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@15.14.9)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10)) + '@uniswap/router-sdk': 1.23.0(hardhat@2.25.0(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@15.14.9)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10)) '@uniswap/sdk-core': 5.9.0 '@uniswap/universal-router': 2.0.0-beta.1 '@uniswap/v2-core': 1.0.1 '@uniswap/v2-sdk': 4.15.2 '@uniswap/v3-core': 1.0.0 - '@uniswap/v3-sdk': 3.25.2(hardhat@2.24.0(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@15.14.9)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10)) - '@uniswap/v4-sdk': 1.21.4(hardhat@2.24.0(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@15.14.9)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10)) + '@uniswap/v3-sdk': 3.25.2(hardhat@2.25.0(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@15.14.9)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10)) + '@uniswap/v4-sdk': 1.21.4(hardhat@2.25.0(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@15.14.9)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10)) bignumber.js: 9.3.0 ethers: 5.8.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) transitivePeerDependencies: @@ -10026,12 +10439,12 @@ snapshots: '@uniswap/v3-core': 1.0.1 base64-sol: 1.0.1 - '@uniswap/v3-sdk@3.25.2(hardhat@2.24.0(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@15.14.9)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10))': + '@uniswap/v3-sdk@3.25.2(hardhat@2.25.0(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@15.14.9)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10))': dependencies: '@ethersproject/abi': 5.8.0 '@ethersproject/solidity': 5.7.0 '@uniswap/sdk-core': 7.7.2 - '@uniswap/swap-router-contracts': 1.3.1(hardhat@2.24.0(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@15.14.9)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10)) + '@uniswap/swap-router-contracts': 1.3.1(hardhat@2.25.0(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@15.14.9)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10)) '@uniswap/v3-periphery': 1.4.4 '@uniswap/v3-staker': 1.0.0 tiny-invariant: 1.3.3 @@ -10045,11 +10458,11 @@ snapshots: '@uniswap/v3-core': 1.0.0 '@uniswap/v3-periphery': 1.4.4 - '@uniswap/v4-sdk@1.21.4(hardhat@2.24.0(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@15.14.9)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10))': + '@uniswap/v4-sdk@1.21.4(hardhat@2.25.0(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@15.14.9)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10))': dependencies: '@ethersproject/solidity': 5.7.0 '@uniswap/sdk-core': 7.7.2 - '@uniswap/v3-sdk': 3.25.2(hardhat@2.24.0(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@15.14.9)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10)) + '@uniswap/v3-sdk': 3.25.2(hardhat@2.25.0(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@15.14.9)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10)) tiny-invariant: 1.3.3 tiny-warning: 1.0.3 transitivePeerDependencies: @@ -10067,11 +10480,11 @@ snapshots: abbrev@3.0.1: {} - abitype@0.8.7(typescript@5.8.3)(zod@3.24.4): + abitype@0.8.7(typescript@5.8.3)(zod@3.25.74): dependencies: typescript: 5.8.3 optionalDependencies: - zod: 3.24.4 + zod: 3.25.74 abort-controller@3.0.0: dependencies: @@ -10094,15 +10507,15 @@ snapshots: mime-types: 2.1.35 negotiator: 0.6.3 - acorn-jsx@5.3.2(acorn@8.14.1): + acorn-jsx@5.3.2(acorn@8.15.0): dependencies: - acorn: 8.14.1 + acorn: 8.15.0 acorn-walk@8.3.4: dependencies: - acorn: 8.14.1 + acorn: 8.15.0 - acorn@8.14.1: {} + acorn@8.15.0: {} adm-zip@0.4.16: {} @@ -10110,7 +10523,7 @@ snapshots: agent-base@6.0.2: dependencies: - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.1(supports-color@8.1.1) transitivePeerDependencies: - supports-color @@ -10207,16 +10620,16 @@ snapshots: app-root-path@3.1.0: {} - arbundles@0.6.23(@solana/web3.js@1.98.2(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.8.3)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(debug@4.4.0)(encoding@0.1.13)(utf-8-validate@5.0.10): + arbundles@0.6.23(@solana/web3.js@1.98.2(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.8.3)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(debug@4.4.1)(encoding@0.1.13)(utf-8-validate@5.0.10): dependencies: '@noble/ed25519': 1.7.5 '@randlabs/myalgo-connect': 1.4.2 - '@solana/wallet-adapter-base': 0.9.26(@solana/web3.js@1.98.2(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.8.3)(utf-8-validate@5.0.10)) + '@solana/wallet-adapter-base': 0.9.27(@solana/web3.js@1.98.2(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.8.3)(utf-8-validate@5.0.10)) algosdk: 1.24.1(encoding@0.1.13) arweave: 1.15.7 arweave-stream-tx: 1.2.2(arweave@1.15.7) avsc: https://codeload.github.com/Irys-xyz/avsc/tar.gz/a730cc8018b79e114b6a3381bbb57760a24c6cef - axios: 0.21.4(debug@4.4.0) + axios: 0.21.4(debug@4.4.1) base64url: 3.0.1 bs58: 4.0.1 ethers: 5.8.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) @@ -10259,14 +10672,16 @@ snapshots: array-flatten@1.1.1: {} - array-includes@3.1.8: + array-includes@3.1.9: dependencies: call-bind: 1.0.8 + call-bound: 1.0.4 define-properties: 1.2.1 - es-abstract: 1.23.9 + es-abstract: 1.24.0 es-object-atoms: 1.1.1 get-intrinsic: 1.3.0 is-string: 1.1.1 + math-intrinsics: 1.1.0 array-union@2.1.0: {} @@ -10277,7 +10692,7 @@ snapshots: call-bind: 1.0.8 call-bound: 1.0.4 define-properties: 1.2.1 - es-abstract: 1.23.9 + es-abstract: 1.24.0 es-errors: 1.3.0 es-object-atoms: 1.1.1 es-shim-unscopables: 1.1.0 @@ -10286,14 +10701,14 @@ snapshots: dependencies: call-bind: 1.0.8 define-properties: 1.2.1 - es-abstract: 1.23.9 + es-abstract: 1.24.0 es-shim-unscopables: 1.1.0 array.prototype.flatmap@1.3.3: dependencies: call-bind: 1.0.8 define-properties: 1.2.1 - es-abstract: 1.23.9 + es-abstract: 1.24.0 es-shim-unscopables: 1.1.0 arraybuffer.prototype.slice@1.0.4: @@ -10301,7 +10716,7 @@ snapshots: array-buffer-byte-length: 1.0.2 call-bind: 1.0.8 define-properties: 1.2.1 - es-abstract: 1.23.9 + es-abstract: 1.24.0 es-errors: 1.3.0 get-intrinsic: 1.3.0 is-array-buffer: 3.0.5 @@ -10327,6 +10742,12 @@ snapshots: minimalistic-assert: 1.0.1 safer-buffer: 2.1.2 + asn1js@3.0.6: + dependencies: + pvtsutils: 1.3.6 + pvutils: 1.1.3 + tslib: 2.8.1 + assert@2.1.0: dependencies: call-bind: 1.0.8 @@ -10374,40 +10795,40 @@ snapshots: transitivePeerDependencies: - debug - axios@0.21.4(debug@4.4.0): + axios@0.21.4(debug@4.4.1): dependencies: - follow-redirects: 1.15.9(debug@4.4.0) + follow-redirects: 1.15.9(debug@4.4.1) transitivePeerDependencies: - debug - axios@0.25.0(debug@4.4.0): + axios@0.25.0(debug@4.4.1): dependencies: - follow-redirects: 1.15.9(debug@4.4.0) + follow-redirects: 1.15.9(debug@4.4.1) transitivePeerDependencies: - debug axios@0.27.2(debug@4.3.4): dependencies: follow-redirects: 1.15.9(debug@4.3.4) - form-data: 4.0.2 + form-data: 4.0.3 transitivePeerDependencies: - debug - axios@1.9.0: + axios@1.10.0: dependencies: follow-redirects: 1.15.9(debug@4.3.4) - form-data: 4.0.2 + form-data: 4.0.3 proxy-from-env: 1.1.0 transitivePeerDependencies: - debug - babel-jest@29.7.0(@babel/core@7.27.1): + babel-jest@29.7.0(@babel/core@7.28.0): dependencies: - '@babel/core': 7.27.1 + '@babel/core': 7.28.0 '@jest/transform': 29.7.0 '@types/babel__core': 7.20.5 babel-plugin-istanbul: 6.1.1 - babel-preset-jest: 29.6.3(@babel/core@7.27.1) + babel-preset-jest: 29.6.3(@babel/core@7.28.0) chalk: 4.1.2 graceful-fs: 4.2.11 slash: 3.0.0 @@ -10427,34 +10848,34 @@ snapshots: babel-plugin-jest-hoist@29.6.3: dependencies: '@babel/template': 7.27.2 - '@babel/types': 7.27.1 + '@babel/types': 7.28.0 '@types/babel__core': 7.20.5 '@types/babel__traverse': 7.20.7 - babel-preset-current-node-syntax@1.1.0(@babel/core@7.27.1): - dependencies: - '@babel/core': 7.27.1 - '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.27.1) - '@babel/plugin-syntax-bigint': 7.8.3(@babel/core@7.27.1) - '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.27.1) - '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.27.1) - '@babel/plugin-syntax-import-attributes': 7.27.1(@babel/core@7.27.1) - '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.27.1) - '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.27.1) - '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.27.1) - '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.27.1) - '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.27.1) - '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.27.1) - '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.27.1) - '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.27.1) - '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.27.1) - '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.27.1) - - babel-preset-jest@29.6.3(@babel/core@7.27.1): - dependencies: - '@babel/core': 7.27.1 + babel-preset-current-node-syntax@1.1.0(@babel/core@7.28.0): + dependencies: + '@babel/core': 7.28.0 + '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.28.0) + '@babel/plugin-syntax-bigint': 7.8.3(@babel/core@7.28.0) + '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.28.0) + '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.28.0) + '@babel/plugin-syntax-import-attributes': 7.27.1(@babel/core@7.28.0) + '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.28.0) + '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.28.0) + '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.28.0) + '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.28.0) + '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.28.0) + '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.28.0) + '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.28.0) + '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.28.0) + '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.28.0) + '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.28.0) + + babel-preset-jest@29.6.3(@babel/core@7.28.0): + dependencies: + '@babel/core': 7.28.0 babel-plugin-jest-hoist: 29.6.3 - babel-preset-current-node-syntax: 1.1.0(@babel/core@7.27.1) + babel-preset-current-node-syntax: 1.1.0(@babel/core@7.28.0) balanced-match@1.0.2: {} @@ -10482,6 +10903,8 @@ snapshots: bech32@1.1.4: {} + bech32@2.0.0: {} + big.js@5.2.2: {} big.js@6.2.2: {} @@ -10501,13 +10924,13 @@ snapshots: bip39-light@1.0.7: dependencies: create-hash: 1.2.0 - pbkdf2: 3.1.2 + pbkdf2: 3.1.3 bip39@3.0.2: dependencies: '@types/node': 11.11.6 create-hash: 1.2.0 - pbkdf2: 3.1.2 + pbkdf2: 3.1.3 randombytes: 2.1.0 bl@4.1.0: @@ -10516,6 +10939,15 @@ snapshots: inherits: 2.0.4 readable-stream: 3.6.2 + blake2b-wasm@1.1.7: + dependencies: + nanoassert: 1.1.0 + + blake2b@2.1.3: + dependencies: + blake2b-wasm: 1.1.7 + nanoassert: 1.1.0 + blakejs@1.2.1: {} bluebird@3.7.2: {} @@ -10551,6 +10983,8 @@ snapshots: bs58: 4.0.1 text-encoding-utf-8: 1.0.2 + bottleneck@2.19.5: {} + bowser@2.11.0: {} boxen@5.1.2: @@ -10564,12 +10998,12 @@ snapshots: widest-line: 3.1.0 wrap-ansi: 7.0.0 - brace-expansion@1.1.11: + brace-expansion@1.1.12: dependencies: balanced-match: 1.0.2 concat-map: 0.0.1 - brace-expansion@2.0.1: + brace-expansion@2.0.2: dependencies: balanced-match: 1.0.2 @@ -10618,12 +11052,12 @@ snapshots: inherits: 2.0.4 safe-buffer: 5.2.1 - browserslist@4.24.5: + browserslist@4.25.1: dependencies: - caniuse-lite: 1.0.30001717 - electron-to-chromium: 1.5.151 + caniuse-lite: 1.0.30001727 + electron-to-chromium: 1.5.179 node-releases: 2.0.19 - update-browserslist-db: 1.1.3(browserslist@4.24.5) + update-browserslist-db: 1.1.3(browserslist@4.25.1) bs-logger@0.2.6: dependencies: @@ -10676,7 +11110,7 @@ snapshots: builtins@5.1.0: dependencies: - semver: 7.7.1 + semver: 7.7.2 bunyan-blackhole@1.1.1(bunyan@1.8.15): dependencies: @@ -10719,6 +11153,18 @@ snapshots: union-value: 1.0.1 unset-value: 1.0.0 + cacheable-lookup@5.0.4: {} + + cacheable-request@7.0.4: + dependencies: + clone-response: 1.0.3 + get-stream: 5.2.0 + http-cache-semantics: 4.2.0 + keyv: 4.5.4 + lowercase-keys: 2.0.0 + normalize-url: 6.1.0 + responselike: 2.0.1 + call-bind-apply-helpers@1.0.2: dependencies: es-errors: 1.3.0 @@ -10744,7 +11190,7 @@ snapshots: camelcase@6.3.0: {} - caniuse-lite@1.0.30001717: {} + caniuse-lite@1.0.30001727: {} capability@0.2.5: {} @@ -10755,6 +11201,10 @@ snapshots: catering@2.1.1: {} + cbor@9.0.2: + dependencies: + nofilter: 3.1.0 + chai@4.5.0: dependencies: assertion-error: 1.1.0 @@ -10870,6 +11320,10 @@ snapshots: strip-ansi: 6.0.1 wrap-ansi: 7.0.0 + clone-response@1.0.3: + dependencies: + mimic-response: 1.0.1 + clone@1.0.4: {} clone@2.1.2: {} @@ -10973,15 +11427,24 @@ snapshots: untildify: 4.0.0 yargs: 16.2.0 + core-js@3.43.0: {} + core-util-is@1.0.3: {} + create-hash@1.1.3: + dependencies: + cipher-base: 1.0.6 + inherits: 2.0.4 + ripemd160: 2.0.1 + sha.js: 2.4.12 + create-hash@1.2.0: dependencies: cipher-base: 1.0.6 inherits: 2.0.4 md5.js: 1.3.5 ripemd160: 2.0.2 - sha.js: 2.4.11 + sha.js: 2.4.12 create-hmac@1.1.7: dependencies: @@ -10990,7 +11453,7 @@ snapshots: inherits: 2.0.4 ripemd160: 2.0.2 safe-buffer: 5.2.1 - sha.js: 2.4.11 + sha.js: 2.4.12 create-jest@29.7.0(@types/node@15.14.9)(ts-node@10.9.2(@types/node@15.14.9)(typescript@5.8.3)): dependencies: @@ -11050,6 +11513,8 @@ snapshots: csv-stringify: 6.5.2 stream-transform: 3.3.3 + data-uri-to-buffer@4.0.1: {} + data-view-buffer@1.0.2: dependencies: call-bound: 1.0.4 @@ -11098,7 +11563,7 @@ snapshots: dependencies: ms: 2.1.2 - debug@4.4.0(supports-color@8.1.1): + debug@4.4.1(supports-color@8.1.1): dependencies: ms: 2.1.3 optionalDependencies: @@ -11110,10 +11575,14 @@ snapshots: decimal.js-light@2.5.1: {} - decimal.js@10.5.0: {} + decimal.js@10.6.0: {} decode-uri-component@0.2.2: {} + decompress-response@6.0.0: + dependencies: + mimic-response: 3.1.0 + dedent@1.6.0: {} deep-eql@4.1.4: @@ -11128,6 +11597,8 @@ snapshots: dependencies: clone: 1.0.4 + defer-to-connect@2.0.1: {} + define-data-property@1.1.4: dependencies: es-define-property: 1.0.1 @@ -11203,7 +11674,7 @@ snapshots: dotenv@14.3.2: {} - dotenv@16.5.0: {} + dotenv@16.6.1: {} dtrace-provider@0.8.8: dependencies: @@ -11226,7 +11697,7 @@ snapshots: dependencies: jake: 10.9.2 - electron-to-chromium@1.5.151: {} + electron-to-chromium@1.5.179: {} elliptic@6.6.1: dependencies: @@ -11255,7 +11726,7 @@ snapshots: iconv-lite: 0.6.3 optional: true - end-of-stream@1.4.4: + end-of-stream@1.4.5: dependencies: once: 1.4.0 @@ -11278,7 +11749,7 @@ snapshots: o3: 1.0.3 u3: 0.1.1 - es-abstract@1.23.9: + es-abstract@1.24.0: dependencies: array-buffer-byte-length: 1.0.2 arraybuffer.prototype.slice: 1.0.4 @@ -11307,7 +11778,9 @@ snapshots: is-array-buffer: 3.0.5 is-callable: 1.2.7 is-data-view: 1.0.2 + is-negative-zero: 2.0.3 is-regex: 1.2.1 + is-set: 2.0.3 is-shared-array-buffer: 1.0.4 is-string: 1.1.1 is-typed-array: 1.1.15 @@ -11322,6 +11795,7 @@ snapshots: safe-push-apply: 1.0.0 safe-regex-test: 1.1.0 set-proto: 1.0.0 + stop-iteration-iterator: 1.1.0 string.prototype.trim: 1.2.10 string.prototype.trimend: 1.0.9 string.prototype.trimstart: 1.0.8 @@ -11378,16 +11852,16 @@ snapshots: eslint-compat-utils@0.5.1(eslint@8.57.1): dependencies: eslint: 8.57.1 - semver: 7.7.1 + semver: 7.7.2 eslint-config-prettier@9.1.0(eslint@8.57.1): dependencies: eslint: 8.57.1 - eslint-config-standard@17.1.0(eslint-plugin-import@2.31.0(@typescript-eslint/parser@7.18.0(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1))(eslint-plugin-n@16.6.2(eslint@8.57.1))(eslint-plugin-promise@6.6.0(eslint@8.57.1))(eslint@8.57.1): + eslint-config-standard@17.1.0(eslint-plugin-import@2.32.0(@typescript-eslint/parser@7.18.0(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1))(eslint-plugin-n@16.6.2(eslint@8.57.1))(eslint-plugin-promise@6.6.0(eslint@8.57.1))(eslint@8.57.1): dependencies: eslint: 8.57.1 - eslint-plugin-import: 2.31.0(@typescript-eslint/parser@7.18.0(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1) + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@7.18.0(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1) eslint-plugin-n: 16.6.2(eslint@8.57.1) eslint-plugin-promise: 6.6.0(eslint@8.57.1) @@ -11404,7 +11878,7 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-module-utils@2.12.0(@typescript-eslint/parser@7.18.0(eslint@8.57.1)(typescript@5.8.3))(eslint-import-resolver-node@0.3.9)(eslint@8.57.1): + eslint-module-utils@2.12.1(@typescript-eslint/parser@7.18.0(eslint@8.57.1)(typescript@5.8.3))(eslint-import-resolver-node@0.3.9)(eslint@8.57.1): dependencies: debug: 3.2.7(supports-color@5.5.0) optionalDependencies: @@ -11421,10 +11895,10 @@ snapshots: eslint: 8.57.1 eslint-compat-utils: 0.5.1(eslint@8.57.1) - eslint-plugin-import@2.31.0(@typescript-eslint/parser@7.18.0(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1): + eslint-plugin-import@2.32.0(@typescript-eslint/parser@7.18.0(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1): dependencies: '@rtsao/scc': 1.1.0 - array-includes: 3.1.8 + array-includes: 3.1.9 array.prototype.findlastindex: 1.2.6 array.prototype.flat: 1.3.3 array.prototype.flatmap: 1.3.3 @@ -11432,7 +11906,7 @@ snapshots: doctrine: 2.1.0 eslint: 8.57.1 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.0(@typescript-eslint/parser@7.18.0(eslint@8.57.1)(typescript@5.8.3))(eslint-import-resolver-node@0.3.9)(eslint@8.57.1) + eslint-module-utils: 2.12.1(@typescript-eslint/parser@7.18.0(eslint@8.57.1)(typescript@5.8.3))(eslint-import-resolver-node@0.3.9)(eslint@8.57.1) hasown: 2.0.2 is-core-module: 2.16.1 is-glob: 4.0.3 @@ -11456,21 +11930,21 @@ snapshots: builtins: 5.1.0 eslint: 8.57.1 eslint-plugin-es-x: 7.8.0(eslint@8.57.1) - get-tsconfig: 4.10.0 + get-tsconfig: 4.10.1 globals: 13.24.0 ignore: 5.3.2 is-builtin-module: 3.2.1 is-core-module: 2.16.1 minimatch: 3.1.2 resolve: 1.22.10 - semver: 7.7.1 + semver: 7.7.2 - eslint-plugin-prettier@5.4.0(eslint-config-prettier@9.1.0(eslint@8.57.1))(eslint@8.57.1)(prettier@3.5.3): + eslint-plugin-prettier@5.5.1(eslint-config-prettier@9.1.0(eslint@8.57.1))(eslint@8.57.1)(prettier@3.6.2): dependencies: eslint: 8.57.1 - prettier: 3.5.3 + prettier: 3.6.2 prettier-linter-helpers: 1.0.0 - synckit: 0.11.4 + synckit: 0.11.8 optionalDependencies: eslint-config-prettier: 9.1.0(eslint@8.57.1) @@ -11502,7 +11976,7 @@ snapshots: ajv: 6.12.6 chalk: 4.1.2 cross-spawn: 7.0.6 - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.1(supports-color@8.1.1) doctrine: 3.0.0 escape-string-regexp: 4.0.0 eslint-scope: 7.2.2 @@ -11534,8 +12008,8 @@ snapshots: espree@9.6.1: dependencies: - acorn: 8.14.1 - acorn-jsx: 5.3.2(acorn@8.14.1) + acorn: 8.15.0 + acorn-jsx: 5.3.2(acorn@8.15.0) eslint-visitor-keys: 3.4.3 esprima@4.0.1: {} @@ -11569,7 +12043,7 @@ snapshots: create-hmac: 1.1.7 hash.js: 1.1.7 keccak: 3.0.4 - pbkdf2: 3.1.2 + pbkdf2: 3.1.3 randombytes: 2.1.0 safe-buffer: 5.2.1 scrypt-js: 3.0.1 @@ -11854,11 +12328,11 @@ snapshots: fastify-plugin@4.5.1: {} - fastify-type-provider-zod@2.1.0(fastify@4.29.1)(zod@3.24.4): + fastify-type-provider-zod@2.1.0(fastify@4.29.1)(zod@3.25.74): dependencies: fastify: 4.29.1 - zod: 3.24.4 - zod-to-json-schema: 3.24.5(zod@3.24.4) + zod: 3.25.74 + zod-to-json-schema: 3.24.6(zod@3.25.74) fastify@4.29.1: dependencies: @@ -11871,12 +12345,12 @@ snapshots: fast-json-stringify: 5.16.1 find-my-way: 8.2.2 light-my-request: 5.14.0 - pino: 9.6.0 + pino: 9.7.0 process-warning: 3.0.0 proxy-addr: 2.0.7 rfdc: 1.4.1 secure-json-parse: 2.7.0 - semver: 7.7.1 + semver: 7.7.2 toad-cache: 3.7.0 fastq@1.19.1: @@ -11887,12 +12361,17 @@ snapshots: dependencies: bser: 2.1.1 - fdir@6.4.4(picomatch@4.0.2): + fdir@6.4.6(picomatch@4.0.2): optionalDependencies: picomatch: 4.0.2 fecha@4.2.3: {} + fetch-blob@3.2.0: + dependencies: + node-domexception: 1.0.0 + web-streams-polyfill: 3.3.3 + figures@3.2.0: dependencies: escape-string-regexp: 1.0.5 @@ -11974,9 +12453,9 @@ snapshots: optionalDependencies: debug: 4.3.4 - follow-redirects@1.15.9(debug@4.4.0): + follow-redirects@1.15.9(debug@4.4.1): optionalDependencies: - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.1(supports-color@8.1.1) for-each@0.3.5: dependencies: @@ -11996,13 +12475,18 @@ snapshots: es-set-tostringtag: 2.1.0 mime-types: 2.1.35 - form-data@4.0.2: + form-data@4.0.3: dependencies: asynckit: 0.4.0 combined-stream: 1.0.8 es-set-tostringtag: 2.1.0 + hasown: 2.0.2 mime-types: 2.1.35 + formdata-polyfill@4.0.10: + dependencies: + fetch-blob: 3.2.0 + formidable@3.5.4: dependencies: '@paralleldrive/cuid2': 2.2.2 @@ -12097,7 +12581,11 @@ snapshots: get-stream@4.1.0: dependencies: - pump: 3.0.2 + pump: 3.0.3 + + get-stream@5.2.0: + dependencies: + pump: 3.0.3 get-stream@6.0.1: {} @@ -12107,7 +12595,7 @@ snapshots: es-errors: 1.3.0 get-intrinsic: 1.3.0 - get-tsconfig@4.10.0: + get-tsconfig@4.10.1: dependencies: resolve-pkg-maps: 1.0.0 @@ -12137,6 +12625,15 @@ snapshots: package-json-from-dist: 1.0.1 path-scurry: 1.11.1 + glob@11.0.3: + dependencies: + foreground-child: 3.3.1 + jackspeak: 4.1.1 + minimatch: 10.0.3 + minipass: 7.1.2 + package-json-from-dist: 1.0.1 + path-scurry: 2.0.0 + glob@6.0.4: dependencies: inflight: 1.0.6 @@ -12151,7 +12648,7 @@ snapshots: fs.realpath: 1.0.0 inflight: 1.0.6 inherits: 2.0.4 - minimatch: 3.1.2 + minimatch: 3.0.4 once: 1.4.0 path-is-absolute: 1.0.1 @@ -12172,8 +12669,6 @@ snapshots: minimatch: 5.1.6 once: 1.4.0 - globals@11.12.0: {} - globals@13.24.0: dependencies: type-fest: 0.20.2 @@ -12200,6 +12695,20 @@ snapshots: gopd@1.2.0: {} + got@11.8.6: + dependencies: + '@sindresorhus/is': 4.6.0 + '@szmarczak/http-timer': 4.0.6 + '@types/cacheable-request': 6.0.3 + '@types/responselike': 1.0.3 + cacheable-lookup: 5.0.4 + cacheable-request: 7.0.4 + decompress-response: 6.0.0 + http2-wrapper: 1.0.3 + lowercase-keys: 2.0.0 + p-cancelable: 2.1.1 + responselike: 2.0.1 + graceful-fs@4.2.11: {} graphemer@1.4.0: {} @@ -12219,16 +12728,16 @@ snapshots: growl@1.10.5: {} - hardhat-watcher@2.5.0(hardhat@2.24.0(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@15.14.9)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10)): + hardhat-watcher@2.5.0(hardhat@2.25.0(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@15.14.9)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10)): dependencies: chokidar: 3.6.0 - hardhat: 2.24.0(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@15.14.9)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10) + hardhat: 2.25.0(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@15.14.9)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10) - hardhat@2.24.0(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@15.14.9)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10): + hardhat@2.25.0(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@15.14.9)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10): dependencies: '@ethereumjs/util': 9.1.0 '@ethersproject/abi': 5.8.0 - '@nomicfoundation/edr': 0.11.0 + '@nomicfoundation/edr': 0.11.3 '@nomicfoundation/solidity-analyzer': 0.1.2 '@sentry/node': 5.30.0 '@types/bn.js': 5.1.6 @@ -12239,7 +12748,7 @@ snapshots: boxen: 5.1.2 chokidar: 4.0.3 ci-info: 2.0.0 - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.1(supports-color@8.1.1) enquirer: 2.4.1 env-paths: 2.2.1 ethereum-cryptography: 1.2.0 @@ -12259,10 +12768,10 @@ snapshots: raw-body: 2.5.2 resolve: 1.17.0 semver: 6.3.1 - solc: 0.8.26(debug@4.4.0) + solc: 0.8.26(debug@4.4.1) source-map-support: 0.5.21 stacktrace-parser: 0.1.11 - tinyglobby: 0.2.13 + tinyglobby: 0.2.14 tsort: 0.0.1 undici: 5.29.0 uuid: 8.3.2 @@ -12316,6 +12825,10 @@ snapshots: is-number: 3.0.0 kind-of: 4.0.0 + hash-base@2.0.2: + dependencies: + inherits: 2.0.4 + hash-base@3.1.0: dependencies: inherits: 2.0.4 @@ -12372,21 +12885,26 @@ snapshots: http-proxy-agent@7.0.2: dependencies: agent-base: 7.1.3 - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.1(supports-color@8.1.1) transitivePeerDependencies: - supports-color + http2-wrapper@1.0.3: + dependencies: + quick-lru: 5.1.1 + resolve-alpn: 1.2.1 + https-proxy-agent@5.0.1: dependencies: agent-base: 6.0.2 - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.1(supports-color@8.1.1) transitivePeerDependencies: - supports-color https-proxy-agent@7.0.6: dependencies: agent-base: 7.1.3 - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.1(supports-color@8.1.1) transitivePeerDependencies: - supports-color @@ -12604,6 +13122,8 @@ snapshots: call-bind: 1.0.8 define-properties: 1.2.1 + is-negative-zero@2.0.3: {} + is-number-object@1.1.1: dependencies: call-bound: 1.0.4 @@ -12704,8 +13224,8 @@ snapshots: istanbul-lib-instrument@5.2.1: dependencies: - '@babel/core': 7.27.1 - '@babel/parser': 7.27.2 + '@babel/core': 7.28.0 + '@babel/parser': 7.28.0 '@istanbuljs/schema': 0.1.3 istanbul-lib-coverage: 3.2.2 semver: 6.3.1 @@ -12714,11 +13234,11 @@ snapshots: istanbul-lib-instrument@6.0.3: dependencies: - '@babel/core': 7.27.1 - '@babel/parser': 7.27.2 + '@babel/core': 7.28.0 + '@babel/parser': 7.28.0 '@istanbuljs/schema': 0.1.3 istanbul-lib-coverage: 3.2.2 - semver: 7.7.1 + semver: 7.7.2 transitivePeerDependencies: - supports-color @@ -12730,7 +13250,7 @@ snapshots: istanbul-lib-source-maps@4.0.1: dependencies: - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.1(supports-color@8.1.1) istanbul-lib-coverage: 3.2.2 source-map: 0.6.1 transitivePeerDependencies: @@ -12747,6 +13267,10 @@ snapshots: optionalDependencies: '@pkgjs/parseargs': 0.11.0 + jackspeak@4.1.1: + dependencies: + '@isaacs/cliui': 8.0.2 + jacoco-parse@2.0.1: dependencies: mocha: 5.2.0 @@ -12832,10 +13356,10 @@ snapshots: jest-config@29.7.0(@types/node@15.14.9)(ts-node@10.9.2(@types/node@15.14.9)(typescript@5.8.3)): dependencies: - '@babel/core': 7.27.1 + '@babel/core': 7.28.0 '@jest/test-sequencer': 29.7.0 '@jest/types': 29.6.3 - babel-jest: 29.7.0(@babel/core@7.27.1) + babel-jest: 29.7.0(@babel/core@7.28.0) chalk: 4.1.2 ci-info: 3.9.0 deepmerge: 4.3.1 @@ -13064,15 +13588,15 @@ snapshots: jest-snapshot@29.7.0: dependencies: - '@babel/core': 7.27.1 - '@babel/generator': 7.27.1 - '@babel/plugin-syntax-jsx': 7.27.1(@babel/core@7.27.1) - '@babel/plugin-syntax-typescript': 7.27.1(@babel/core@7.27.1) - '@babel/types': 7.27.1 + '@babel/core': 7.28.0 + '@babel/generator': 7.28.0 + '@babel/plugin-syntax-jsx': 7.27.1(@babel/core@7.28.0) + '@babel/plugin-syntax-typescript': 7.27.1(@babel/core@7.28.0) + '@babel/types': 7.28.0 '@jest/expect-utils': 29.7.0 '@jest/transform': 29.7.0 '@jest/types': 29.6.3 - babel-preset-current-node-syntax: 1.1.0(@babel/core@7.27.1) + babel-preset-current-node-syntax: 1.1.0(@babel/core@7.28.0) chalk: 4.1.2 expect: 29.7.0 graceful-fs: 4.2.11 @@ -13083,7 +13607,7 @@ snapshots: jest-util: 29.7.0 natural-compare: 1.4.0 pretty-format: 29.7.0 - semver: 7.7.1 + semver: 7.7.2 transitivePeerDependencies: - supports-color @@ -13182,7 +13706,7 @@ snapshots: json-schema-resolver@2.0.0: dependencies: - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.1(supports-color@8.1.1) rfdc: 1.4.1 uri-js: 4.4.1 transitivePeerDependencies: @@ -13325,8 +13849,12 @@ snapshots: dependencies: tslib: 2.8.1 + lowercase-keys@2.0.0: {} + lru-cache@10.4.3: {} + lru-cache@11.1.0: {} + lru-cache@5.1.1: dependencies: yallist: 3.1.1 @@ -13335,7 +13863,7 @@ snapshots: make-dir@4.0.0: dependencies: - semver: 7.7.1 + semver: 7.7.2 make-error@1.3.6: {} @@ -13375,9 +13903,9 @@ snapshots: mathjs@10.6.4: dependencies: - '@babel/runtime': 7.27.1 + '@babel/runtime': 7.27.6 complex.js: 2.4.2 - decimal.js: 10.5.0 + decimal.js: 10.6.0 escape-latex: 1.2.0 fraction.js: 4.3.7 javascript-natural-sort: 0.7.1 @@ -13425,7 +13953,7 @@ snapshots: micro-packed@0.7.3: dependencies: - '@scure/base': 1.2.5 + '@scure/base': 1.2.6 micromatch@3.1.10: dependencies: @@ -13464,25 +13992,33 @@ snapshots: mimic-fn@2.1.0: {} + mimic-response@1.0.1: {} + + mimic-response@3.1.0: {} + minimalistic-assert@1.0.1: {} minimalistic-crypto-utils@1.0.1: {} + minimatch@10.0.3: + dependencies: + '@isaacs/brace-expansion': 5.0.0 + minimatch@3.0.4: dependencies: - brace-expansion: 1.1.11 + brace-expansion: 1.1.12 minimatch@3.1.2: dependencies: - brace-expansion: 1.1.11 + brace-expansion: 1.1.12 minimatch@5.1.6: dependencies: - brace-expansion: 2.0.1 + brace-expansion: 2.0.2 minimatch@9.0.5: dependencies: - brace-expansion: 2.0.1 + brace-expansion: 2.0.2 minimist@0.2.4: {} @@ -13536,7 +14072,7 @@ snapshots: ansi-colors: 4.1.3 browser-stdout: 1.3.1 chokidar: 3.6.0 - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.1(supports-color@8.1.1) diff: 5.2.0 escape-string-regexp: 4.0.0 find-up: 5.0.0 @@ -13617,6 +14153,8 @@ snapshots: nan@2.22.2: optional: true + nanoassert@1.1.0: {} + nanomatch@1.2.13: dependencies: arr-diff: 4.0.0 @@ -13692,6 +14230,8 @@ snapshots: dependencies: clone: 2.1.2 + node-domexception@1.0.0: {} + node-fetch@2.6.1: {} node-fetch@2.7.0(encoding@0.1.13): @@ -13700,6 +14240,12 @@ snapshots: optionalDependencies: encoding: 0.1.13 + node-fetch@3.3.2: + dependencies: + data-uri-to-buffer: 4.0.1 + fetch-blob: 3.2.0 + formdata-polyfill: 4.0.10 + node-gyp-build@4.8.4: {} node-gyp@11.2.0: @@ -13710,9 +14256,9 @@ snapshots: make-fetch-happen: 14.0.3 nopt: 8.1.0 proc-log: 5.0.0 - semver: 7.7.1 + semver: 7.7.2 tar: 7.4.3 - tinyglobby: 0.2.13 + tinyglobby: 0.2.14 which: 5.0.0 transitivePeerDependencies: - supports-color @@ -13734,6 +14280,8 @@ snapshots: touch: 3.1.1 undefsafe: 2.0.5 + nofilter@3.1.0: {} + noms@0.0.0: dependencies: inherits: 2.0.4 @@ -13745,11 +14293,13 @@ snapshots: normalize-path@3.0.0: {} + normalize-url@6.1.0: {} + npm-package-arg@11.0.3: dependencies: hosted-git-info: 7.0.2 proc-log: 4.2.0 - semver: 7.7.1 + semver: 7.7.2 validate-npm-package-name: 5.0.1 npm-run-path@2.0.2: @@ -13764,7 +14314,7 @@ snapshots: dependencies: path-key: 4.0.0 - npm@10.9.2: {} + npm@10.9.3: {} number-is-nan@1.0.1: {} @@ -13815,14 +14365,14 @@ snapshots: dependencies: call-bind: 1.0.8 define-properties: 1.2.1 - es-abstract: 1.23.9 + es-abstract: 1.24.0 es-object-atoms: 1.1.1 object.groupby@1.0.3: dependencies: call-bind: 1.0.8 define-properties: 1.2.1 - es-abstract: 1.23.9 + es-abstract: 1.24.0 object.pick@1.3.0: dependencies: @@ -13892,6 +14442,8 @@ snapshots: object-keys: 1.1.1 safe-push-apply: 1.0.0 + p-cancelable@2.1.1: {} + p-defer@1.0.0: {} p-finally@1.0.0: {} @@ -13971,6 +14523,11 @@ snapshots: lru-cache: 10.4.3 minipass: 7.1.2 + path-scurry@2.0.0: + dependencies: + lru-cache: 11.1.0 + minipass: 7.1.2 + path-to-regexp@0.1.12: {} path-type@4.0.0: {} @@ -13981,13 +14538,14 @@ snapshots: dependencies: through: 2.3.8 - pbkdf2@3.1.2: + pbkdf2@3.1.3: dependencies: - create-hash: 1.2.0 + create-hash: 1.1.3 create-hmac: 1.1.7 - ripemd160: 2.0.2 + ripemd160: 2.0.1 safe-buffer: 5.2.1 - sha.js: 2.4.11 + sha.js: 2.4.12 + to-buffer: 1.2.1 picocolors@1.1.1: {} @@ -14010,7 +14568,7 @@ snapshots: minimist: 0.2.4 on-exit-leak-free: 2.1.2 pino-abstract-transport: 2.0.0 - pump: 3.0.2 + pump: 3.0.3 readable-stream: 4.7.0 secure-json-parse: 2.7.0 sonic-boom: 4.2.0 @@ -14018,14 +14576,14 @@ snapshots: pino-std-serializers@7.0.0: {} - pino@9.6.0: + pino@9.7.0: dependencies: atomic-sleep: 1.0.0 fast-redact: 3.5.0 on-exit-leak-free: 2.1.2 pino-abstract-transport: 2.0.0 pino-std-serializers: 7.0.0 - process-warning: 4.0.1 + process-warning: 5.0.0 quick-format-unescaped: 4.0.4 real-require: 0.2.0 safe-stable-stringify: 2.5.0 @@ -14038,7 +14596,7 @@ snapshots: dependencies: find-up: 4.1.0 - pnpm@10.10.0: {} + pnpm@10.12.4: {} posix-character-classes@0.1.1: {} @@ -14050,7 +14608,7 @@ snapshots: dependencies: fast-diff: 1.3.0 - prettier@3.5.3: {} + prettier@3.6.2: {} pretty-format@22.4.3: dependencies: @@ -14078,7 +14636,7 @@ snapshots: process-warning@3.0.0: {} - process-warning@4.0.1: {} + process-warning@5.0.0: {} process@0.11.10: {} @@ -14105,23 +14663,35 @@ snapshots: pstree.remy@1.1.8: {} - pump@3.0.2: + pump@3.0.3: dependencies: - end-of-stream: 1.4.4 + end-of-stream: 1.4.5 once: 1.4.0 punycode@2.3.1: {} pure-rand@6.1.0: {} + pvtsutils@1.3.6: + dependencies: + tslib: 2.8.1 + + pvutils@1.1.3: {} + qs@6.13.0: dependencies: side-channel: 1.1.0 + qs@6.14.0: + dependencies: + side-channel: 1.1.0 + queue-microtask@1.2.3: {} quick-format-unescaped@4.0.4: {} + quick-lru@5.1.1: {} + randombytes@2.1.0: dependencies: safe-buffer: 5.2.1 @@ -14196,7 +14766,7 @@ snapshots: dependencies: call-bind: 1.0.8 define-properties: 1.2.1 - es-abstract: 1.23.9 + es-abstract: 1.24.0 es-errors: 1.3.0 es-object-atoms: 1.1.1 get-intrinsic: 1.3.0 @@ -14229,6 +14799,8 @@ snapshots: require-main-filename@1.0.1: {} + resolve-alpn@1.2.1: {} + resolve-cwd@3.0.0: dependencies: resolve-from: 5.0.0 @@ -14253,6 +14825,10 @@ snapshots: path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 + responselike@2.0.1: + dependencies: + lowercase-keys: 2.0.0 + restore-cursor@3.1.0: dependencies: onetime: 5.1.2 @@ -14279,6 +14855,16 @@ snapshots: dependencies: glob: 7.2.3 + rimraf@6.0.1: + dependencies: + glob: 11.0.3 + package-json-from-dist: 1.0.1 + + ripemd160@2.0.1: + dependencies: + hash-base: 2.0.2 + inherits: 2.0.4 + ripemd160@2.0.2: dependencies: hash-base: 3.1.0 @@ -14296,7 +14882,7 @@ snapshots: buffer: 6.0.3 eventemitter3: 5.0.1 uuid: 8.3.2 - ws: 8.18.2(bufferutil@4.0.9)(utf-8-validate@5.0.10) + ws: 8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10) optionalDependencies: bufferutil: 4.0.9 utf-8-validate: 5.0.10 @@ -14381,7 +14967,7 @@ snapshots: semver@7.0.0: {} - semver@7.7.1: {} + semver@7.7.2: {} send@0.19.0: dependencies: @@ -14451,10 +15037,15 @@ snapshots: setprototypeof@1.2.0: {} - sha.js@2.4.11: + sha.js@2.4.12: dependencies: inherits: 2.0.4 safe-buffer: 5.2.1 + to-buffer: 1.2.1 + + sha3@2.1.4: + dependencies: + buffer: 6.0.3 shebang-command@1.2.0: dependencies: @@ -14557,21 +15148,21 @@ snapshots: socks-proxy-agent@8.0.5: dependencies: agent-base: 7.1.3 - debug: 4.4.0(supports-color@8.1.1) - socks: 2.8.4 + debug: 4.4.1(supports-color@8.1.1) + socks: 2.8.5 transitivePeerDependencies: - supports-color - socks@2.8.4: + socks@2.8.5: dependencies: ip-address: 9.0.5 smart-buffer: 4.2.0 - solc@0.8.26(debug@4.4.0): + solc@0.8.26(debug@4.4.1): dependencies: command-exists: 1.2.9 commander: 8.3.0 - follow-redirects: 1.15.9(debug@4.4.0) + follow-redirects: 1.15.9(debug@4.4.1) js-sha3: 0.8.0 memorystream: 0.3.1 semver: 5.7.2 @@ -14665,6 +15256,11 @@ snapshots: statuses@2.0.1: {} + stop-iteration-iterator@1.1.0: + dependencies: + es-errors: 1.3.0 + internal-slot: 1.1.0 + stream-blackhole@1.0.3: {} stream-chain@2.2.5: {} @@ -14713,7 +15309,7 @@ snapshots: call-bound: 1.0.4 define-data-property: 1.1.4 define-properties: 1.2.1 - es-abstract: 1.23.9 + es-abstract: 1.24.0 es-object-atoms: 1.1.1 has-property-descriptors: 1.0.2 @@ -14776,17 +15372,17 @@ snapshots: strnum@1.1.2: {} - superagent@9.0.2: + superagent@10.2.1: dependencies: component-emitter: 1.3.1 cookiejar: 2.1.4 - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.1(supports-color@8.1.1) fast-safe-stringify: 2.1.1 - form-data: 4.0.2 + form-data: 4.0.3 formidable: 3.5.4 methods: 1.1.2 mime: 2.6.0 - qs: 6.13.0 + qs: 6.14.0 transitivePeerDependencies: - supports-color @@ -14794,10 +15390,10 @@ snapshots: superstruct@2.0.2: {} - supertest@7.1.0: + supertest@7.1.1: dependencies: methods: 1.1.2 - superagent: 9.0.2 + superagent: 10.2.1 transitivePeerDependencies: - supports-color @@ -14828,10 +15424,9 @@ snapshots: supports-preserve-symlinks-flag@1.0.0: {} - synckit@0.11.4: + synckit@0.11.8: dependencies: - '@pkgr/core': 0.2.4 - tslib: 2.8.1 + '@pkgr/core': 0.2.7 table@6.9.0: dependencies: @@ -14879,9 +15474,9 @@ snapshots: tiny-warning@1.0.3: {} - tinyglobby@0.2.13: + tinyglobby@0.2.14: dependencies: - fdir: 6.4.4(picomatch@4.0.2) + fdir: 6.4.6(picomatch@4.0.2) picomatch: 4.0.2 tmp-promise@3.0.3: @@ -14896,6 +15491,12 @@ snapshots: tmpl@1.0.5: {} + to-buffer@1.2.1: + dependencies: + isarray: 2.0.5 + safe-buffer: 5.2.1 + typed-array-buffer: 1.0.3 + to-object-path@0.3.0: dependencies: kind-of: 3.2.2 @@ -14938,25 +15539,25 @@ snapshots: dependencies: typescript: 5.8.3 - ts-jest@29.3.2(@babel/core@7.27.1)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.27.1))(jest@29.7.0(@types/node@15.14.9)(ts-node@10.9.2(@types/node@15.14.9)(typescript@5.8.3)))(typescript@5.8.3): + ts-jest@29.4.0(@babel/core@7.28.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.28.0))(jest-util@29.7.0)(jest@29.7.0(@types/node@15.14.9)(ts-node@10.9.2(@types/node@15.14.9)(typescript@5.8.3)))(typescript@5.8.3): dependencies: bs-logger: 0.2.6 ejs: 3.1.10 fast-json-stable-stringify: 2.1.0 jest: 29.7.0(@types/node@15.14.9)(ts-node@10.9.2(@types/node@15.14.9)(typescript@5.8.3)) - jest-util: 29.7.0 json5: 2.2.3 lodash.memoize: 4.1.2 make-error: 1.3.6 - semver: 7.7.1 + semver: 7.7.2 type-fest: 4.41.0 typescript: 5.8.3 yargs-parser: 21.1.1 optionalDependencies: - '@babel/core': 7.27.1 + '@babel/core': 7.28.0 '@jest/transform': 29.7.0 '@jest/types': 29.6.3 - babel-jest: 29.7.0(@babel/core@7.27.1) + babel-jest: 29.7.0(@babel/core@7.28.0) + jest-util: 29.7.0 ts-node@10.9.2(@types/node@15.14.9)(typescript@5.8.3): dependencies: @@ -14966,7 +15567,7 @@ snapshots: '@tsconfig/node14': 1.0.3 '@tsconfig/node16': 1.0.4 '@types/node': 15.14.9 - acorn: 8.14.1 + acorn: 8.15.0 acorn-walk: 8.3.4 arg: 4.1.3 create-require: 1.1.1 @@ -15092,9 +15693,9 @@ snapshots: untildify@4.0.0: {} - update-browserslist-db@1.1.3(browserslist@4.24.5): + update-browserslist-db@1.1.3(browserslist@4.25.1): dependencies: - browserslist: 4.24.5 + browserslist: 4.25.1 escalade: 3.2.0 picocolors: 1.1.1 @@ -15133,7 +15734,7 @@ snapshots: v8-to-istanbul@9.3.0: dependencies: - '@jridgewell/trace-mapping': 0.3.25 + '@jridgewell/trace-mapping': 0.3.29 '@types/istanbul-lib-coverage': 2.0.6 convert-source-map: 2.0.0 @@ -15141,7 +15742,7 @@ snapshots: vary@1.1.2: {} - viem@0.3.50(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.24.4): + viem@0.3.50(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.74): dependencies: '@adraffy/ens-normalize': 1.9.0 '@noble/curves': 1.0.0 @@ -15149,7 +15750,7 @@ snapshots: '@scure/bip32': 1.3.0 '@scure/bip39': 1.2.0 '@wagmi/chains': 1.0.0(typescript@5.8.3) - abitype: 0.8.7(typescript@5.8.3)(zod@3.24.4) + abitype: 0.8.7(typescript@5.8.3)(zod@3.25.74) isomorphic-ws: 5.0.0(ws@8.12.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) ws: 8.12.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) transitivePeerDependencies: @@ -15178,6 +15779,8 @@ snapshots: dependencies: defaults: 1.0.4 + web-streams-polyfill@3.3.3: {} + web3-utils@1.7.3: dependencies: bn.js: 5.2.1 @@ -15188,6 +15791,14 @@ snapshots: randombytes: 2.1.0 utf8: 3.0.0 + webcrypto-core@1.8.1: + dependencies: + '@peculiar/asn1-schema': 2.3.15 + '@peculiar/json-schema': 1.1.12 + asn1js: 3.0.6 + pvtsutils: 1.3.6 + tslib: 2.8.1 + webidl-conversions@3.0.1: {} whatwg-url@5.0.0: @@ -15342,7 +15953,7 @@ snapshots: bufferutil: 4.0.9 utf-8-validate: 5.0.10 - ws@8.18.2(bufferutil@4.0.9)(utf-8-validate@5.0.10): + ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10): optionalDependencies: bufferutil: 4.0.9 utf-8-validate: 5.0.10 @@ -15373,7 +15984,7 @@ snapshots: yallist@5.0.0: {} - yaml@2.7.1: {} + yaml@2.8.0: {} yargs-parser@11.1.1: dependencies: @@ -15432,8 +16043,8 @@ snapshots: yocto-queue@0.1.0: {} - zod-to-json-schema@3.24.5(zod@3.24.4): + zod-to-json-schema@3.24.6(zod@3.25.74): dependencies: - zod: 3.24.4 + zod: 3.25.74 - zod@3.24.4: {} + zod@3.25.74: {} diff --git a/src/app.ts b/src/app.ts index 61ba6eba85..e4c8e013cd 100644 --- a/src/app.ts +++ b/src/app.ts @@ -15,12 +15,15 @@ import Fastify, { FastifyInstance } from 'fastify'; import { chainRoutes } from './chains/chain.routes'; import { ethereumRoutes } from './chains/ethereum/ethereum.routes'; import { solanaRoutes } from './chains/solana/solana.routes'; +import { cardanoRoutes } from './chains/cardano/cardano.routes'; import { configRoutes } from './config/config.routes'; import { connectorsRoutes } from './connectors/connector.routes'; import { jupiterRoutes } from './connectors/jupiter/jupiter.routes'; import { meteoraRoutes } from './connectors/meteora/meteora.routes'; import { raydiumRoutes } from './connectors/raydium/raydium.routes'; import { uniswapRoutes } from './connectors/uniswap/uniswap.routes'; +import { minswapRoutes } from './connectors/minswap/minswap.routes'; +import { sundaeswapRoutes } from './connectors/sundaeswap/sundaeswap.routes'; import { getHttpsOptions } from './https'; import { ConfigManagerV2 } from './services/config-manager-v2'; import { logger } from './services/logger'; @@ -63,6 +66,7 @@ const swaggerOptions = { // Chains { name: 'solana', description: 'Solana chain endpoints' }, { name: 'ethereum', description: 'Ethereum chain endpoints' }, + { name: 'cardano', description: 'Cardano chain endpoints' }, // Connectors { name: 'jupiter', description: 'Jupiter DEX aggregator (Solana)' }, @@ -90,6 +94,14 @@ const swaggerOptions = { name: 'uniswap/clmm', description: 'Uniswap V3 pool connector (Ethereum)', }, + { + name: 'minswap/amm', + description: 'Minswap pool connector (Cardano)', + }, + { + name: 'sundaeswap/amm', + description: 'Sundaeswap pool connector (Cardano)', + }, ], components: { parameters: { @@ -209,9 +221,18 @@ const configureGatewayServer = () => { app.register(uniswapRoutes, { prefix: '/connectors/uniswap' }); + // Minswap routes + app.register(minswapRoutes.amm, { prefix: '/connectors/minswap/amm' }); + + // Sundaeswap routes + app.register(sundaeswapRoutes.amm, { + prefix: '/connectors/sundaeswap/amm', + }); + // Register chain routes app.register(solanaRoutes, { prefix: '/chains/solana' }); app.register(ethereumRoutes, { prefix: '/chains/ethereum' }); + app.register(cardanoRoutes, { prefix: '/chains/cardano' }); }; // Register routes on main server diff --git a/src/chains/cardano/cardano.config.ts b/src/chains/cardano/cardano.config.ts new file mode 100644 index 0000000000..c1499a90a2 --- /dev/null +++ b/src/chains/cardano/cardano.config.ts @@ -0,0 +1,40 @@ +import { ConfigManagerV2 } from '../../services/config-manager-v2'; +interface NetworkConfig { + name: string; + tokenListType: string; + tokenListSource: string; + nativeCurrencySymbol: string; + apiurl: string; + projectId: string; +} + +export interface Config { + network: NetworkConfig; +} + +export function getCardanoConfig( + chainName: string, + networkName: string, +): Config { + return { + network: { + name: networkName, + tokenListType: ConfigManagerV2.getInstance().get( + chainName + '.networks.' + networkName + '.tokenListType', + ), + tokenListSource: ConfigManagerV2.getInstance().get( + chainName + '.networks.' + networkName + '.tokenListSource', + ), + nativeCurrencySymbol: ConfigManagerV2.getInstance().get( + chainName + '.networks.' + networkName + '.nativeCurrencySymbol', + ), + apiurl: ConfigManagerV2.getInstance().get( + chainName + '.networks.' + networkName + '.apiurl', + ), + projectId: ConfigManagerV2.getInstance().get( + chainName + '.networks.' + networkName + '.projectId', + ), + }, + // Additional Cardano-specific configurations can be added here + }; +} diff --git a/src/chains/cardano/cardano.routes.ts b/src/chains/cardano/cardano.routes.ts new file mode 100644 index 0000000000..4e683d6d2a --- /dev/null +++ b/src/chains/cardano/cardano.routes.ts @@ -0,0 +1,24 @@ +import { FastifyPluginAsync } from 'fastify'; + +import { statusRoute } from './routes/status'; +import { tokensRoute } from './routes/tokens'; +import { balancesRoute } from './routes/balances'; +import { pollRoute } from './routes/poll'; + +// Register the type declaration needed for Fastify schema tags +declare module 'fastify' { + interface FastifySchema { + tags?: readonly string[]; + description?: string; + } +} + +export const cardanoRoutes: FastifyPluginAsync = async (fastify) => { + // Register all the route handlers + fastify.register(statusRoute); + fastify.register(tokensRoute); + fastify.register(balancesRoute); + fastify.register(pollRoute); +}; + +export default cardanoRoutes; diff --git a/src/chains/cardano/cardano.ts b/src/chains/cardano/cardano.ts new file mode 100644 index 0000000000..4ccab27e06 --- /dev/null +++ b/src/chains/cardano/cardano.ts @@ -0,0 +1,513 @@ +import { Config, getCardanoConfig } from './cardano.config'; +import { Lucid, Blockfrost, C, UTxO } from '@aiquant/lucid-cardano'; +import { TokenListType, TokenValue } from '../../services/base'; +import { ConfigManagerCertPassphrase } from '../../services/config-manager-cert-passphrase'; +import { walletPath } from '../../wallet/utils'; +import { promises as fs } from 'fs'; +import fse from 'fs-extra'; +import crypto from 'crypto'; +import { + NETWORK_ERROR_CODE, + NETWORK_ERROR_MESSAGE, + HttpException, + TOKEN_NOT_SUPPORTED_ERROR_CODE, + TOKEN_NOT_SUPPORTED_ERROR_MESSAGE, + TransactionStatus, +} from './cardano.utils'; +import { logger } from '../../services/logger'; +import { TokenListResolutionStrategy } from '../../services/token-list-resolution'; + +//import { Cardanoish } from "../../services/common-interfaces"; +export type CardanoTokenInfo = { + policyId: string; + assetName: string; + decimals: number; + name: string; + symbol: string; + logoURI: string; + address: string; +}; + +export class Cardano { + private static _instances: { [name: string]: Cardano }; + public tokenList: CardanoTokenInfo[] = []; + public config: Config; + public tokenMap: Record = {}; + private _tokenListSource: string; + private _tokenListType: TokenListType; + public lucidInstance: Lucid | null = null; + public network: string; + private _chain: string; + private _ready: boolean = false; + public apiURL: any; + public nativeTokenSymbol: string; + public projectId: string; + + private constructor(network: string) { + // Throw error if network is not 'mainnet' or 'preprod' + if ( + network !== 'mainnet' && + network !== 'preprod' && + network !== 'preview' + ) { + throw new HttpException(503, NETWORK_ERROR_MESSAGE, NETWORK_ERROR_CODE); + } + this.config = getCardanoConfig('cardano', network); + this._chain = 'cardano'; + // Determine the appropriate Blockfrost Project ID and API URL + this.apiURL = this.config.network.apiurl; + this.network = this.config.network.name; + this.nativeTokenSymbol = this.config.network.nativeCurrencySymbol; + this._tokenListSource = this.config.network.tokenListSource; + this._tokenListType = this.config.network.tokenListType; + this.projectId = this.config.network.projectId; + } + public static async getInstance(network: string): Promise { + if (Cardano._instances === undefined) { + Cardano._instances = {}; + } + + if (!Cardano._instances[network]) { + const instance = new Cardano(network); + + if ( + instance.projectId && + instance.projectId.toLowerCase().startsWith(network.toLowerCase()) + ) { + try { + await instance.init(); + } catch (err: any) { + logger.warn( + `[Cardano] initial init() skipped for network="${network}": ${err.message}`, + ); + } + } else { + logger.info( + `[Cardano] skipped init() for network="${network}" because projectId is still placeholder`, + ); + } + + Cardano._instances[network] = instance; + } + + return Cardano._instances[network]; + } + + public static getConnectedInstances(): { [name: string]: Cardano } { + return Cardano._instances; + } + + public get chain(): string { + return this._chain; + } + + public ready(): boolean { + return this._ready; + } + + public async init(): Promise { + if (!this.lucidInstance) { + this.lucidInstance = await Lucid.new( + new Blockfrost(this.apiURL, this.projectId), + this.network === 'preprod' + ? 'Preprod' + : this.network === 'preview' + ? 'Preview' + : 'Mainnet', + ); + } + + if (!this._ready) { + // Ensure we only set ready once + this._ready = true; + await this.loadTokens(this._tokenListSource, this._tokenListType); + } + } + + private getLucid(): Lucid { + if (!this.lucidInstance) { + // Use instance-specific Lucid + throw new Error('Lucid is not initialized. Call `init` first.'); + } + return this.lucidInstance; + } + + public async getWalletFromPrivateKey(privateKey: string): Promise<{ + address: string; + }> { + if (!this._ready) { + throw new Error( + 'Cardano instance is not initialized. Call `init` first.', + ); + } + + try { + const lucid = this.getLucid(); + lucid.selectWalletFromPrivateKey(privateKey); + + // Get wallet address + const address = await lucid.wallet.address(); + return { address }; + } catch (error: any) { + throw new Error( + `Error retrieving wallet from private key: ${error.message}`, + ); + } + } + + public async getWalletFromAddress(address: string): Promise { + const path = `${walletPath}/${this._chain}`; + const encryptedPrivateKey: string = await fse.readFile( + `${path}/${address}.json`, + 'utf8', + ); + const passphrase = ConfigManagerCertPassphrase.readPassphrase(); + if (!passphrase) { + throw new Error('missing passphrase'); + } + + // Ensure decrypt is awaited if it's asynchronous + const privateKey = await this.decrypt(encryptedPrivateKey, passphrase); + + return privateKey; // Correctly resolved the Promise to string + } + // get native balance ADA + public async getNativeBalance(privateKey: string): Promise { + const Lucid = this.getLucid(); + Lucid.selectWalletFromPrivateKey(privateKey); + + // Get wallet address + const address = await Lucid.wallet.address(); + // Fetch UTXOs at the wallet's address + const utxos = await Lucid.utxosAt(address); + + // Calculate total balance in ADA using BigInt + const totalLovelace = utxos.reduce( + (acc, utxo) => acc + (utxo.assets.lovelace || 0n), + 0n, + ); + + // Convert Lovelace (BigInt) to ADA (Number) + const balanceInADA = Number(totalLovelace) / 1_000_000; + + return balanceInADA.toString(); + } + // get Asset balance like MIN and LP + async getAssetBalance( + privateKey: string, + token: CardanoTokenInfo, + ): Promise { + let tokenAdress: string; + + // If token information is not found, throw an error + if (!token || Object.keys(token).length === 0) { + throw new Error(`Token ${token} is not supported.`); + } + + tokenAdress = token.policyId + token.assetName; + + const Lucid = this.getLucid(); + Lucid.selectWalletFromPrivateKey(privateKey); + + // Get wallet address + const address = await Lucid.wallet.address(); + + // Fetch UTXOs at the wallet's address + const utxos = await Lucid.utxosAt(address); + + // Calculate token balance + const calculatedTokenBalance = utxos.reduce((acc, utxo) => { + if (utxo.assets[tokenAdress]) { + return acc + Number(utxo.assets[tokenAdress]); + } + return acc; + }, 0); + // Divide raw balance by 10^decimals to get the actual amount + const decimals = token.decimals; + const actualTokenBalance = calculatedTokenBalance / Math.pow(10, decimals); + logger.debug( + `Token balance for ${address}: ${actualTokenBalance.toString()}`, + ); + return actualTokenBalance.toString(); + } + + async encrypt(secret: string, password: string): Promise { + const algorithm = 'aes-256-ctr'; + const iv = crypto.randomBytes(16); + const salt = crypto.randomBytes(32); + const key = crypto.pbkdf2Sync( + password, + new Uint8Array(salt), + 5000, + 32, + 'sha512', + ); + const cipher = crypto.createCipheriv( + algorithm, + new Uint8Array(key), + new Uint8Array(iv), + ); + + const encryptedBuffers = [ + new Uint8Array(cipher.update(new Uint8Array(Buffer.from(secret)))), + new Uint8Array(cipher.final()), + ]; + const encrypted = Buffer.concat(encryptedBuffers); + + const ivJSON = iv.toJSON(); + const saltJSON = salt.toJSON(); + const encryptedJSON = encrypted.toJSON(); + + return JSON.stringify({ + algorithm, + iv: ivJSON, + salt: saltJSON, + encrypted: encryptedJSON, + }); + } + + async decrypt(encryptedSecret: string, password: string): Promise { + const hash = JSON.parse(encryptedSecret); + const salt = new Uint8Array(Buffer.from(hash.salt, 'utf8')); + const iv = new Uint8Array(Buffer.from(hash.iv, 'utf8')); + + const key = crypto.pbkdf2Sync(password, salt, 5000, 32, 'sha512'); + + const decipher = crypto.createDecipheriv( + hash.algorithm, + new Uint8Array(key), + iv, + ); + + const decryptedBuffers = [ + new Uint8Array( + decipher.update(new Uint8Array(Buffer.from(hash.encrypted, 'hex'))), + ), + new Uint8Array(decipher.final()), + ]; + const decrypted = Buffer.concat(decryptedBuffers); + + return decrypted.toString(); + } + + async getCurrentBlockNumber(): Promise { + const response = await fetch(`${this.apiURL}/blocks/latest`, { + headers: { + project_id: this.projectId, + }, + }); + + if (!response.ok) { + throw new Error(`Error fetching latest block: ${response.statusText}`); + } + + const latestBlock = await response.json(); + return latestBlock.height; + } + + public async getTransaction(txHash: string): Promise { + try { + // Fetch transaction details from Blockfrost + const response = await fetch(`${this.apiURL}/txs/${txHash}`, { + method: 'GET', + headers: { + project_id: this.projectId, // Pass project ID in the header + }, + }); + + // Check if the response is successful + if (!response.ok) { + throw new Error(`Failed to fetch transaction: ${response.statusText}`); + } + + // Parse the response JSON + const tx = await response.json(); + + // Simplify the response for the bot + return { + txHash: tx.hash, + block: tx.block, + blockHeight: tx.block_height, + blockTime: tx.block_time, + fees: Number(tx.fees), + validContract: tx.valid_contract, + status: tx.block ? 1 : 0, // Simplified status + }; + } catch (error) { + console.error(`Error fetching transaction: ${error}`); + throw error; + } + } + + /** + * Load tokens from the token list source + */ + public async loadTokens( + tokenListSource: string, + tokenListType: TokenListType, + ): Promise { + logger.info( + `Loading tokens for cardano from ${tokenListType} source: ${tokenListSource}`, + ); + try { + this.tokenList = await this.getTokenList(tokenListSource, tokenListType); + + if (this.tokenList) { + logger.info(`Loaded ${this.tokenList.length} tokens for cardano`); + // Build token map for faster lookups + this.tokenList.forEach( + (token: CardanoTokenInfo) => (this.tokenMap[token.symbol] = token), + ); + } + } catch (error) { + logger.error(`Failed to load token list: ${error.message}`); + throw error; + } + } + + /** + * Get token list from source + */ + private async getTokenList( + tokenListSource: string, + tokenListType: TokenListType, + ): Promise { + const tokensList = await new TokenListResolutionStrategy( + tokenListSource, + tokenListType, + ).resolve(); + + // Normalize addresses + return tokensList.tokens; + } + + public get storedTokenList(): CardanoTokenInfo[] { + return this.tokenList; + } + + /** + * Get token info by symbol or address + */ + public getTokenBySymbol(tokenSymbol: string): CardanoTokenInfo | undefined { + // First try to find token by symbol + const tokenBySymbol = this.tokenList.find( + (token: CardanoTokenInfo) => + token.symbol.toUpperCase() === tokenSymbol.toUpperCase(), + ); + + if (tokenBySymbol) { + return tokenBySymbol; + } + } + + public getTokenAddress(symbol: string): string { + let tokenAddress: string = ''; + let tokenInfo = this.getTokenBySymbol(symbol); + // If token information is not found, throw an error + if (!tokenInfo || Object.keys(tokenInfo).length === 0) { + // Handle token not supported errors + throw new HttpException( + 500, + TOKEN_NOT_SUPPORTED_ERROR_MESSAGE, + TOKEN_NOT_SUPPORTED_ERROR_CODE, + ); + } + + tokenAddress = tokenInfo[0]?.policyId + tokenInfo[0]?.assetName; + + return tokenAddress; + } + + /** + * Get the first available Cardano wallet address + */ + public async getFirstWalletAddress(): Promise { + // Specifically look in the cardano subdirectory, not in any other chain's directory + const path = `${walletPath}/cardano`; + try { + // Create directory if it doesn't exist + await fse.ensureDir(path); + + // Get all .json files in the directory + const files = await fse.readdir(path); + const walletFiles = files.filter((f) => f.endsWith('.json')); + + if (walletFiles.length === 0) { + return null; + } + + // Return first wallet address (without .json extension) + const walletAddress = walletFiles[0].slice(0, -5); + + // Validate it looks like an Cardano address + if (!walletAddress.startsWith('addr')) { + logger.warn( + `Invalid Cardano address found in wallet directory: ${walletAddress}`, + ); + return null; + } + + return walletAddress; + } catch (error) { + logger.error(`Error getting Cardano wallet address: ${error.message}`); + return null; + } + } + + /** + * Given a payment address, load its private key & select that + * wallet in Lucid, then return all UTxOs at that address. + */ + public async getUtxos(address: string): Promise { + try { + // 1) derive the private key from your store (e.g. DB or seed) + const privateKey = await this.getWalletFromAddress(address); + if (!privateKey) { + throw new Error(`No private key found for address ${address}`); + } + + // 2) tell Lucid to use that key for signing / UTxO queries + this.lucidInstance.selectWalletFromPrivateKey(privateKey); + + // 3) fetch & return UTxOs + const utxos: UTxO[] = await this.lucidInstance.utxosAt(address); + return utxos; + } catch (error: any) { + // 4) log the failure for debugging + logger.error( + `Cardano.getUtxos failed for address ${address}: ${error.message || error}`, + ); + // 5) rethrow a trimmed error + throw new Error( + `Unable to fetch UTxOs for ${address}: ${error.message || error}`, + ); + } + } + + /** + * Validate Cardano address format + * @param address The address to validate + * @returns The address if valid + * @throws Error if the address is invalid + */ + public static validateAddress(address: string): string { + try { + const cardanoAddressRegex = /^(addr|addr_test)[0-9a-zA-Z]{1,}$/; + + // Additional check for proper length + if (!cardanoAddressRegex.test(address)) { + throw new Error('Invalid address length'); + } + + return address; + } catch (error) { + throw new Error(`Invalid Cardano address format: ${address}`); + } + } + + async close() { + if (this._chain in Cardano._instances) { + delete Cardano._instances[this._chain]; + } + } +} diff --git a/src/chains/cardano/cardano.utils.ts b/src/chains/cardano/cardano.utils.ts new file mode 100644 index 0000000000..dbdbd5fca3 --- /dev/null +++ b/src/chains/cardano/cardano.utils.ts @@ -0,0 +1,68 @@ +export const NETWORK_ERROR_CODE = 1001; +export const RATE_LIMIT_ERROR_CODE = 1002; +export const OUT_OF_GAS_ERROR_CODE = 1003; +export const TRANSACTION_GAS_PRICE_TOO_LOW = 1004; +export const LOAD_WALLET_ERROR_CODE = 1005; +export const TOKEN_NOT_SUPPORTED_ERROR_CODE = 1006; +export const TRADE_FAILED_ERROR_CODE = 1007; +export const SWAP_PRICE_EXCEEDS_LIMIT_PRICE_ERROR_CODE = 1008; +export const SWAP_PRICE_LOWER_THAN_LIMIT_PRICE_ERROR_CODE = 1009; +export const SERVICE_UNITIALIZED_ERROR_CODE = 1010; +export const UNKNOWN_CHAIN_ERROR_CODE = 1011; +export const INVALID_NONCE_ERROR_CODE = 1012; +export const PRICE_FAILED_ERROR_CODE = 1013; +export const INCOMPLETE_REQUEST_PARAM_CODE = 1014; +export const ERROR_RETRIEVING_WALLET_ADDRESS_ERROR_CODE = 1015; +export const ACCOUNT_NOT_SPECIFIED_CODE = 1016; +export const TRADE_NOT_FOUND_ERROR_CODE = 1017; +export const UNKNOWN_ERROR_ERROR_CODE = 1099; +export const AMOUNT_NOT_SUPPORTED_ERROR_CODE = 1016; +export const ENDPOINT_NOT_SUPPORTED_ERROR_CODE = 1018; +export const INSUFFICIENT_FUNDS_ERROR_CODE = 1019; +export const GAS_LIMIT_EXCEEDED_ERROR_CODE = 1020; +export const AMOUNT_LESS_THAN_MIN_AMOUNT_ERROR_CODE = 1021; + +export const NETWORK_ERROR_MESSAGE = + 'Network error. Please check your node URL, API key, and Internet connection.'; +export const RATE_LIMIT_ERROR_MESSAGE = + 'Blockchain node API rate limit exceeded.'; +export const LOAD_WALLET_ERROR_MESSAGE = 'Failed to load wallet: '; +export const TOKEN_NOT_SUPPORTED_ERROR_MESSAGE = 'Token not supported: '; +export const TRADE_FAILED_ERROR_MESSAGE = 'Trade query failed: '; +export const INCOMPLETE_REQUEST_PARAM = 'Incomplete request parameters.'; +export const INVALID_NONCE_ERROR_MESSAGE = 'Invalid Nonce provided: '; +export const AMOUNT_NOT_SUPPORTED_ERROR_MESSAGE = + 'Amount provided in an unexpected format'; +export const ENDPOINT_NOT_SUPPORTED_ERROR_MESSAGE = + 'Endpoint not supported by this chain/controller.'; +export const INSUFFICIENT_FUNDS_ERROR_MESSAGE = + 'Insufficient funds for transaction.'; +export const GAS_LIMIT_EXCEEDED_ERROR_MESSAGE = + 'Gas limit exceeded (gasWanted greater than gasLimitEstimate).'; +export const AMOUNT_LESS_THAN_MIN_AMOUNT_ERROR_MESSAGE = + 'Calculated amount less than min amount provided with slippage. Maybe try increasing slippage. '; + +// custom error for http exceptions +export class HttpException extends Error { + status: number; + message: string; + errorCode: number; + constructor(status: number, message: string, errorCode: number = -1) { + super(message); + this.status = status; + this.message = message; + this.errorCode = errorCode; + } +} + +export interface TransactionStatus { + txHash: string; + block: number | null; + blockHeight: number | null; + blockTime: number | null; + fees: number; + validContract: boolean; + status: 0 | 1; // 0 = pending, 1 = confirmed +} + +export interface CardanoTokensResponseType {} diff --git a/src/chains/cardano/routes/balances.ts b/src/chains/cardano/routes/balances.ts new file mode 100644 index 0000000000..c9ca653851 --- /dev/null +++ b/src/chains/cardano/routes/balances.ts @@ -0,0 +1,214 @@ +import { FastifyPluginAsync, FastifyInstance } from 'fastify'; + +import { + BalanceRequestType, + BalanceResponseType, + BalanceRequestSchema, + BalanceResponseSchema, +} from '../../../schemas/chain-schema'; +import { tokenValueToString } from '../../../services/base'; +import { logger } from '../../../services/logger'; +import { Cardano } from '../cardano'; + +export async function getCardanoBalances( + fastify: FastifyInstance, + network: string, + address: string, + tokens?: string[], +): Promise { + try { + const cardano = await Cardano.getInstance(network); + await cardano.init(); + + let wallet: string; + const balances: Record = {}; + + // Treat empty array as if no tokens were specified + const effectiveTokens = tokens && tokens.length === 0 ? undefined : tokens; + + // If no tokens specified, check all tokens in the token list + const checkAllTokens = !effectiveTokens; + + try { + wallet = await cardano.getWalletFromAddress(address); + } catch (err) { + logger.error(`Failed to load wallet: ${err.message}`); + throw fastify.httpErrors.internalServerError( + `Failed to load wallet: ${err.message}`, + ); + } + + // Always get native token balance + const nativeBalance = await cardano.getNativeBalance(wallet); + // Convert string to number as required by schema + balances[cardano.nativeTokenSymbol] = parseFloat( + tokenValueToString(nativeBalance), + ); + + if (checkAllTokens) { + // No tokens specified, check all tokens in the token list + logger.info( + `Checking balances for all ${cardano.storedTokenList.length} tokens in the token list`, + ); + + // Process tokens in batches to avoid overwhelming the provider + // This allows for provider-specific rate limiting while still being efficient + const batchSize = 25; // Reasonable default batch size + const tokenList = cardano.storedTokenList; + const totalTokens = tokenList.length; + + // Set a maximum time limit for the entire operation + const maxScanTimeMs = 30000; // 30 seconds maximum for scanning + const startTime = Date.now(); + let timeExceeded = false; + + logger.info( + `Processing ${totalTokens} tokens in batches of ${batchSize} with ${maxScanTimeMs}ms time limit`, + ); + + for (let i = 0; i < totalTokens && !timeExceeded; i += batchSize) { + // Check if we've exceeded the time limit + if (Date.now() - startTime > maxScanTimeMs) { + logger.warn( + `Time limit of ${maxScanTimeMs}ms exceeded after checking ${i} tokens. Stopping scan.`, + ); + timeExceeded = true; + break; + } + + const batch = tokenList.slice(i, i + batchSize); + logger.debug( + `Processing batch ${Math.floor(i / batchSize) + 1}/${Math.ceil(totalTokens / batchSize)}`, + ); + + // Process batch in parallel with timeout + await Promise.all( + batch.map(async (token) => { + try { + const balance = await cardano.getAssetBalance(wallet, token); + // Parse balance to number + const balanceNum = parseFloat(tokenValueToString(balance)); + + // Only add tokens with non-zero balances + if (balanceNum > 0) { + balances[token.symbol] = balanceNum; + logger.debug( + `Found non-zero balance for ${token.symbol}: ${balanceNum}`, + ); + } + } catch (err) { + // Log error but continue with other tokens + logger.warn( + `Error getting balance for ${token.symbol}: ${err.message}`, + ); + } + }), + ); + } + } else if (effectiveTokens) { + // Get ERC20 token balances for specific tokens + await Promise.all( + effectiveTokens.map(async (symbolOrAddress) => { + // Don't process the native token again + if (symbolOrAddress === cardano.nativeTokenSymbol) { + return; + } + + const token = cardano.getTokenBySymbol(symbolOrAddress); + if (token) { + const balance = await cardano.getAssetBalance(wallet, token); + // Convert string to number as required by schema + balances[token.symbol] = parseFloat(tokenValueToString(balance)); + } + }), + ); + } + + if (!Object.keys(balances).length) { + throw fastify.httpErrors.badRequest( + 'No token balances found for the given wallet', + ); + } + + return { balances }; + } catch (error) { + if (error.statusCode) { + throw error; // Re-throw if it's already a Fastify error + } + logger.error(`Error getting balances: ${error.message}`); + throw fastify.httpErrors.internalServerError( + `Failed to get balances: ${error.message}`, + ); + } +} + +export const balancesRoute: FastifyPluginAsync = async (fastify) => { + // Get first wallet address for example + const cardano = await Cardano.getInstance('preprod'); + + // Default Cardano address for examples if no wallet is available + let firstWalletAddress = ''; + + try { + // Try to get user's first Cardano wallet if available + // getFirstWalletAddress specifically looks in the /cardano directory + const userWallet = await cardano.getFirstWalletAddress(); + if (userWallet) { + // Make sure it's a valid Cardano address + const isValidCardanoAddress = /^(addr|addr_test)[0-9a-zA-Z]{1,}$/i.test( + userWallet, + ); + if (isValidCardanoAddress) { + firstWalletAddress = userWallet; + logger.info( + `Using user's Cardano wallet for examples: ${firstWalletAddress}`, + ); + } + } + } catch (error) { + logger.warn('No Cardano wallets found for examples in schema'); + } + + BalanceRequestSchema.properties.address.examples = [firstWalletAddress]; + + fastify.post<{ + Body: BalanceRequestType; + Reply: BalanceResponseType; + }>( + '/balances', + { + schema: { + description: + 'Get Cardano balances. If no tokens specified or empty array provided, returns native token (ADA) and only non-zero balances for tokens from the token list. If specific tokens are requested, returns those exact tokens with their balances, including zeros.', + tags: ['cardano'], + body: { + ...BalanceRequestSchema, + properties: { + ...BalanceRequestSchema.properties, + network: { + type: 'string', + examples: ['mainnet', 'preprod', 'preview'], + }, + address: { type: 'string', examples: [firstWalletAddress] }, + tokens: { + type: 'array', + items: { type: 'string' }, + description: + 'A list of token symbols or addresses. An empty array is treated the same as if the parameter was not provided, returning only non-zero balances plus the native token.', + examples: [['ADA', 'MIN', 'LP']], + }, + }, + }, + response: { + 200: BalanceResponseSchema, + }, + }, + }, + async (request) => { + const { network, address, tokens } = request.body; + return await getCardanoBalances(fastify, network, address, tokens); + }, + ); +}; + +export default balancesRoute; diff --git a/src/chains/cardano/routes/poll.ts b/src/chains/cardano/routes/poll.ts new file mode 100644 index 0000000000..2ecb0d5907 --- /dev/null +++ b/src/chains/cardano/routes/poll.ts @@ -0,0 +1,108 @@ +import { FastifyPluginAsync, FastifyInstance } from 'fastify'; + +import { + PollRequestType, + PollResponseType, + PollRequestSchema, + PollResponseSchema, +} from '../../../schemas/chain-schema'; +import { logger } from '../../../services/logger'; +import { Cardano } from '../cardano'; + +export async function pollCardanoTransaction( + _fastify: FastifyInstance, + network: string, + signature: string, +): Promise { + const cardano = await Cardano.getInstance(network); + + try { + const currentBlock = await cardano.getCurrentBlockNumber(); + + // Validate transaction signature format + if (!signature || typeof signature !== 'string') { + return { + currentBlock, + signature, + txBlock: null, + txStatus: 0, + txData: null, + fee: null, + error: 'Invalid transaction signature format', + }; + } + + const txData = await cardano.getTransaction(signature); + + if (!txData) { + return { + currentBlock, + signature, + txBlock: null, + txStatus: 0, + txData: null, + fee: null, + }; + } + + return { + currentBlock, + signature, + txBlock: txData.blockHeight, + txStatus: txData.status, + fee: txData.fees, + txData, + }; + } catch (error) { + logger.error(`Error polling transaction ${signature}: ${error.message}`); + return { + currentBlock: await cardano.getCurrentBlockNumber(), + signature, + txBlock: null, + txStatus: 0, + txData: null, + fee: null, + error: 'Transaction not found or invalid', + }; + } +} + +export const pollRoute: FastifyPluginAsync = async (fastify) => { + fastify.post<{ + Body: PollRequestType; + Reply: PollResponseType; + }>( + '/poll', + { + schema: { + description: 'Poll for the status of a Cardano transaction', + tags: ['cardano'], + body: { + ...PollRequestSchema, + properties: { + ...PollRequestSchema.properties, + network: { + type: 'string', + examples: ['mainnet', 'preprod', 'preview'], + }, + signature: { + type: 'string', + examples: [ + '66f5f15d15124a77418cfa3ec0e72cc1d2295647e528a9ecb4636f9ed5342d06', + ], + }, + }, + }, + response: { + 200: PollResponseSchema, + }, + }, + }, + async (request) => { + const { network, signature } = request.body; + return await pollCardanoTransaction(fastify, network, signature); + }, + ); +}; + +export default pollRoute; diff --git a/src/chains/cardano/routes/status.ts b/src/chains/cardano/routes/status.ts new file mode 100644 index 0000000000..d31f8a39d1 --- /dev/null +++ b/src/chains/cardano/routes/status.ts @@ -0,0 +1,97 @@ +import { FastifyPluginAsync } from 'fastify'; + +import { + StatusRequestType, + StatusResponseType, + StatusRequestSchema, + StatusResponseSchema, +} from '../../../schemas/chain-schema'; +import { logger } from '../../../services/logger'; +import { Cardano } from '../cardano'; + +export async function getCardanoStatus( + network: string, +): Promise { + try { + const cardano = await Cardano.getInstance(network); + const chain = 'cardano'; + const rpcUrl = cardano.apiURL; + const nativeCurrency = cardano.nativeTokenSymbol; + + // Directly try to get the current block number with a timeout + let currentBlockNumber = 0; + try { + // Set up a timeout promise to prevent hanging on unresponsive nodes + const blockPromise = await cardano.getCurrentBlockNumber(); + const timeoutPromise = new Promise((_, reject) => { + setTimeout(() => reject(new Error('Request timed out')), 5000); + }); + + // Race the block request against the timeout + currentBlockNumber = await Promise.race([blockPromise, timeoutPromise]); + } catch (blockError) { + logger.warn(`Failed to get block number: ${blockError.message}`); + // Continue with default block number + } + + return { + chain, + network, + rpcUrl, + currentBlockNumber, + nativeCurrency, + }; + } catch (error) { + logger.error(`Error getting Cardano status: ${error.message}`); + throw new Error(`Failed to get Cardano status: ${error.message}`); + } +} + +export const statusRoute: FastifyPluginAsync = async (fastify) => { + fastify.get<{ + Querystring: StatusRequestType; + Reply: StatusResponseType; + }>( + '/status', + { + schema: { + description: 'Get Cardano chain status', + tags: ['cardano'], + querystring: { + ...StatusRequestSchema, + properties: { + ...StatusRequestSchema.properties, + network: { + type: 'string', + examples: ['mainnet', 'preprod', 'preview'], + }, + }, + }, + response: { + 200: StatusResponseSchema, + }, + }, + }, + async (request, reply) => { + const { network } = request.query; + try { + // This will handle node timeout internally + return await getCardanoStatus(network); + } catch (error) { + // This will catch any other unexpected errors + logger.error(`Error in Cardano status endpoint: ${error.message}`); + reply.status(500); + // Return a minimal valid response + return { + chain: 'cardano', + network, + rpcUrl: 'unavailable', + currentBlockNumber: 0, + nativeCurrency: 'ADA', + }; + } + }, + ); +}; + +export default statusRoute; diff --git a/src/chains/cardano/routes/tokens.ts b/src/chains/cardano/routes/tokens.ts new file mode 100644 index 0000000000..eae5372bee --- /dev/null +++ b/src/chains/cardano/routes/tokens.ts @@ -0,0 +1,76 @@ +import { FastifyPluginAsync, FastifyInstance } from 'fastify'; + +import { + TokensRequestType, + TokensResponseType, + TokensRequestSchema, + TokensResponseSchema, +} from '../../../schemas/chain-schema'; +import { logger } from '../../../services/logger'; +import { Cardano } from '../cardano'; + +export async function getCardanoTokens( + fastify: FastifyInstance, + network: string, + tokenSymbols?: string[] | string, +): Promise { + try { + const cardano = await Cardano.getInstance(network); + let tokens = []; + + if (!tokenSymbols) { + tokens = cardano.tokenList; + } else { + const symbolsArray = Array.isArray(tokenSymbols) + ? tokenSymbols + : typeof tokenSymbols === 'string' + ? tokenSymbols.replace(/[\[\]]/g, '').split(',') + : []; + + for (const symbol of symbolsArray) { + const token = cardano.getTokenBySymbol(symbol.trim()); + if (token) tokens.push(token); + } + } + + return { tokens }; + } catch (error) { + logger.error(`Error getting tokens: ${error.message}`); + throw fastify.httpErrors.internalServerError( + `Failed to get tokens: ${error.message}`, + ); + } +} + +export const tokensRoute: FastifyPluginAsync = async (fastify) => { + fastify.get<{ + Querystring: TokensRequestType; + Reply: TokensResponseType; + }>( + '/tokens', + { + schema: { + description: + 'Get list of supported Cardano tokens with their addresses and decimals', + tags: ['cardano'], + querystring: { + ...TokensRequestSchema, + properties: { + ...TokensRequestSchema.properties, + network: { type: 'string', default: 'preprod' }, + tokenSymbols: { type: 'array', items: { type: 'string' } }, + }, + }, + response: { + 200: TokensResponseSchema, + }, + }, + }, + async (request) => { + const { network, tokenSymbols } = request.query; + return await getCardanoTokens(fastify, network, tokenSymbols); + }, + ); +}; + +export default tokensRoute; diff --git a/src/chains/chain.routes.ts b/src/chains/chain.routes.ts index 087ce63ec3..f85bbe3fad 100644 --- a/src/chains/chain.routes.ts +++ b/src/chains/chain.routes.ts @@ -44,6 +44,12 @@ export const chainRoutes: FastifyPluginAsync = async (fastify) => { ConfigManagerV2.getInstance().get('solana.networks') || {}, ); + // Get Cardano networks + + const cardanoNetworks = Object.keys( + ConfigManagerV2.getInstance().get('cardano.networks') || {}, + ); + const chains = [ { chain: 'ethereum', @@ -53,6 +59,10 @@ export const chainRoutes: FastifyPluginAsync = async (fastify) => { chain: 'solana', networks: solanaNetworks, }, + { + chain: 'cardano', + networks: cardanoNetworks, + }, ]; logger.info( diff --git a/src/config/routes/getPools.ts b/src/config/routes/getPools.ts index 713bee7849..07b1fd5b52 100644 --- a/src/config/routes/getPools.ts +++ b/src/config/routes/getPools.ts @@ -53,6 +53,16 @@ export const getPoolsRoute: FastifyPluginAsync = async (fastify) => { 'SOL-USDC': '5rCf1DM8LjKTw4YqhnoLcngyZYeNnQqztScTogYHAS6', 'USDT-USDC': 'ARwi1S4DaiTG5DX7S4M4ZsrXqpMD1MrTmbu9ue2tpmEq', }, + { + // Minswap AMM examples + 'ADA-MIN': + '6aa2153e1ae896a95539c9d62f76cedcdabdcdf144e564b8955f609d660cf6a2', + }, + { + // Sundaeswap AMM examples + 'ADA-SUNDAE': + '2baab4c73a1cd60176f903a29a9c92ed4237c88622da51e9179121a3', + }, ], }, }, diff --git a/src/config/routes/updateConfig.ts b/src/config/routes/updateConfig.ts index 5fc53a551b..cfb4942a5c 100644 --- a/src/config/routes/updateConfig.ts +++ b/src/config/routes/updateConfig.ts @@ -9,6 +9,7 @@ import { ConfigUpdateResponseSchema, } from '../schemas'; import { updateConfig, updateAllowedSlippageToFraction } from '../utils'; +import { Cardano } from '../../chains/cardano/cardano'; export const updateConfigRoute: FastifyPluginAsync = async (fastify) => { fastify.post<{ Body: ConfigUpdateRequest; Reply: ConfigUpdateResponse }>( @@ -58,6 +59,17 @@ export const updateConfigRoute: FastifyPluginAsync = async (fastify) => { } updateConfig(fastify, configPath, processedValue); + // If they updated the projectId for one of the Cardano networks: + if ( + configPath.startsWith('cardano.') && + configPath.endsWith('.projectId') + ) { + const network = configPath.split('.')[2]; // e.g. 'preprod || mainnet || preview' + console.log('network', network); + const cardano = await Cardano.getInstance(network); + cardano.projectId = String(processedValue); // assign the new key as string + await cardano.init(); // re‐init Lucid on the fly + } return { message: `Configuration updated successfully: '${configPath}' set to ${JSON.stringify(processedValue)}`, diff --git a/src/config/schemas.ts b/src/config/schemas.ts index 93504bdc90..229824794f 100644 --- a/src/config/schemas.ts +++ b/src/config/schemas.ts @@ -34,15 +34,17 @@ export const DefaultPoolRequestSchema = Type.Object({ 'uniswap/amm', 'uniswap/clmm', 'meteora/clmm', + 'minswap/amm', + 'sundaeswap/amm', ], }), baseToken: Type.String({ description: 'Base token symbol', - examples: ['SOL', 'USDC', 'ETH', 'WETH'], + examples: ['SOL', 'USDC', 'ETH', 'WETH', 'ADA'], }), quoteToken: Type.String({ description: 'Quote token symbol', - examples: ['USDC', 'USDT', 'DAI', 'WETH'], + examples: ['USDC', 'USDT', 'DAI', 'WETH', 'MIN', 'SUNDAE'], }), poolAddress: Type.Optional( Type.String({ @@ -96,6 +98,8 @@ export const PoolsQuerySchema = Type.Object({ 'uniswap/amm', 'uniswap/clmm', 'meteora/clmm', + 'minswap/amm', + 'sundaeswap/amm', ], }), }); diff --git a/src/connectors/connector.routes.ts b/src/connectors/connector.routes.ts index b034e1994e..cb008cd5fc 100644 --- a/src/connectors/connector.routes.ts +++ b/src/connectors/connector.routes.ts @@ -6,6 +6,8 @@ import { logger } from '../services/logger'; import { JupiterConfig } from './jupiter/jupiter.config'; import { MeteoraConfig } from './meteora/meteora.config'; import { RaydiumConfig } from './raydium/raydium.config'; +import { MinswapConfig } from './minswap/minswap.config'; +import { SundaeswapConfig } from './sundaeswap/sundaeswap.config'; import { UniswapConfig, uniswapNetworks, @@ -88,6 +90,18 @@ export const connectorsRoutes: FastifyPluginAsync = async (fastify) => { chain: 'ethereum', networks: uniswapClmmNetworks, }, + { + name: 'minswap/amm', + trading_types: ['amm', 'swap'], + chain: MinswapConfig.chain, + networks: MinswapConfig.networks, + }, + { + name: 'sundaeswap/amm', + trading_types: ['amm', 'swap'], + chain: SundaeswapConfig.chain, + networks: SundaeswapConfig.networks, + }, ]; logger.info( diff --git a/src/connectors/minswap/amm-routes/addLiquidity.ts b/src/connectors/minswap/amm-routes/addLiquidity.ts new file mode 100644 index 0000000000..68676dd512 --- /dev/null +++ b/src/connectors/minswap/amm-routes/addLiquidity.ts @@ -0,0 +1,190 @@ +import { BigNumber } from 'ethers'; +import { FastifyPluginAsync } from 'fastify'; + +import { + AddLiquidityRequestType, + AddLiquidityRequest, + AddLiquidityResponseType, + AddLiquidityResponse, +} from '../../../schemas/amm-schema'; +import { logger } from '../../../services/logger'; +import { Minswap } from '../minswap'; +import { formatTokenAmount } from '../minswap.utils'; +import { getMinswapAmmLiquidityQuote } from './quoteLiquidity'; +import { Assets, TxComplete } from '@aiquant/lucid-cardano'; +import { Asset, calculateDeposit, Dex } from '@aiquant/minswap-sdk'; + +async function addLiquidity( + fastify: any, + network: string, + walletAddress: string, + poolAddress: string, + baseToken: string, + quoteToken: string, + baseTokenAmount: number, + quoteTokenAmount: number, + slippagePct?: number, // decimal, e.g. 0.01 for 1% +): Promise { + const networkToUse = network || 'mainnet'; + + // 1) Get quote for optimal amounts + const quote = await getMinswapAmmLiquidityQuote( + networkToUse, + poolAddress, + baseToken, + quoteToken, + baseTokenAmount, + quoteTokenAmount, + slippagePct, + ); + + // 2) Prepare Minswap + const minswap = await Minswap.getInstance(networkToUse); + const { cardano } = minswap; + + // 3) Ensure wallet key + const privateKey = await cardano.getWalletFromAddress(walletAddress); + if (!privateKey) { + throw fastify.httpErrors.badRequest('Wallet not found'); + } + cardano.lucidInstance.selectWalletFromPrivateKey(privateKey); + + // 4) Determine slippage + const slippage = + slippagePct !== undefined ? slippagePct : minswap.getAllowedSlippage(); // returns decimal, e.g. 0.005 + + const { poolState, poolDatum } = await minswap.getPoolData(poolAddress); + if (!poolState) { + throw fastify.httpErrors.internalServerError('Pool state not found'); + } + const { reserveA, reserveB } = poolState; + const { totalLiquidity, assetA, assetB } = poolDatum; + + // 6) Compute necessary amounts and LP tokens + const baseRaw = quote.rawBaseTokenAmount.toBigInt(); + const quoteRaw = quote.rawQuoteTokenAmount.toBigInt(); + const { necessaryAmountA, necessaryAmountB, lpAmount } = calculateDeposit({ + depositedAmountA: baseRaw, + depositedAmountB: quoteRaw, + reserveA, + reserveB, + totalLiquidity, + }); + + // 7) Apply slippage to LP minimum + const minLP = + (lpAmount * BigInt(Math.floor((1 - slippage) * 1e6))) / BigInt(1e6); + + // 8) Build tx + const dex = new Dex(cardano.lucidInstance); + const utxos = await cardano.lucidInstance.utxosAt(walletAddress); + + const txBuild: TxComplete = await dex.buildDepositTx({ + assetA, + assetB, + amountA: necessaryAmountA, + amountB: necessaryAmountB, + minimumLPReceived: minLP, + sender: walletAddress, + availableUtxos: utxos, + }); + + // 9) Sign & submit + const signed = await txBuild.sign().complete(); + const txHash = await signed.submit(); + + return { + signature: txHash, + fee: txBuild.fee, + baseTokenAmountAdded: quote.baseTokenAmount, + quoteTokenAmountAdded: quote.quoteTokenAmount, + }; +} + +export const addLiquidityRoute: FastifyPluginAsync = async (fastify) => { + await fastify.register(require('@fastify/sensible')); + fastify.post<{ + Body: AddLiquidityRequestType; + Reply: AddLiquidityResponseType; + }>( + '/add-liquidity', + { + schema: { + description: 'Add liquidity to a Minswap pool', + tags: ['minswap/amm'], + body: { + ...AddLiquidityRequest, + properties: { + ...AddLiquidityRequest.properties, + network: { type: 'string', default: 'mainnet' }, + walletAddress: { type: 'string', examples: ['addr...'] }, + poolAddress: { type: 'string', examples: [''] }, + baseToken: { type: 'string', examples: ['ADA'] }, + quoteToken: { type: 'string', examples: ['MIN'] }, + baseTokenAmount: { type: 'number', examples: [0.001] }, + quoteTokenAmount: { type: 'number', examples: [2.5] }, + slippagePct: { type: 'number', examples: [1] }, + }, + }, + response: { 200: AddLiquidityResponse }, + }, + }, + async (request) => { + try { + const { + network, + poolAddress: reqPool, + baseToken, + quoteToken, + baseTokenAmount, + quoteTokenAmount, + slippagePct, + walletAddress: reqWallet, + } = request.body; + + if ( + !baseToken || + !quoteToken || + !baseTokenAmount || + !quoteTokenAmount + ) { + throw fastify.httpErrors.badRequest('Missing parameters'); + } + + const minswap = await Minswap.getInstance(network || 'mainnet'); + const walletAddr = + reqWallet || (await minswap.cardano.getFirstWalletAddress()); + if (!walletAddr) { + throw fastify.httpErrors.badRequest('No wallet address'); + } + + const poolAddr = + reqPool || + (await minswap.findDefaultPool(baseToken, quoteToken, 'amm')); + if (!poolAddr) { + throw fastify.httpErrors.notFound( + `Pool not found for ${baseToken}-${quoteToken}`, + ); + } + + return await addLiquidity( + fastify, + network || 'mainnet', + walletAddr, + poolAddr, + baseToken, + quoteToken, + baseTokenAmount, + quoteTokenAmount, + slippagePct !== undefined ? slippagePct / 100 : undefined, // convert % to decimal + ); + } catch (e: any) { + logger.error(e); + if (e.statusCode) throw e; + throw fastify.httpErrors.internalServerError('Failed to add liquidity'); + } + }, + ); +}; + +export default addLiquidityRoute; diff --git a/src/connectors/minswap/amm-routes/executeSwap.ts b/src/connectors/minswap/amm-routes/executeSwap.ts new file mode 100644 index 0000000000..aaa6234d57 --- /dev/null +++ b/src/connectors/minswap/amm-routes/executeSwap.ts @@ -0,0 +1,210 @@ +import { FastifyPluginAsync } from 'fastify'; +import { + ExecuteSwapRequestType, + ExecuteSwapRequest, + ExecuteSwapResponseType, + ExecuteSwapResponse, +} from '../../../schemas/swap-schema'; +import { logger } from '../../../services/logger'; +import { Minswap } from '../minswap'; +import { + ADA, + Asset, + Dex, + calculateSwapExactIn, + calculateSwapExactOut, +} from '@aiquant/minswap-sdk'; +import { formatTokenAmount } from '../minswap.utils'; +import { Blockfrost, Lucid, TxComplete } from '@aiquant/lucid-cardano'; + +export const executeSwapRoute: FastifyPluginAsync = async (fastify) => { + await fastify.register(require('@fastify/sensible')); + + fastify.post<{ + Body: ExecuteSwapRequestType; + Reply: ExecuteSwapResponseType; + }>( + '/execute-swap', + { + schema: { + description: 'Execute a swap on Minswap AMM (Cardano)', + tags: ['minswap/amm'], + body: { + ...ExecuteSwapRequest, + properties: { + ...ExecuteSwapRequest.properties, + network: { type: 'string', default: 'mainnet' }, + walletAddress: { type: 'string' }, + baseToken: { type: 'string', examples: ['ADA'] }, + quoteToken: { type: 'string', examples: ['MIN'] }, + amount: { type: 'number', examples: [1.5] }, // now always quote + side: { type: 'string', enum: ['BUY', 'SELL'] }, + poolAddress: { type: 'string' }, + slippagePct: { type: 'number', examples: [1] }, + }, + }, + response: { 200: ExecuteSwapResponse }, + }, + }, + async (request) => { + try { + const { + network, + walletAddress: reqAddr, + baseToken, + quoteToken, + amount, // this is always quote quantity + side, + slippagePct = 1, + poolAddress: reqPool, + } = request.body; + + const net = network || 'mainnet'; + const minswap = await Minswap.getInstance(net); + + const walletAddr = + reqAddr || (await minswap.cardano.getFirstWalletAddress()); + if (!walletAddr) { + throw fastify.httpErrors.badRequest('No wallet address provided'); + } + + const poolAddr = + reqPool || + (await minswap.findDefaultPool(baseToken, quoteToken, 'amm')); + if (!poolAddr) { + throw fastify.httpErrors.notFound( + `Pool not found for ${baseToken}-${quoteToken}`, + ); + } + + const baseInfo = minswap.cardano.getTokenBySymbol(baseToken)!; + const quoteInfo = minswap.cardano.getTokenBySymbol(quoteToken)!; + + // Build Assets + const assetA: Asset = { + policyId: baseInfo.policyId, + tokenName: baseInfo.assetName, + }; + const assetB: Asset = { + policyId: quoteInfo.policyId, + tokenName: quoteInfo.assetName, + }; + + // On‑chain reserves + + const { poolState, poolDatum } = await minswap.getPoolData(poolAddr); + if (!poolState) { + throw fastify.httpErrors.notFound('Pool state unavailable'); + } + const baseReserve = poolState.reserveA; + const quoteReserve = poolState.reserveB; + + const pct = BigInt(slippagePct); + + // 2) build via SDK + const privateKey = + await minswap.cardano.getWalletFromAddress(walletAddr); + minswap.cardano.lucidInstance.selectWalletFromPrivateKey(privateKey); + const dex = new Dex(minswap.cardano.lucidInstance); + + let txBuild: TxComplete; + let baseAmountChange: number; + let quoteAmountChange: number; + let totalInputSwapped: number; + let totalOutputSwapped: number; + + if (side === 'SELL') { + // SELL: selling quote tokens to get base tokens + // `amount` is the amount of quote tokens to sell (input) + const amountIn = BigInt( + Math.floor(amount * 10 ** quoteInfo.decimals).toString(), + ); + + const { amountOut: idealBaseOut } = calculateSwapExactIn({ + amountIn, + reserveIn: quoteReserve, + reserveOut: baseReserve, + }); + const minBaseOut = (idealBaseOut * (100n - pct)) / 100n; + + txBuild = await dex.buildSwapExactInTx({ + sender: walletAddr, + availableUtxos: + await minswap.cardano.lucidInstance.utxosAt(walletAddr), + assetIn: quoteToken === 'ADA' ? ADA : assetB, + amountIn, + assetOut: baseToken === 'ADA' ? ADA : assetA, + minimumAmountOut: minBaseOut, + isLimitOrder: false, + }); + + // SELL: spending quote tokens (-), receiving base tokens (+) + quoteAmountChange = -Number(amount); + baseAmountChange = +Number( + formatTokenAmount(minBaseOut.toString(), baseInfo.decimals), + ); + totalInputSwapped = amount; // quote tokens spent + totalOutputSwapped = Number( + formatTokenAmount(minBaseOut.toString(), baseInfo.decimals), + ); // base tokens received + } else { + // BUY: buying quote tokens with base tokens + // `amount` is the amount of quote tokens to buy (output) + const exactQuoteOut = BigInt( + Math.floor(amount * 10 ** quoteInfo.decimals).toString(), + ); + + const { amountIn: idealBaseIn } = calculateSwapExactOut({ + exactAmountOut: exactQuoteOut, + reserveIn: baseReserve, + reserveOut: quoteReserve, + }); + + const maxBaseIn = (idealBaseIn * (100n + pct)) / 100n; + + txBuild = await dex.buildSwapExactOutTx({ + sender: walletAddr, + availableUtxos: + await minswap.cardano.lucidInstance.utxosAt(walletAddr), + assetIn: baseToken === 'ADA' ? ADA : assetA, + maximumAmountIn: maxBaseIn, + assetOut: quoteToken === 'ADA' ? ADA : assetB, + expectedAmountOut: exactQuoteOut, + }); + + // BUY: spending base tokens (-), receiving quote tokens (+) + baseAmountChange = -Number( + formatTokenAmount(maxBaseIn.toString(), baseInfo.decimals), + ); + quoteAmountChange = +Number(amount); + totalInputSwapped = Number( + formatTokenAmount(maxBaseIn.toString(), baseInfo.decimals), + ); // base tokens spent + totalOutputSwapped = amount; // quote tokens received + } + + // 3) sign & submit + const signed = await txBuild.sign().complete(); + + const txHash = await signed.submit(); + + return { + signature: txHash, + totalInputSwapped: totalInputSwapped, + totalOutputSwapped: totalOutputSwapped, + fee: txBuild.fee, + baseTokenBalanceChange: baseAmountChange, + quoteTokenBalanceChange: quoteAmountChange, + }; + } catch (err: any) { + logger.error('Swap failed:', err); + if (err.statusCode) throw err; + throw fastify.httpErrors.internalServerError( + `Swap execution error: ${err.message}`, + ); + } + }, + ); +}; + +export default executeSwapRoute; diff --git a/src/connectors/minswap/amm-routes/poolInfo.ts b/src/connectors/minswap/amm-routes/poolInfo.ts new file mode 100644 index 0000000000..5bb3a2fed5 --- /dev/null +++ b/src/connectors/minswap/amm-routes/poolInfo.ts @@ -0,0 +1,82 @@ +import { FastifyPluginAsync } from 'fastify'; + +import { + GetPoolInfoRequestType, + GetPoolInfoRequest, + PoolInfo, + PoolInfoSchema, +} from '../../../schemas/amm-schema'; +import { logger } from '../../../services/logger'; +import { Minswap } from '../minswap'; + +export const ammPoolInfoRoute: FastifyPluginAsync = async (fastify) => { + fastify.get<{ + Querystring: GetPoolInfoRequestType; + Reply: Record; + }>( + '/pool-info', + { + schema: { + description: 'Get AMM pool information from Minswap', + tags: ['minswap/amm'], + querystring: { + ...GetPoolInfoRequest, + properties: { + network: { type: 'string', examples: ['mainnet'] }, + poolAddress: { + type: 'string', + examples: [ + '6aa2153e1ae896a95539c9d62f76cedcdabdcdf144e564b8955f609d660cf6a2', + ], + }, + baseToken: { type: 'string', examples: ['ADA'] }, + quoteToken: { type: 'string', examples: ['MIN'] }, + }, + }, + response: { + 200: PoolInfoSchema, + }, + }, + }, + async (request): Promise => { + try { + const { poolAddress, baseToken, quoteToken } = request.query; + const network = request.query.network || 'mainnet'; + + const minswap = await Minswap.getInstance(network); + + // Check if either poolAddress or both baseToken and quoteToken are provided + if (!poolAddress && (!baseToken || !quoteToken)) { + throw fastify.httpErrors.badRequest( + 'Either poolAddress or both baseToken and quoteToken must be provided', + ); + } + + let poolAddressToUse = poolAddress; + + // If no pool address provided, find default pool using base and quote tokens + if (!poolAddressToUse) { + poolAddressToUse = await minswap.findDefaultPool( + baseToken, + quoteToken, + 'amm', + ); + if (!poolAddressToUse) { + throw fastify.httpErrors.notFound( + `No AMM pool found for pair ${baseToken}-${quoteToken}`, + ); + } + } + + const poolInfo = await minswap.getAmmPoolInfo(poolAddressToUse); + if (!poolInfo) throw fastify.httpErrors.notFound('Pool not found'); + return poolInfo; + } catch (e) { + logger.error(e); + throw fastify.httpErrors.internalServerError( + 'Failed to fetch pool info', + ); + } + }, + ); +}; diff --git a/src/connectors/minswap/amm-routes/quoteLiquidity.ts b/src/connectors/minswap/amm-routes/quoteLiquidity.ts new file mode 100644 index 0000000000..63eabc7d1a --- /dev/null +++ b/src/connectors/minswap/amm-routes/quoteLiquidity.ts @@ -0,0 +1,246 @@ +import { BigNumber } from 'ethers'; +import { FastifyPluginAsync } from 'fastify'; +import { Cardano, CardanoTokenInfo } from '../../../chains/cardano/cardano'; +import { + QuoteLiquidityRequestType, + QuoteLiquidityRequest, + QuoteLiquidityResponseType, + QuoteLiquidityResponse, +} from '../../../schemas/amm-schema'; +import { logger } from '../../../services/logger'; +import { Minswap } from '../minswap'; +import { formatTokenAmount } from '../minswap.utils'; + +export async function getMinswapAmmLiquidityQuote( + network: string, + poolAddress?: string, + baseToken?: string, + quoteToken?: string, + baseTokenAmount?: number, + quoteTokenAmount?: number, + _slippagePct?: number, +): Promise<{ + baseLimited: boolean; + baseTokenAmount: number; + quoteTokenAmount: number; + baseTokenAmountMax: number; + quoteTokenAmountMax: number; + baseTokenObj: CardanoTokenInfo; + quoteTokenObj: CardanoTokenInfo; + poolAddress?: string; + rawBaseTokenAmount: BigNumber; + rawQuoteTokenAmount: BigNumber; + routerAddress: string; +}> { + const networkToUse = network || 'mainnet'; + + if (!baseToken || !quoteToken) { + throw new Error('Base token and quote token are required'); + } + if (baseTokenAmount === undefined && quoteTokenAmount === undefined) { + throw new Error('At least one token amount must be provided'); + } + + const minswap = await Minswap.getInstance(networkToUse); + + const baseTokenObj = minswap.cardano.getTokenBySymbol(baseToken); + const quoteTokenObj = minswap.cardano.getTokenBySymbol(quoteToken); + if (!baseTokenObj || !quoteTokenObj) { + throw new Error( + `Token not found: ${!baseTokenObj ? baseToken : quoteToken}`, + ); + } + + let poolAddressToUse = poolAddress; + let existingPool = true; + if (!poolAddressToUse) { + poolAddressToUse = await minswap.findDefaultPool( + baseToken, + quoteToken, + 'amm', + ); + if (!poolAddressToUse) { + existingPool = false; + logger.info( + `No existing pool found for ${baseToken}-${quoteToken}, providing theoretical quote`, + ); + } + } + + let baseTokenAmountOptimal = baseTokenAmount!; + let quoteTokenAmountOptimal = quoteTokenAmount!; + let baseLimited = false; + + if (existingPool) { + const { poolState, poolDatum } = + await minswap.getPoolData(poolAddressToUse); + + if (!poolState) { + throw new Error(`Unable to load pool ${poolAddressToUse}`); + } + + // ── 2) Pull reserves as bigints ──────────────────────── + const baseReserve: bigint = poolState.reserveA; + const quoteReserve: bigint = poolState.reserveB; + + // ── 3) Convert user inputs into raw bigints ─────────── + const baseRaw = baseTokenAmount + ? BigInt( + Math.floor(baseTokenAmount * 10 ** baseTokenObj.decimals).toString(), + ) + : null; + const quoteRaw = quoteTokenAmount + ? BigInt( + Math.floor( + quoteTokenAmount * 10 ** quoteTokenObj.decimals, + ).toString(), + ) + : null; + + // ── 4) Compute the “optimal” opposite amount ─────────── + if (baseRaw !== null && quoteRaw !== null) { + // both sides provided → pick the limiting one + const quoteOptimal = (baseRaw * quoteReserve) / baseReserve; + if (quoteOptimal <= quoteRaw) { + baseLimited = true; + quoteTokenAmountOptimal = Number( + formatTokenAmount(quoteOptimal.toString(), quoteTokenObj.decimals), + ); + } else { + baseLimited = false; + const baseOptimal = (quoteRaw * baseReserve) / quoteReserve; + baseTokenAmountOptimal = Number( + formatTokenAmount(baseOptimal.toString(), baseTokenObj.decimals), + ); + } + } else if (baseRaw !== null) { + // only base provided + const quoteOptimal = + baseReserve === BigInt(0) + ? BigInt(0) + : (baseRaw * quoteReserve) / baseReserve; + quoteTokenAmountOptimal = Number( + formatTokenAmount(quoteOptimal.toString(), quoteTokenObj.decimals), + ); + baseLimited = true; + } else if (quoteRaw !== null) { + // only quote provided + const baseOptimal = + quoteReserve === BigInt(0) + ? BigInt(0) + : (quoteRaw * baseReserve) / quoteReserve; + baseTokenAmountOptimal = Number( + formatTokenAmount(baseOptimal.toString(), baseTokenObj.decimals), + ); + baseLimited = false; + } + } else { + // new pool → must supply both + if (baseTokenAmount == null || quoteTokenAmount == null) { + throw new Error( + 'For a new pool, you must supply both baseTokenAmount and quoteTokenAmount', + ); + } + baseLimited = false; // arbitrary; both get used + } + + // ── 5) Convert back into Ethers BigNumber for any on‐chain tx ─── + const rawBaseTokenAmount = BigNumber.from( + Math.floor(baseTokenAmountOptimal * 10 ** baseTokenObj.decimals).toString(), + ); + const rawQuoteTokenAmount = BigNumber.from( + Math.floor( + quoteTokenAmountOptimal * 10 ** quoteTokenObj.decimals, + ).toString(), + ); + + return { + baseLimited, + baseTokenAmount: baseTokenAmountOptimal, + quoteTokenAmount: quoteTokenAmountOptimal, + baseTokenAmountMax: baseTokenAmount ?? baseTokenAmountOptimal, + quoteTokenAmountMax: quoteTokenAmount ?? quoteTokenAmountOptimal, + baseTokenObj, + quoteTokenObj, + poolAddress: poolAddressToUse, + rawBaseTokenAmount, + rawQuoteTokenAmount, + routerAddress: 'N/A', + }; +} + +export const quoteLiquidityRoute: FastifyPluginAsync = async (fastify) => { + await fastify.register(require('@fastify/sensible')); + fastify.get<{ + Querystring: QuoteLiquidityRequestType; + Reply: QuoteLiquidityResponseType; + }>( + '/quote-liquidity', + { + schema: { + description: 'Get liquidity quote for Minswap', + tags: ['minswap/amm'], + querystring: { + ...QuoteLiquidityRequest, + properties: { + ...QuoteLiquidityRequest.properties, + network: { type: 'string', default: 'mainnet' }, + poolAddress: { + type: 'string', + examples: [''], + }, + baseToken: { type: 'string', examples: ['ADA'] }, + quoteToken: { type: 'string', examples: ['MIN'] }, + baseTokenAmount: { type: 'number', examples: [0.029314] }, + quoteTokenAmount: { type: 'number', examples: [1] }, + slippagePct: { type: 'number', examples: [1] }, + }, + }, + response: { + 200: QuoteLiquidityResponse, + }, + }, + }, + async (request) => { + try { + const { + network, + poolAddress, + baseToken, + quoteToken, + baseTokenAmount, + quoteTokenAmount, + slippagePct, + } = request.query; + + const quote = await getMinswapAmmLiquidityQuote( + network, + poolAddress, + baseToken, + quoteToken, + baseTokenAmount, + quoteTokenAmount, + slippagePct, + ); + + return { + baseLimited: quote.baseLimited, + baseTokenAmount: quote.baseTokenAmount, + quoteTokenAmount: quote.quoteTokenAmount, + baseTokenAmountMax: quote.baseTokenAmountMax, + quoteTokenAmountMax: quote.quoteTokenAmountMax, + }; + } catch (e) { + logger.error(e); + if (e.statusCode) { + throw e; + } + throw fastify.httpErrors.internalServerError( + 'Failed to get liquidity quote', + ); + } + }, + ); +}; + +export default quoteLiquidityRoute; diff --git a/src/connectors/minswap/amm-routes/quoteSwap.ts b/src/connectors/minswap/amm-routes/quoteSwap.ts new file mode 100644 index 0000000000..83878df97e --- /dev/null +++ b/src/connectors/minswap/amm-routes/quoteSwap.ts @@ -0,0 +1,421 @@ +import { BigNumber } from 'ethers'; +import { FastifyPluginAsync, FastifyInstance } from 'fastify'; +import { Cardano, CardanoTokenInfo } from '../../../chains/cardano/cardano'; +import { + GetSwapQuoteResponseType, + GetSwapQuoteResponse, + GetSwapQuoteRequestType, + GetSwapQuoteRequest, +} from '../../../schemas/swap-schema'; +import { logger } from '../../../services/logger'; +import { Minswap } from '../minswap'; +import { formatTokenAmount } from '../minswap.utils'; +import { + Asset, + calculateSwapExactIn, + calculateSwapExactOut, +} from '@aiquant/minswap-sdk'; +import { BN } from 'bn.js'; + +async function quoteAmmSwap( + minswap: Minswap, + poolAddress: string, + baseToken: CardanoTokenInfo, + quoteToken: CardanoTokenInfo, + amount: number, // now always refers to quote‐token units + side: 'BUY' | 'SELL', + slippagePct?: number, +): Promise { + // BUY: you want to RECEIVE `amount` of quoteToken, paying baseToken + // SELL: you want to SPEND `amount` of quoteToken, receiving baseToken + const exactIn = side === 'SELL'; + + // Figure out which asset is input vs. output + const inputToken = exactIn ? quoteToken : baseToken; + const outputToken = exactIn ? baseToken : quoteToken; + + // FIXED: Convert `amount` to smallest‐unit based on what the amount represents + // For BUY: amount = desired quoteToken amount (output) + // For SELL: amount = available quoteToken amount (input) + let amountInSmallestUnit: bigint; + + if (side === 'BUY') { + // For BUY, amount represents the desired quoteToken (output), but we need exactOut calculation + // So convert amount using quoteToken decimals + amountInSmallestUnit = BigNumber.from( + Math.floor(amount * 10 ** quoteToken.decimals), + ).toBigInt(); + } else { + // For SELL, amount represents the quoteToken to spend (input) + // So convert amount using quoteToken decimals + amountInSmallestUnit = BigNumber.from( + Math.floor(amount * 10 ** quoteToken.decimals), + ).toBigInt(); + } + + const { poolState, poolDatum } = await minswap.getPoolData(poolAddress); + + if (!poolState) + throw new Error( + `Pool not found for ${baseToken.symbol}-${quoteToken.symbol}`, + ); + + // Figure out reserves & fee depending on input/output + const idA = poolState.assetA; + const idB = poolState.assetB; + const assetIdIn = + inputToken.symbol === 'ADA' + ? 'lovelace' + : inputToken.policyId + inputToken.assetName; + let reserveIn: bigint, reserveOut: bigint; + if (assetIdIn === idA) { + reserveIn = poolState.reserveA; + reserveOut = poolState.reserveB; + } else if (assetIdIn === idB) { + reserveIn = poolState.reserveB; + reserveOut = poolState.reserveA; + } else { + throw new Error(`Input token not in pool`); + } + + // Do the math + let inputAmount: bigint, outputAmount: bigint, priceImpact: number; + if (exactIn) { + // SELL: spending exact amount of quoteToken + inputAmount = amountInSmallestUnit; + const { amountOut, priceImpact: pi } = calculateSwapExactIn({ + amountIn: inputAmount, + reserveIn, + reserveOut, + }); + outputAmount = amountOut; + priceImpact = pi.toNumber(); + } else { + // BUY: want to receive exact amount of quoteToken + outputAmount = amountInSmallestUnit; + const { amountIn, priceImpact: pi } = calculateSwapExactOut({ + exactAmountOut: outputAmount, + reserveIn, + reserveOut, + }); + inputAmount = amountIn; + priceImpact = pi.toNumber(); + } + + const effectiveSlippage = + slippagePct !== undefined + ? slippagePct / 100 + : minswap.getAllowedSlippage(); + + const minAmountOut = exactIn + ? new BN(outputAmount.toString()) + .mul(new BN(Math.floor((1 - effectiveSlippage) * 10000))) + .div(new BN(10000)) + : outputAmount; + + const maxAmountIn = exactIn + ? inputAmount + : new BN(inputAmount.toString()) + .mul(new BN(Math.floor((1 + effectiveSlippage) * 10000))) + .div(new BN(10000)); + + // Format human‐readable + const estimatedIn = formatTokenAmount( + inputAmount.toString(), + inputToken.decimals, + ); + const estimatedOut = formatTokenAmount( + outputAmount.toString(), + outputToken.decimals, + ); + const minOutHuman = formatTokenAmount( + minAmountOut.toString(), + outputToken.decimals, + ); + const maxInHuman = formatTokenAmount( + maxAmountIn.toString(), + inputToken.decimals, + ); + + return { + poolAddress, + estimatedAmountIn: estimatedIn, + estimatedAmountOut: estimatedOut, + minAmountOut: minOutHuman, + maxAmountIn: maxInHuman, + priceImpact, + inputToken, + outputToken, + rawAmountIn: inputAmount.toString(), + rawAmountOut: outputAmount.toString(), + rawMinAmountOut: minAmountOut.toString(), + rawMaxAmountIn: maxAmountIn.toString(), + pathAddresses: [ + inputToken.address || `${inputToken.policyId}.${inputToken.assetName}`, + outputToken.address || `${outputToken.policyId}.${outputToken.assetName}`, + ], + }; +} + +export async function getMinswapAmmQuote( + _fastify: FastifyInstance, + network: string, + poolAddress: string, + baseToken: string, + quoteToken: string, + amount: number, + side: 'BUY' | 'SELL', + slippagePct?: number, +): Promise<{ + quote: any; + minswap: any; + cardano: any; + baseTokenObj: any; + quoteTokenObj: any; +}> { + // Get instances + const minswap = await Minswap.getInstance(network); + const cardano = await Cardano.getInstance(network); + + if (!cardano.ready()) { + logger.info('Cardano instance not ready, initializing...'); + await cardano.init(); + } + + // Resolve tokens + const baseTokenObj = cardano.getTokenBySymbol(baseToken); + const quoteTokenObj = cardano.getTokenBySymbol(quoteToken); + + if (!baseTokenObj) { + logger.error(`Base token not found: ${baseToken}`); + throw new Error(`Base token not found: ${baseToken}`); + } + + if (!quoteTokenObj) { + logger.error(`Quote token not found: ${quoteToken}`); + throw new Error(`Quote token not found: ${quoteToken}`); + } + + logger.info( + `Base token: ${baseTokenObj.symbol}, address=${baseTokenObj.address}, decimals=${baseTokenObj.decimals}`, + ); + logger.info( + `Quote token: ${quoteTokenObj.symbol}, address=${quoteTokenObj.address}, decimals=${quoteTokenObj.decimals}`, + ); + + // Get the quote + const quote = await quoteAmmSwap( + minswap, + poolAddress, + baseTokenObj, + quoteTokenObj, + amount, + side as 'BUY' | 'SELL', + slippagePct, + ); + + if (!quote) { + throw new Error('Failed to get swap quote'); + } + + return { + quote, + minswap, + cardano, + baseTokenObj, + quoteTokenObj, + }; +} + +async function formatSwapQuote( + fastify: FastifyInstance, + network: string, + poolAddress: string, + baseToken: string, + quoteToken: string, + amount: number, + side: 'BUY' | 'SELL', + slippagePct?: number, +): Promise { + logger.info( + `formatSwapQuote: poolAddress=${poolAddress}, baseToken=${baseToken}, quoteToken=${quoteToken}, amount=${amount}, side=${side}, network=${network}`, + ); + + try { + // Use the extracted quote function + const { quote, minswap, cardano, baseTokenObj, quoteTokenObj } = + await getMinswapAmmQuote( + fastify, + network, + poolAddress, + baseToken, + quoteToken, + amount, + side, + slippagePct, + ); + + logger.info( + `Quote result: estimatedAmountIn=${quote.estimatedAmountIn}, estimatedAmountOut=${quote.estimatedAmountOut}`, + ); + + // Calculate balance changes based on which tokens are being swapped + // The quote object tells us which token is input and which is output + let baseTokenBalanceChange: number; + let quoteTokenBalanceChange: number; + + if (side === 'SELL') { + // SELL: spending quoteToken, receiving baseToken + // Input token is quoteToken, output token is baseToken + baseTokenBalanceChange = quote.estimatedAmountOut; // positive (receiving) + quoteTokenBalanceChange = -quote.estimatedAmountIn; // negative (spending) + } else { + // BUY: spending baseToken, receiving quoteToken + // Input token is baseToken, output token is quoteToken + baseTokenBalanceChange = -quote.estimatedAmountIn; // negative (spending) + quoteTokenBalanceChange = quote.estimatedAmountOut; // positive (receiving) + } + + logger.info( + `Balance changes: baseTokenBalanceChange=${baseTokenBalanceChange}, quoteTokenBalanceChange=${quoteTokenBalanceChange}`, + ); + + // Calculate price based on side + // For SELL: price = quote received / base sold + // For BUY: price = quote needed / base received + const price = + side === 'SELL' + ? quote.estimatedAmountOut / quote.estimatedAmountIn + : quote.estimatedAmountIn / quote.estimatedAmountOut; + + return { + poolAddress, + estimatedAmountIn: quote.estimatedAmountIn, + estimatedAmountOut: quote.estimatedAmountOut, + minAmountOut: quote.minAmountOut, + maxAmountIn: quote.maxAmountIn, + baseTokenBalanceChange, + quoteTokenBalanceChange, + price, + gasPrice: 0, + gasLimit: 0, + gasCost: 0, + }; + } catch (error) { + logger.error(`Error formatting swap quote: ${error.message}`); + if (error.stack) { + logger.debug(`Stack trace: ${error.stack}`); + } + throw error; + } +} + +export const quoteSwapRoute: FastifyPluginAsync = async (fastify) => { + // Import the httpErrors plugin to ensure it's available + await fastify.register(require('@fastify/sensible')); + + fastify.get<{ + Querystring: GetSwapQuoteRequestType; + Reply: GetSwapQuoteResponseType; + }>( + '/quote-swap', + { + schema: { + description: 'Get swap quote for Minswap AMM', + tags: ['minswap/amm'], + querystring: { + ...GetSwapQuoteRequest, + properties: { + ...GetSwapQuoteRequest.properties, + network: { type: 'string', default: 'mainnet' }, + baseToken: { type: 'string', examples: ['ADA'] }, + quoteToken: { type: 'string', examples: ['MIN'] }, + amount: { type: 'number', examples: [0.001] }, + side: { type: 'string', enum: ['BUY', 'SELL'], examples: ['SELL'] }, + poolAddress: { type: 'string', examples: [''] }, + slippagePct: { type: 'number', examples: [1] }, + }, + }, + response: { + 200: { + properties: { + ...GetSwapQuoteResponse.properties, + }, + }, + }, + }, + }, + async (request) => { + try { + const { + network, + poolAddress: requestedPoolAddress, + baseToken, + quoteToken, + amount, + side, + slippagePct, + } = request.query; + + const networkToUse = network || 'mainnet'; + + const minswap = await Minswap.getInstance(networkToUse); + let poolAddress = requestedPoolAddress; + + if (!poolAddress) { + // Look up the pool from configuration pools dictionary + poolAddress = await minswap.findDefaultPool( + baseToken, + quoteToken, + 'amm', + ); + + if (!poolAddress) { + throw fastify.httpErrors.notFound( + `No AMM pool found for pair ${baseToken}-${quoteToken}`, + ); + } + } + + return await formatSwapQuote( + fastify, + networkToUse, + poolAddress, + baseToken, + quoteToken, + amount, + side as 'BUY' | 'SELL', + slippagePct, + ); + } catch (e) { + logger.error(`Error in quote-swap route: ${e.message}`); + + // If it's already a Fastify HTTP error, re-throw it + if (e.statusCode) { + throw e; + } + + // Check for specific error types + if (e.message?.includes('Insufficient liquidity')) { + throw fastify.httpErrors.badRequest(e.message); + } + if ( + e.message?.includes('Pool not found') || + e.message?.includes('No AMM pool found') + ) { + throw fastify.httpErrors.notFound(e.message); + } + if (e.message?.includes('token not found')) { + throw fastify.httpErrors.badRequest(e.message); + } + + // Default to internal server error with the actual error message + throw fastify.httpErrors.internalServerError( + `Error getting swap quote: ${e.message || 'Unknown error'}`, + ); + } + }, + ); +}; + +export default quoteSwapRoute; diff --git a/src/connectors/minswap/amm-routes/removeLiquidity.ts b/src/connectors/minswap/amm-routes/removeLiquidity.ts new file mode 100644 index 0000000000..3a053182fe --- /dev/null +++ b/src/connectors/minswap/amm-routes/removeLiquidity.ts @@ -0,0 +1,193 @@ +import { BigNumber } from 'ethers'; +import { FastifyPluginAsync } from 'fastify'; + +import { Cardano } from '../../../chains/cardano/cardano'; +import { + RemoveLiquidityRequestType, + RemoveLiquidityRequest, + RemoveLiquidityResponseType, + RemoveLiquidityResponse, +} from '../../../schemas/amm-schema'; +import { logger } from '../../../services/logger'; +import { Minswap } from '../minswap'; + +import { formatTokenAmount } from '../minswap.utils'; +import { Asset, calculateWithdraw, Dex } from '@aiquant/minswap-sdk'; + +export const removeLiquidityRoute: FastifyPluginAsync = async (fastify) => { + fastify.post<{ + Body: RemoveLiquidityRequestType; + Reply: RemoveLiquidityResponseType; + }>( + '/remove-liquidity', + { + schema: { + description: 'Remove liquidity from a Minswap pool', + tags: ['minswap/amm'], + body: { + ...RemoveLiquidityRequest, + properties: { + ...RemoveLiquidityRequest.properties, + network: { type: 'string', default: 'preprod' }, + walletAddress: { type: 'string', examples: ['addr...'] }, + poolAddress: { + type: 'string', + examples: [''], + }, + baseToken: { type: 'string', examples: ['ADA'] }, + quoteToken: { type: 'string', examples: ['MIN'] }, + percentageToRemove: { type: 'number', examples: [100] }, + }, + }, + response: { + 200: RemoveLiquidityResponse, + }, + }, + }, + async (request) => { + try { + const { + network, + poolAddress: requestedPoolAddress, + baseToken, + quoteToken, + percentageToRemove, + walletAddress: requestedWalletAddress, + } = request.body; + + const networkToUse = network || 'preprod'; + + // Validate essential parameters + if (!baseToken || !quoteToken || !percentageToRemove) { + throw fastify.httpErrors.badRequest('Missing required parameters'); + } + + if (percentageToRemove <= 0 || percentageToRemove > 100) { + throw fastify.httpErrors.badRequest( + 'Percentage to remove must be between 0 and 100', + ); + } + + // Get Minswap and Cardano instances + const minswap = await Minswap.getInstance(networkToUse); + + // Get wallet address - either from request or first available + let walletAddress = requestedWalletAddress; + if (!walletAddress) { + walletAddress = await minswap.cardano.getFirstWalletAddress(); + if (!walletAddress) { + throw fastify.httpErrors.badRequest( + 'No wallet address provided and no default wallet found', + ); + } + logger.info(`Using first available wallet address: ${walletAddress}`); + } + + // Resolve tokens + const baseTokenObj = minswap.cardano.getTokenBySymbol(baseToken); + const quoteTokenObj = minswap.cardano.getTokenBySymbol(quoteToken); + + if (!baseTokenObj || !quoteTokenObj) { + throw fastify.httpErrors.badRequest( + `Token not found: ${!baseTokenObj ? baseToken : quoteToken}`, + ); + } + + // Find pool address if not provided + let poolAddress = requestedPoolAddress; + if (!poolAddress) { + poolAddress = await minswap.findDefaultPool( + baseToken, + quoteToken, + 'amm', + ); + + if (!poolAddress) { + throw fastify.httpErrors.notFound( + `No AMM pool found for pair ${baseToken}-${quoteToken}`, + ); + } + } + // 5) Fetch on-chain pool state for withdraw calculation + const assetA: Asset = { + policyId: baseTokenObj.policyId, + tokenName: baseTokenObj.assetName, + }; + const assetB: Asset = { + policyId: quoteTokenObj.policyId, + tokenName: quoteTokenObj.assetName, + }; + const { poolState, poolDatum } = await minswap.getPoolData(poolAddress); + + // 6) Fetch wallet UTxOs (this also selects the key in Lucid) + const wallet = + await minswap.cardano.getWalletFromAddress(walletAddress); + minswap.cardano.lucidInstance.selectWalletFromPrivateKey(wallet); + const utxos = + await minswap.cardano.lucidInstance.utxosAt(walletAddress); + + // 8) Calculate withdrawal amounts + const totalLpInWallet = minswap.calculateAssetAmount( + utxos, + poolState.assetLP, + ); + + const withdrawLpAmount = + (totalLpInWallet * BigInt(percentageToRemove)) / 100n; + + // 9) Calculate the assets to be received upon withdrawal + const { amountAReceive, amountBReceive } = calculateWithdraw({ + withdrawalLPAmount: withdrawLpAmount, + reserveA: poolState.reserveA, + reserveB: poolState.reserveB, + totalLiquidity: poolDatum.totalLiquidity, + }); + + const lpAsset = Asset.fromString(poolState.assetLP); + // minimums = 0 here; you could tighten via slippage + const dex = new Dex(minswap.cardano.lucidInstance); + const txBuild = await dex.buildWithdrawTx({ + sender: walletAddress, + lpAsset: lpAsset, + lpAmount: withdrawLpAmount, + minimumAssetAReceived: amountAReceive, + minimumAssetBReceived: amountBReceive, + availableUtxos: utxos, + }); + + // 9) Sign & submit + const signed = await txBuild.sign().complete(); + const txHash = await signed.submit(); + const fee = txBuild.fee; + + // 10) Compute how many tokens were removed (roughly) + const baseTokenAmountRemoved = formatTokenAmount( + amountAReceive, + baseTokenObj.decimals, + ); + const quoteTokenAmountRemoved = formatTokenAmount( + amountBReceive, + quoteTokenObj.decimals, + ); + + return { + signature: txHash, + fee, + baseTokenAmountRemoved, + quoteTokenAmountRemoved, + }; + } catch (e) { + logger.error(e); + if (e.statusCode) { + throw e; + } + + throw fastify.httpErrors.internalServerError( + 'Failed to remove liquidity', + ); + } + }, + ); +}; + +export default removeLiquidityRoute; diff --git a/src/connectors/minswap/minswap.config.ts b/src/connectors/minswap/minswap.config.ts new file mode 100644 index 0000000000..455d42316f --- /dev/null +++ b/src/connectors/minswap/minswap.config.ts @@ -0,0 +1,62 @@ +import { ConfigManagerV2 } from '../../services/config-manager-v2'; + +interface AvailableNetworks { + chain: string; + networks: Array; +} + +export namespace MinswapConfig { + // Supported networks for Minswap + export const chain = 'cardano'; + export const networks = ['mainnet', 'preprod']; + + export interface PoolsConfig { + [pairKey: string]: string; + } + + export interface NetworkConfig { + // Pool configurations + amm: PoolsConfig; + } + + export interface NetworkPoolsConfig { + // Dictionary of predefined pool addresses and settings by network + [network: string]: NetworkConfig; + } + + export interface RootConfig { + // Global configuration + allowedSlippage: string; + + // Network-specific configurations + networks: NetworkPoolsConfig; + + // Available networks + availableNetworks: Array; + } + + export const config: RootConfig = { + // Global configuration + allowedSlippage: ConfigManagerV2.getInstance().get( + 'minswap.allowedSlippage', + ), + + // Network-specific pools + networks: ConfigManagerV2.getInstance().get('minswap.networks'), + + availableNetworks: [ + { + chain: 'cardano', + networks: ['mainnet', 'preprod'], + }, + ], + }; + + // Helper methods to get pools for a specific network + export const getNetworkPools = ( + network: string, + poolType: 'amm', + ): PoolsConfig => { + return config.networks[network]?.[poolType] || {}; + }; +} diff --git a/src/connectors/minswap/minswap.routes.ts b/src/connectors/minswap/minswap.routes.ts new file mode 100644 index 0000000000..2358eb4e09 --- /dev/null +++ b/src/connectors/minswap/minswap.routes.ts @@ -0,0 +1,33 @@ +import sensible from '@fastify/sensible'; +import type { FastifyPluginAsync } from 'fastify'; +import { ammPoolInfoRoute } from './amm-routes/poolInfo'; +import { quoteSwapRoute as ammQuoteSwapRoute } from './amm-routes/quoteSwap'; +import quoteLiquidityRoute from './amm-routes/quoteLiquidity'; +import { executeSwapRoute as ammExecuteSwapRoute } from './amm-routes/executeSwap'; +import { addLiquidityRoute as ammAddLiquidityRoute } from './amm-routes/addLiquidity'; +import { removeLiquidityRoute as ammRemoveLiquidityRoute } from './amm-routes/removeLiquidity'; + +// AMM routes including swap endpoints +const minswapAmmRoutes: FastifyPluginAsync = async (fastify) => { + await fastify.register(sensible); + + await fastify.register(async (instance) => { + instance.addHook('onRoute', (routeOptions) => { + if (routeOptions.schema && routeOptions.schema.tags) { + routeOptions.schema.tags = ['minswap/amm']; + } + }); + + await instance.register(ammPoolInfoRoute); + await instance.register(ammQuoteSwapRoute); + await instance.register(quoteLiquidityRoute); + await instance.register(ammExecuteSwapRoute); + await instance.register(ammAddLiquidityRoute); + await instance.register(ammRemoveLiquidityRoute); + }); +}; + +// Main export that combines all routes +export const minswapRoutes = { + amm: minswapAmmRoutes, +}; diff --git a/src/connectors/minswap/minswap.ts b/src/connectors/minswap/minswap.ts new file mode 100644 index 0000000000..fe515730c1 --- /dev/null +++ b/src/connectors/minswap/minswap.ts @@ -0,0 +1,207 @@ +import { Cardano } from '../../chains/cardano/cardano'; +import { Data, PrivateKey, TxComplete, UTxO } from '@aiquant/lucid-cardano'; +import { BlockFrostAPI } from '@blockfrost/blockfrost-js'; +import { + ADA, + Asset, + BlockfrostAdapter, + NetworkId, + PoolV1, +} from '@aiquant/minswap-sdk'; + +import { + percentRegexp, + ConfigManagerV2, +} from '../../services/config-manager-v2'; +import { logger } from '../../services/logger'; + +import { MinswapConfig } from './minswap.config'; +import { PoolInfo } from '../../schemas/amm-schema'; +import { findPoolAddress, isFractionString } from './minswap.utils'; + +export class Minswap { + private static _instances: { [name: string]: Minswap }; + public cardano: Cardano; + public config: MinswapConfig.RootConfig; + private owner?: PrivateKey; + public blockfrostAdapter: BlockfrostAdapter; + // Network information + private networkName: string; + + private constructor(network: string) { + this.networkName = network; + this.config = MinswapConfig.config as MinswapConfig.RootConfig; + this.cardano = null; + } + + /** Gets singleton instance of Minswap */ + public static async getInstance(network: string): Promise { + if (!Minswap._instances) { + Minswap._instances = {}; + } + + if (!Minswap._instances[network]) { + const instance = new Minswap(network); + await instance.init(network); + Minswap._instances[network] = instance; + } + + return Minswap._instances[network]; + } + + /** Initializes Minswap instance */ + private async init(network: string) { + try { + this.cardano = await Cardano.getInstance(network); + + // Load first wallet if available + const walletAddress = await this.cardano.getFirstWalletAddress(); + if (walletAddress) { + this.owner = await this.cardano.getWalletFromAddress(walletAddress); + } + this.blockfrostAdapter = new BlockfrostAdapter({ + networkId: + this.cardano.network === 'preprod' + ? NetworkId.TESTNET + : NetworkId.MAINNET, + blockFrost: new BlockFrostAPI({ + projectId: this.cardano.projectId, + }), + }); + + logger.info( + 'Minswap initialized' + + (walletAddress ? ` with wallet: ${walletAddress}` : 'with no wallet'), + ); + } catch (error) { + logger.error('Minswap initialization failed:', error); + throw error; + } + } + + /** + * Gets the allowed slippage percentage from config + * @returns Slippage as a percentage (e.g., 1.0 for 1%) + */ + getSlippagePct(): number { + const allowedSlippage = MinswapConfig.config.allowedSlippage; + const nd = allowedSlippage.match(percentRegexp); + let slippage = 0.0; + if (nd) { + slippage = Number(nd[1]) / Number(nd[2]); + } else { + logger.error('Failed to parse slippage value:', allowedSlippage); + } + return slippage * 100; + } + + private getPairKey(baseToken: string, quoteToken: string): string { + return `${baseToken}-${quoteToken}`; + } + + async findDefaultPool( + baseToken: string, + quoteToken: string, + routeType: 'amm', + ): Promise { + // Get the network-specific pools + const network = this.cardano.network; + const pools = MinswapConfig.getNetworkPools(network, routeType); + + if (!pools) return null; + + const pairKey = this.getPairKey(baseToken, quoteToken); + const reversePairKey = this.getPairKey(quoteToken, baseToken); + + return pools[pairKey] || pools[reversePairKey] || null; + } + + async getAmmPoolInfo(poolAddress: string): Promise { + const pool = await this.blockfrostAdapter.getV1PoolById({ + id: poolAddress, + }); + if (!pool) { + throw new Error(`Not found PoolState of ID: ${poolAddress}`); + } + + const getQuantity = (unit) => { + const found = pool.value.find((v) => v.unit === unit); + return found ? Number(found.quantity) : 0; + }; + + const baseTokenUnit = pool.assetA; // e.g., 'lovelace' + const quoteTokenUnit = pool.assetB; // e.g., '29d...d494e' + + const baseTokenAmount = getQuantity(baseTokenUnit); + const quoteTokenAmount = getQuantity(quoteTokenUnit); + + // Convert to number for price calculation (if not zero) + const price = await this.blockfrostAdapter.getV1PoolPrice({ + pool: pool, + }); + + return { + address: poolAddress, + baseTokenAddress: pool.assetA, + quoteTokenAddress: pool.assetB, + feePct: 2, + price: price[0], + baseTokenAmount: baseTokenAmount, + quoteTokenAmount: quoteTokenAmount, + poolType: 'amm', + lpMint: { + address: pool.assetLP, + decimals: 0, + }, + }; + } + + /** + * Get the allowed slippage as a decimal from string or config + * @param allowedSlippageStr Optional string representation of slippage value + * @returns A decimal number (e.g., 0.05 for 5%) + */ + public getAllowedSlippage(allowedSlippageStr?: string): number { + if (allowedSlippageStr != null && isFractionString(allowedSlippageStr)) { + const fractionSplit = allowedSlippageStr.split('/'); + return Number(fractionSplit[0]) / Number(fractionSplit[1]); + } + + // Use the global allowedSlippage setting + const allowedSlippage = this.config.allowedSlippage; + + const nd = allowedSlippage.match(percentRegexp); + if (nd) return Number(nd[1]) / Number(nd[2]); + + throw new Error( + 'Encountered a malformed percent string in the config for allowed slippage.', + ); + } + + public calculateAssetAmount(utxos: UTxO[], asset: string): bigint { + return utxos.reduce((acc, utxo) => { + const assetValue = utxo.assets[asset]; + if (assetValue) { + return acc + BigInt(assetValue); // Ensure addition is performed with BigInt + } + return acc; + }, 0n); // Initialize the accumulator with BigInt zero + } + + async getPoolData(poolAddress: string) { + const poolState = await this.blockfrostAdapter.getV1PoolById({ + id: poolAddress, + }); + if (!poolState) { + throw new Error(`Not found PoolState of ID: ${poolAddress}`); + } + const rawPoolDatum = await this.blockfrostAdapter.getDatumByDatumHash( + poolState.datumHash, + ); + const poolDatum = PoolV1.Datum.fromPlutusData( + this.networkName === 'mainnet' ? NetworkId.MAINNET : NetworkId.TESTNET, + Data.from(rawPoolDatum), + ); + return { poolState, poolDatum }; + } +} diff --git a/src/connectors/minswap/minswap.utils.ts b/src/connectors/minswap/minswap.utils.ts new file mode 100644 index 0000000000..8139340dad --- /dev/null +++ b/src/connectors/minswap/minswap.utils.ts @@ -0,0 +1,65 @@ +import { logger } from '../../services/logger'; +import { MinswapConfig } from './minswap.config'; + +/** + * Find a pool address for a token pair in the configured pools + * + * @param baseToken Base token symbol + * @param quoteToken Quote token symbol + * @param poolType Type of pool ('amm' or 'clmm') + * @param network Network name (defaults to 'mainnet-beta') + * @returns Pool address or null if not found + */ +export const findPoolAddress = ( + baseToken: string, + quoteToken: string, + poolType: 'amm', + network: string = 'mainnet', +): string | null => { + // Get the network-specific pools + const pools = MinswapConfig.getNetworkPools(network, poolType); + if (!pools) return null; + + // Try standard order (BASE-QUOTE) + const standardKey = `${baseToken}-${quoteToken}`; + if (pools[standardKey]) return pools[standardKey]; + + // Try reverse order (QUOTE-BASE) + const reverseKey = `${quoteToken}-${baseToken}`; + if (pools[reverseKey]) return pools[reverseKey]; + + return null; +}; + +/** + * Format token amounts for display + * @param amount The raw amount as a string or number + * @param decimals The token decimals + * @returns The formatted token amount + */ +export const formatTokenAmount = ( + amount: string | number | bigint, + decimals: number, +): number => { + try { + if (typeof amount === 'string') { + return parseFloat(amount) / Math.pow(10, decimals); + } + if (typeof amount === 'bigint') { + return Number(amount) / Math.pow(10, decimals); + } + return amount / Math.pow(10, decimals); + } catch (error) { + logger.error(`Error formatting token amount: ${error}`); + return 0; + } +}; + +/** + * Check if a string is a valid fraction (in the form of 'a/b') + * @param value The string to check + * @returns True if the string is a valid fraction, false otherwise + */ +export function isFractionString(value: string): boolean { + return value.includes('/') && value.split('/').length === 2; +} diff --git a/src/connectors/sundaeswap/amm-routes/addLiquidity.ts b/src/connectors/sundaeswap/amm-routes/addLiquidity.ts new file mode 100644 index 0000000000..d571130f05 --- /dev/null +++ b/src/connectors/sundaeswap/amm-routes/addLiquidity.ts @@ -0,0 +1,181 @@ +import { BigNumber } from 'ethers'; +import { FastifyPluginAsync } from 'fastify'; + +import { + AddLiquidityRequestType, + AddLiquidityRequest, + AddLiquidityResponseType, + AddLiquidityResponse, +} from '../../../schemas/amm-schema'; +import { logger } from '../../../services/logger'; +import { Sundaeswap } from '../sundaeswap'; +import { formatTokenAmount } from '../sundaeswap.utils'; +import { getSundaeswapAmmLiquidityQuote } from './quoteLiquidity'; +import { Assets, TxComplete } from '@aiquant/lucid-cardano'; +import { + EDatumType, + IDepositConfigArgs, + TSupportedNetworks, +} from '@aiquant/sundaeswap-core'; +import { AssetAmount, IAssetAmountMetadata } from '@sundaeswap/asset'; +import { + DatumBuilderLucidV3, + TxBuilderLucidV3, +} from '@aiquant/sundaeswap-core/lucid'; + +async function addLiquidity( + fastify: any, + network: string, + walletAddress: string, + poolAddress: string, + baseToken: string, + quoteToken: string, + baseTokenAmount: number, + quoteTokenAmount: number, + slippagePct?: number, // decimal, e.g. 0.01 for 1% +): Promise { + const networkToUse = network || 'mainnet'; + + // 1) Get quote for optimal amounts + const quote = await getSundaeswapAmmLiquidityQuote( + networkToUse, + poolAddress, + baseToken, + quoteToken, + baseTokenAmount, + quoteTokenAmount, + slippagePct, + ); + + // 2) Prepare Sundaeswap + const sundaeswap = await Sundaeswap.getInstance(networkToUse); + const { cardano } = sundaeswap; + + // 3) Ensure wallet key + const privateKey = await cardano.getWalletFromAddress(walletAddress); + if (!privateKey) { + throw fastify.httpErrors.badRequest('Wallet not found'); + } + cardano.lucidInstance.selectWalletFromPrivateKey(privateKey); + + const depositArgs: IDepositConfigArgs = { + suppliedAssets: [ + new AssetAmount(quote.rawBaseTokenAmount, quote.poolData.assetA), + new AssetAmount(quote.rawQuoteTokenAmount, quote.poolData.assetB), + ] as [AssetAmount, AssetAmount], // Explicit tuple + pool: quote.poolData, + orderAddresses: { + DestinationAddress: { + address: walletAddress, + datum: { + type: EDatumType.NONE, + }, + }, + }, + }; + + const txBuilder = new TxBuilderLucidV3( + sundaeswap.cardano.lucidInstance, + new DatumBuilderLucidV3(network as TSupportedNetworks), + ); + + const result = await txBuilder.deposit({ ...depositArgs }); + const builtTx = await result.build(); + const { submit } = await builtTx.sign(); + const txHash = await submit(); + + return { + signature: txHash, + fee: builtTx.builtTx.fee, + baseTokenAmountAdded: quote.baseTokenAmount, + quoteTokenAmountAdded: quote.quoteTokenAmount, + }; +} + +export const addLiquidityRoute: FastifyPluginAsync = async (fastify) => { + await fastify.register(require('@fastify/sensible')); + fastify.post<{ + Body: AddLiquidityRequestType; + Reply: AddLiquidityResponseType; + }>( + '/add-liquidity', + { + schema: { + description: 'Add liquidity to a Sundaeswap pool', + tags: ['sundaeswap/amm'], + body: { + ...AddLiquidityRequest, + properties: { + ...AddLiquidityRequest.properties, + network: { type: 'string', default: 'mainnet' }, + walletAddress: { type: 'string', examples: ['addr'] }, + poolAddress: { type: 'string', examples: [''] }, + baseToken: { type: 'string', examples: ['ADA'] }, + quoteToken: { type: 'string', examples: ['SUNDAE'] }, + baseTokenAmount: { type: 'number', examples: [0.001] }, + quoteTokenAmount: { type: 'number', examples: [2.5] }, + slippagePct: { type: 'number', examples: [1] }, + }, + }, + response: { 200: AddLiquidityResponse }, + }, + }, + async (request) => { + try { + const { + network, + poolAddress: reqPool, + baseToken, + quoteToken, + baseTokenAmount, + quoteTokenAmount, + slippagePct, + walletAddress: reqWallet, + } = request.body; + + if ( + !baseToken || + !quoteToken || + !baseTokenAmount || + !quoteTokenAmount + ) { + throw fastify.httpErrors.badRequest('Missing parameters'); + } + + const sundaeswap = await Sundaeswap.getInstance(network || 'mainnet'); + const walletAddr = + reqWallet || (await sundaeswap.cardano.getFirstWalletAddress()); + if (!walletAddr) { + throw fastify.httpErrors.badRequest('No wallet address'); + } + + const poolAddr = + reqPool || + (await sundaeswap.findDefaultPool(baseToken, quoteToken, 'amm')); + if (!poolAddr) { + throw fastify.httpErrors.notFound( + `Pool not found for ${baseToken}-${quoteToken}`, + ); + } + + return await addLiquidity( + fastify, + network || 'mainnet', + walletAddr, + poolAddr, + baseToken, + quoteToken, + baseTokenAmount, + quoteTokenAmount, + slippagePct !== undefined ? slippagePct / 100 : undefined, // convert % to decimal + ); + } catch (e: any) { + logger.error(e); + if (e.statusCode) throw e; + throw fastify.httpErrors.internalServerError('Failed to add liquidity'); + } + }, + ); +}; + +export default addLiquidityRoute; diff --git a/src/connectors/sundaeswap/amm-routes/executeSwap.ts b/src/connectors/sundaeswap/amm-routes/executeSwap.ts new file mode 100644 index 0000000000..8ececa3ae0 --- /dev/null +++ b/src/connectors/sundaeswap/amm-routes/executeSwap.ts @@ -0,0 +1,264 @@ +import { FastifyPluginAsync } from 'fastify'; +import { + ExecuteSwapRequestType, + ExecuteSwapRequest, + ExecuteSwapResponseType, + ExecuteSwapResponse, +} from '../../../schemas/swap-schema'; +import { logger } from '../../../services/logger'; +import { Sundaeswap } from '../sundaeswap'; +import { formatTokenAmount } from '../sundaeswap.utils'; +import { + EDatumType, + ESwapType, + ISwapConfigArgs, + TSupportedNetworks, +} from '@aiquant/sundaeswap-core'; +import { + DatumBuilderLucidV3, + TxBuilderLucidV3, +} from '@aiquant/sundaeswap-core/lucid'; +import { AssetAmount, IAssetAmountMetadata } from '@sundaeswap/asset'; +import { BigNumber } from 'ethers'; +import { CardanoTokenInfo } from '../../../chains/cardano/cardano'; + +export const executeSwapRoute: FastifyPluginAsync = async (fastify) => { + await fastify.register(require('@fastify/sensible')); + + fastify.post<{ + Body: ExecuteSwapRequestType; + Reply: ExecuteSwapResponseType; + }>( + '/execute-swap', + { + schema: { + description: 'Execute a swap on Sundaeswap AMM (Cardano)', + tags: ['sundaeswap/amm'], + body: { + ...ExecuteSwapRequest, + properties: { + ...ExecuteSwapRequest.properties, + network: { type: 'string', default: 'mainnet' }, + walletAddress: { type: 'string' }, + baseToken: { type: 'string', examples: ['ADA'] }, + quoteToken: { type: 'string', examples: ['SUNDAE'] }, + amount: { type: 'number', examples: [100] }, // always quote amount + side: { type: 'string', enum: ['BUY', 'SELL'] }, + poolAddress: { type: 'string' }, + slippagePct: { type: 'number', examples: [1] }, + }, + }, + response: { 200: ExecuteSwapResponse }, + }, + }, + async (request) => { + try { + const { + network, + walletAddress: reqAddr, + baseToken, + quoteToken, + amount, + side, + slippagePct = 1, + poolAddress: reqPool, + } = request.body; + + const net = (network || 'mainnet') as TSupportedNetworks; + const sundaeswap = await Sundaeswap.getInstance(net); + + // determine wallet + const walletAddr = + reqAddr || (await sundaeswap.cardano.getFirstWalletAddress()); + if (!walletAddr) { + throw fastify.httpErrors.badRequest('No wallet address provided'); + } + const wallet = + await sundaeswap.cardano.getWalletFromAddress(walletAddr); + sundaeswap.cardano.lucidInstance.selectWalletFromPrivateKey(wallet); + + // determine pool + const poolAddr = + reqPool || + (await sundaeswap.findDefaultPool(baseToken, quoteToken, 'amm')); + if (!poolAddr) { + throw fastify.httpErrors.notFound( + `Pool not found for ${baseToken}-${quoteToken}`, + ); + } + const poolData = await sundaeswap.getPoolData(poolAddr); + + // Get token objects + const baseTokenObj = sundaeswap.cardano.getTokenBySymbol(baseToken); + const quoteTokenObj = sundaeswap.cardano.getTokenBySymbol(quoteToken); + + if (!baseTokenObj || !quoteTokenObj) { + throw fastify.httpErrors.badRequest('Token not found'); + } + + // Get pool assets and reserves + const assetA = poolData.assetA.assetId.trim(); + const assetB = poolData.assetB.assetId.trim(); + const reserveA = BigInt(poolData.liquidity.aReserve); + const reserveB = BigInt(poolData.liquidity.bReserve); + + // Determine which token corresponds to which asset in the pool + const baseAssetId = + baseTokenObj.address || + `${baseTokenObj.policyId}.${baseTokenObj.assetName}`; + const quoteAssetId = + quoteTokenObj.address || + `${quoteTokenObj.policyId}.${quoteTokenObj.assetName}`; + + let baseReserve: bigint; + let quoteReserve: bigint; + + // Match tokens to pool reserves + if (baseAssetId.trim() === assetA) { + baseReserve = reserveA; + quoteReserve = reserveB; + } else if (baseAssetId.trim() === assetB) { + baseReserve = reserveB; + quoteReserve = reserveA; + } else { + throw fastify.httpErrors.badRequest( + `Base token ${baseAssetId} not found in pool`, + ); + } + + // Validate quote token is in the pool + const quoteInPool = + quoteAssetId.trim() === assetA || quoteAssetId.trim() === assetB; + if (!quoteInPool) { + throw fastify.httpErrors.badRequest( + `Quote token ${quoteAssetId} not found in pool`, + ); + } + + // Convert amount to smallest units and calculate swap amounts + const fee = poolData.currentFee; // e.g., 0.005 for 0.5% + let inputAmount: bigint; + let outputAmount: bigint; + let inputTokenObj: CardanoTokenInfo; + let outputTokenObj: CardanoTokenInfo; + + if (side === 'SELL') { + // SELL: spending `amount` of quoteToken, receiving baseToken + inputTokenObj = quoteTokenObj; + outputTokenObj = baseTokenObj; + inputAmount = BigInt( + Math.floor(amount * 10 ** quoteTokenObj.decimals), + ); + + // Apply AMM formula for sell (exactIn): dy = (y * dx * (1 - fee)) / (x + dx * (1 - fee)) + const inputAfterFee = + (inputAmount * BigInt(Math.floor((1 - fee) * 10000))) / 10000n; + outputAmount = + (baseReserve * inputAfterFee) / (quoteReserve + inputAfterFee); + } else { + // BUY: wanting to receive `amount` of quoteToken, paying baseToken + inputTokenObj = baseTokenObj; + outputTokenObj = quoteTokenObj; + outputAmount = BigInt( + Math.floor(amount * 10 ** quoteTokenObj.decimals), + ); + + // Check if we have enough liquidity + if (outputAmount >= quoteReserve) { + throw fastify.httpErrors.badRequest( + 'Insufficient liquidity: requested amount exceeds available reserves', + ); + } + + // Apply AMM formula for buy (exactOut): dx = (x * dy) / ((y - dy) * (1 - fee)) + const numerator = baseReserve * outputAmount; + const denominator = + ((quoteReserve - outputAmount) * + BigInt(Math.floor((1 - fee) * 10000))) / + 10000n; + inputAmount = numerator / denominator; + } + + // Prepare asset metadata for the input token + const asset: IAssetAmountMetadata = + inputTokenObj.symbol === 'ADA' + ? { + assetId: 'ada.lovelace', + decimals: 6, + } + : { + assetId: + inputTokenObj.address || + `${inputTokenObj.policyId}.${inputTokenObj.assetName}`, + decimals: inputTokenObj.decimals, + }; + + // Prepare suppliedAsset + let suppliedAsset: AssetAmount = new AssetAmount(inputAmount, asset); + + // Build swap transaction + const args: ISwapConfigArgs = { + swapType: { type: ESwapType.MARKET, slippage: slippagePct / 100 }, + pool: poolData, + orderAddresses: { + DestinationAddress: { + address: walletAddr, + datum: { type: EDatumType.NONE }, + }, + }, + suppliedAsset, + }; + + const txBuilder = new TxBuilderLucidV3( + sundaeswap.cardano.lucidInstance, + new DatumBuilderLucidV3(net), + ); + const swapResult = await txBuilder.swap({ ...args }); + + const builtTx = await swapResult.build(); + const { submit } = await builtTx.sign(); + + const txHash = await submit(); + + // Format response values - convert back to human readable amounts + const inputAmountHuman = + Number(inputAmount) / 10 ** inputTokenObj.decimals; + const outputAmountHuman = + Number(outputAmount) / 10 ** outputTokenObj.decimals; + + // Calculate balance changes correctly + let baseTokenBalanceChange: number; + let quoteTokenBalanceChange: number; + + if (side === 'BUY') { + // BUY: spending baseToken to get quoteToken + // baseToken decreases (negative), quoteToken increases (positive) + baseTokenBalanceChange = -inputAmountHuman; // spending baseToken + quoteTokenBalanceChange = outputAmountHuman; // receiving quoteToken + } else { + // SELL: spending quoteToken to get baseToken + // quoteToken decreases (negative), baseToken increases (positive) + quoteTokenBalanceChange = -inputAmountHuman; // spending quoteToken + baseTokenBalanceChange = outputAmountHuman; // receiving baseToken + } + + return { + signature: txHash, + totalInputSwapped: inputAmountHuman, + totalOutputSwapped: outputAmountHuman, + fee: builtTx.builtTx.fee, + baseTokenBalanceChange, + quoteTokenBalanceChange, + }; + } catch (err: any) { + logger.error('Swap failed:', err); + if (err.statusCode) throw err; + throw fastify.httpErrors.internalServerError( + `Swap execution error: ${err.message}`, + ); + } + }, + ); +}; + +export default executeSwapRoute; diff --git a/src/connectors/sundaeswap/amm-routes/poolInfo.ts b/src/connectors/sundaeswap/amm-routes/poolInfo.ts new file mode 100644 index 0000000000..b50268fc49 --- /dev/null +++ b/src/connectors/sundaeswap/amm-routes/poolInfo.ts @@ -0,0 +1,82 @@ +import { FastifyPluginAsync } from 'fastify'; + +import { + GetPoolInfoRequestType, + GetPoolInfoRequest, + PoolInfo, + PoolInfoSchema, +} from '../../../schemas/amm-schema'; +import { logger } from '../../../services/logger'; +import { Sundaeswap } from '../sundaeswap'; + +export const ammPoolInfoRoute: FastifyPluginAsync = async (fastify) => { + fastify.get<{ + Querystring: GetPoolInfoRequestType; + Reply: Record; + }>( + '/pool-info', + { + schema: { + description: 'Get AMM pool information from Sundaeswap', + tags: ['sundaeswap/amm'], + querystring: { + ...GetPoolInfoRequest, + properties: { + network: { type: 'string', examples: ['mainnet'] }, + poolIdent: { + type: 'string', + examples: [ + '2f36866691fa75a9aab66dec99f7cc2d297ca09e34d9ce68cde04773', + ], + }, + baseToken: { type: 'string', examples: ['ADA'] }, + quoteToken: { type: 'string', examples: ['SUNDAE'] }, + }, + }, + response: { + 200: PoolInfoSchema, + }, + }, + }, + async (request): Promise => { + try { + const { poolAddress: poolIdent, baseToken, quoteToken } = request.query; + const network = request.query.network || 'mainnet'; + + const sundaeswap = await Sundaeswap.getInstance(network); + + // Check if either poolIdent or both baseToken and quoteToken are provided + if (!poolIdent && (!baseToken || !quoteToken)) { + throw fastify.httpErrors.badRequest( + 'Either poolIdent or both baseToken and quoteToken must be provided', + ); + } + + let poolIdentToUse = poolIdent; + + // If no pool address provided, find default pool using base and quote tokens + if (!poolIdentToUse) { + poolIdentToUse = await sundaeswap.findDefaultPool( + baseToken, + quoteToken, + 'amm', + ); + if (!poolIdentToUse) { + throw fastify.httpErrors.notFound( + `No AMM pool found for pair ${baseToken}-${quoteToken}`, + ); + } + } + + const poolInfo = await sundaeswap.getAmmPoolInfo(poolIdentToUse); + if (!poolInfo) throw fastify.httpErrors.notFound('Pool not found'); + return poolInfo; + } catch (e) { + logger.error(e); + throw fastify.httpErrors.internalServerError( + 'Failed to fetch pool info', + ); + } + }, + ); +}; diff --git a/src/connectors/sundaeswap/amm-routes/quoteLiquidity.ts b/src/connectors/sundaeswap/amm-routes/quoteLiquidity.ts new file mode 100644 index 0000000000..8cc935c780 --- /dev/null +++ b/src/connectors/sundaeswap/amm-routes/quoteLiquidity.ts @@ -0,0 +1,246 @@ +import { BigNumber } from 'ethers'; +import { FastifyPluginAsync } from 'fastify'; +import { Cardano, CardanoTokenInfo } from '../../../chains/cardano/cardano'; +import { + QuoteLiquidityRequestType, + QuoteLiquidityRequest, + QuoteLiquidityResponseType, + QuoteLiquidityResponse, +} from '../../../schemas/amm-schema'; +import { logger } from '../../../services/logger'; +import { Sundaeswap } from '../sundaeswap'; +import { formatTokenAmount } from '../sundaeswap.utils'; +import { IPoolData } from '@aiquant/sundaeswap-core'; + +export async function getSundaeswapAmmLiquidityQuote( + network: string, + poolAddress?: string, + baseToken?: string, + quoteToken?: string, + baseTokenAmount?: number, + quoteTokenAmount?: number, + _slippagePct?: number, +): Promise<{ + baseLimited: boolean; + baseTokenAmount: number; + quoteTokenAmount: number; + baseTokenAmountMax: number; + quoteTokenAmountMax: number; + baseTokenObj: CardanoTokenInfo; + quoteTokenObj: CardanoTokenInfo; + poolAddress?: string; + rawBaseTokenAmount: string; + rawQuoteTokenAmount: string; + poolData: IPoolData; +}> { + const networkToUse = network || 'mainnet'; + + if (!baseToken || !quoteToken) { + throw new Error('Base token and quote token are required'); + } + if (baseTokenAmount === undefined && quoteTokenAmount === undefined) { + throw new Error('At least one token amount must be provided'); + } + + const sundaeswap = await Sundaeswap.getInstance(networkToUse); + + const baseTokenObj = sundaeswap.cardano.getTokenBySymbol(baseToken); + const quoteTokenObj = sundaeswap.cardano.getTokenBySymbol(quoteToken); + if (!baseTokenObj || !quoteTokenObj) { + throw new Error( + `Token not found: ${!baseTokenObj ? baseToken : quoteToken}`, + ); + } + + let poolAddressToUse = poolAddress; + let existingPool = true; + if (!poolAddressToUse) { + poolAddressToUse = await sundaeswap.findDefaultPool( + baseToken, + quoteToken, + 'amm', + ); + if (!poolAddressToUse) { + existingPool = false; + logger.info( + `No existing pool found for ${baseToken}-${quoteToken}, providing theoretical quote`, + ); + } + } + + let baseTokenAmountOptimal = baseTokenAmount!; + let quoteTokenAmountOptimal = quoteTokenAmount!; + let baseLimited = false; + let poolState: IPoolData; + if (existingPool) { + // Get pool state from Sundaeswap (adjust method name based on their SDK) + poolState = await sundaeswap.getPoolData(poolAddressToUse); + if (!poolState) { + throw new Error(`Unable to load pool ${poolAddressToUse}`); + } + + // ── 2) Pull reserves as bigints ──────────────────────── + // Adjust property names based on Sundaeswap's pool structure + const baseReserve: bigint = poolState.liquidity.aReserve || BigInt(0); + const quoteReserve: bigint = poolState.liquidity.bReserve || BigInt(0); + + // ── 3) Convert user inputs into raw bigints ─────────── + const baseRaw = baseTokenAmount + ? BigInt( + Math.floor(baseTokenAmount * 10 ** baseTokenObj.decimals).toString(), + ) + : null; + const quoteRaw = quoteTokenAmount + ? BigInt( + Math.floor( + quoteTokenAmount * 10 ** quoteTokenObj.decimals, + ).toString(), + ) + : null; + + // ── 4) Compute the "optimal" opposite amount ─────────── + if (baseRaw !== null && quoteRaw !== null) { + // both sides provided → pick the limiting one + const quoteOptimal = (baseRaw * quoteReserve) / baseReserve; + if (quoteOptimal <= quoteRaw) { + baseLimited = true; + quoteTokenAmountOptimal = Number( + formatTokenAmount(quoteOptimal.toString(), quoteTokenObj.decimals), + ); + } else { + baseLimited = false; + const baseOptimal = (quoteRaw * baseReserve) / quoteReserve; + baseTokenAmountOptimal = Number( + formatTokenAmount(baseOptimal.toString(), baseTokenObj.decimals), + ); + } + } else if (baseRaw !== null) { + // only base provided + const quoteOptimal = + baseReserve === BigInt(0) + ? BigInt(0) + : (baseRaw * quoteReserve) / baseReserve; + quoteTokenAmountOptimal = Number( + formatTokenAmount(quoteOptimal.toString(), quoteTokenObj.decimals), + ); + baseLimited = true; + } else if (quoteRaw !== null) { + // only quote provided + const baseOptimal = + quoteReserve === BigInt(0) + ? BigInt(0) + : (quoteRaw * baseReserve) / quoteReserve; + baseTokenAmountOptimal = Number( + formatTokenAmount(baseOptimal.toString(), baseTokenObj.decimals), + ); + baseLimited = false; + } + } else { + // new pool → must supply both + if (baseTokenAmount == null || quoteTokenAmount == null) { + throw new Error( + 'For a new pool, you must supply both baseTokenAmount and quoteTokenAmount', + ); + } + baseLimited = false; // arbitrary; both get used + } + + // ── 5) Convert back into Ethers BigNumber for any on‐chain tx ─── + const rawBaseTokenAmount = Math.floor( + baseTokenAmountOptimal * 10 ** baseTokenObj.decimals, + ).toString(); + + const rawQuoteTokenAmount = Math.floor( + quoteTokenAmountOptimal * 10 ** quoteTokenObj.decimals, + ).toString(); + + return { + baseLimited, + baseTokenAmount: baseTokenAmountOptimal, + quoteTokenAmount: quoteTokenAmountOptimal, + baseTokenAmountMax: baseTokenAmount ?? baseTokenAmountOptimal, + quoteTokenAmountMax: quoteTokenAmount ?? quoteTokenAmountOptimal, + baseTokenObj, + quoteTokenObj, + poolAddress: poolAddressToUse, + rawBaseTokenAmount, + rawQuoteTokenAmount, + poolData: poolState, + }; +} + +export const quoteLiquidityRoute: FastifyPluginAsync = async (fastify) => { + await fastify.register(require('@fastify/sensible')); + fastify.get<{ + Querystring: QuoteLiquidityRequestType; + Reply: QuoteLiquidityResponseType; + }>( + '/quote-liquidity', + { + schema: { + description: 'Get liquidity quote for Sundaeswap', + tags: ['sundaeswap/amm'], + querystring: { + ...QuoteLiquidityRequest, + properties: { + ...QuoteLiquidityRequest.properties, + network: { type: 'string', default: 'mainnet' }, + poolAddress: { + type: 'string', + examples: [''], + }, + baseToken: { type: 'string', examples: ['ADA'] }, + quoteToken: { type: 'string', examples: ['SUNDAE'] }, + baseTokenAmount: { type: 'number', examples: [0.029314] }, + quoteTokenAmount: { type: 'number', examples: [1] }, + slippagePct: { type: 'number', examples: [1] }, + }, + }, + response: { + 200: QuoteLiquidityResponse, + }, + }, + }, + async (request) => { + try { + const { + network, + poolAddress, + baseToken, + quoteToken, + baseTokenAmount, + quoteTokenAmount, + slippagePct, + } = request.query; + + const quote = await getSundaeswapAmmLiquidityQuote( + network, + poolAddress, + baseToken, + quoteToken, + baseTokenAmount, + quoteTokenAmount, + slippagePct, + ); + + return { + baseLimited: quote.baseLimited, + baseTokenAmount: quote.baseTokenAmount, + quoteTokenAmount: quote.quoteTokenAmount, + baseTokenAmountMax: quote.baseTokenAmountMax, + quoteTokenAmountMax: quote.quoteTokenAmountMax, + }; + } catch (e) { + logger.error(e); + if (e.statusCode) { + throw e; + } + throw fastify.httpErrors.internalServerError( + 'Failed to get liquidity quote', + ); + } + }, + ); +}; + +export default quoteLiquidityRoute; diff --git a/src/connectors/sundaeswap/amm-routes/quoteSwap.ts b/src/connectors/sundaeswap/amm-routes/quoteSwap.ts new file mode 100644 index 0000000000..cf2bc89b69 --- /dev/null +++ b/src/connectors/sundaeswap/amm-routes/quoteSwap.ts @@ -0,0 +1,415 @@ +import { BigNumber } from 'ethers'; +import { FastifyPluginAsync, FastifyInstance } from 'fastify'; +import { CardanoTokenInfo } from '../../../chains/cardano/cardano'; +import { + GetSwapQuoteResponseType, + GetSwapQuoteResponse, + GetSwapQuoteRequestType, + GetSwapQuoteRequest, +} from '../../../schemas/swap-schema'; +import { logger } from '../../../services/logger'; +import { Sundaeswap } from '../sundaeswap'; +import { formatTokenAmount } from '../sundaeswap.utils'; + +export async function quoteAmmSwap( + sundaeswap: Sundaeswap, + poolIdent: string, + baseToken: CardanoTokenInfo, + quoteToken: CardanoTokenInfo, + amount: number, // now always refers to quote‐token units + side: 'BUY' | 'SELL', + slippagePct: number = 1, // Default to 1% if not provided +): Promise { + // BUY: you want to RECEIVE `amount` of quoteToken, paying baseToken + // SELL: you want to SPEND `amount` of quoteToken, receiving baseToken + const poolData = await sundaeswap.getPoolData(poolIdent); + + // Get pool assets and reserves + const assetA = poolData.assetA.assetId.trim(); + const assetB = poolData.assetB.assetId.trim(); + const reserveA = BigInt(poolData.liquidity.aReserve); + const reserveB = BigInt(poolData.liquidity.bReserve); + + // Determine which token corresponds to which asset in the pool + const baseAssetId = + baseToken.address || `${baseToken.policyId}.${baseToken.assetName}`; + const quoteAssetId = + quoteToken.address || `${quoteToken.policyId}.${quoteToken.assetName}`; + + let baseReserve: bigint; + let quoteReserve: bigint; + + // Match tokens to pool reserves + if (baseAssetId.trim() === assetA) { + baseReserve = reserveA; + quoteReserve = reserveB; + } else if (baseAssetId.trim() === assetB) { + baseReserve = reserveB; + quoteReserve = reserveA; + } else { + throw new Error(`Base token ${baseAssetId} not found in pool`); + } + + // Validate quote token is in the pool + const quoteInPool = + quoteAssetId.trim() === assetA || quoteAssetId.trim() === assetB; + if (!quoteInPool) { + throw new Error(`Quote token ${quoteAssetId} not found in pool`); + } + + // Convert amount to smallest units + const fee = poolData.currentFee; // e.g., 0.005 for 0.5% + let inputAmount: bigint; + let outputAmount: bigint; + + if (side === 'SELL') { + // SELL: spending `amount` of quoteToken, receiving baseToken + // This is exactIn scenario + inputAmount = BigInt(Math.floor(amount * 10 ** quoteToken.decimals)); + + // Apply AMM formula for sell (exactIn): dy = (y * dx * (1 - fee)) / (x + dx * (1 - fee)) + const inputAfterFee = + (inputAmount * BigInt(Math.floor((1 - fee) * 10000))) / 10000n; + outputAmount = + (baseReserve * inputAfterFee) / (quoteReserve + inputAfterFee); + } else { + // BUY: wanting to receive `amount` of quoteToken, paying baseToken + // This is exactOut scenario + outputAmount = BigInt(Math.floor(amount * 10 ** quoteToken.decimals)); + + // Check if we have enough liquidity + if (outputAmount >= quoteReserve) { + throw new Error( + 'Insufficient liquidity: requested amount exceeds available reserves', + ); + } + + // Apply AMM formula for buy (exactOut): dx = (x * dy) / ((y - dy) * (1 - fee)) + const numerator = baseReserve * outputAmount; + const denominator = + ((quoteReserve - outputAmount) * BigInt(Math.floor((1 - fee) * 10000))) / + 10000n; + inputAmount = numerator / denominator; + } + + // Calculate slippage protection amounts + const slippageTolerance = slippagePct / 100; + const slippageMultiplier = BigInt( + Math.floor((1 - slippageTolerance) * 10000), + ); + const slippageDenominator = 10000n; + + const minAmountOut = + side === 'SELL' + ? (outputAmount * slippageMultiplier) / slippageDenominator + : outputAmount; + + const maxAmountIn = + side === 'BUY' + ? (inputAmount * + (slippageDenominator + + BigInt(Math.floor(slippageTolerance * 10000)))) / + slippageDenominator + : inputAmount; + + // Calculate price impact + const midPrice = + Number(baseReserve) / + 10 ** baseToken.decimals / + (Number(quoteReserve) / 10 ** quoteToken.decimals); + + const executionPrice = + Number(inputAmount) / + 10 ** baseToken.decimals / + (Number(outputAmount) / 10 ** quoteToken.decimals); + + const priceImpact = Math.abs((executionPrice - midPrice) / midPrice); + + // Determine which token is input and output based on side + const inputToken = side === 'SELL' ? quoteToken : baseToken; + const outputToken = side === 'SELL' ? baseToken : quoteToken; + + // Convert amounts to human-readable format + const estimatedIn = formatTokenAmount(inputAmount, inputToken.decimals); + const estimatedOut = formatTokenAmount(outputAmount, outputToken.decimals); + const minOutHuman = formatTokenAmount(minAmountOut, outputToken.decimals); + const maxInHuman = formatTokenAmount(maxAmountIn, inputToken.decimals); + + return { + poolIdent, + estimatedAmountIn: estimatedIn, + estimatedAmountOut: estimatedOut, + minAmountOut: minOutHuman, + maxAmountIn: maxInHuman, + priceImpact, + inputToken, + outputToken, + rawAmountIn: inputAmount.toString(), + rawAmountOut: outputAmount.toString(), + rawMinAmountOut: minAmountOut.toString(), + rawMaxAmountIn: maxAmountIn.toString(), + slippagePct, + pathAddresses: [ + inputToken.address || `${inputToken.policyId}.${inputToken.assetName}`, + outputToken.address || `${outputToken.policyId}.${outputToken.assetName}`, + ], + }; +} + +export async function getSundaeswapAmmQuote( + _fastify: FastifyInstance, + network: string, + poolIdent: string, + baseToken: string, + quoteToken: string, + amount: number, + side: 'BUY' | 'SELL', + slippagePct: number = 1, +): Promise<{ + quote: any; + sundaeswap: any; + cardano: any; + baseTokenObj: any; + quoteTokenObj: any; +}> { + // Get instances + const sundaeswap = await Sundaeswap.getInstance(network); + + // Resolve tokens + const baseTokenObj = sundaeswap.cardano.getTokenBySymbol(baseToken); + const quoteTokenObj = sundaeswap.cardano.getTokenBySymbol(quoteToken); + + if (!baseTokenObj) { + logger.error(`Base token not found: ${baseToken}`); + throw new Error(`Base token not found: ${baseToken}`); + } + + if (!quoteTokenObj) { + logger.error(`Quote token not found: ${quoteToken}`); + throw new Error(`Quote token not found: ${quoteToken}`); + } + + logger.info( + `Base token: ${baseTokenObj.symbol}, address=${baseTokenObj.address}, decimals=${baseTokenObj.decimals}`, + ); + logger.info( + `Quote token: ${quoteTokenObj.symbol}, address=${quoteTokenObj.address}, decimals=${quoteTokenObj.decimals}`, + ); + + // Get the quote with slippage percentage + const quote = await quoteAmmSwap( + sundaeswap, + poolIdent, + baseTokenObj, + quoteTokenObj, + amount, + side as 'BUY' | 'SELL', + slippagePct, + ); + + if (!quote) { + throw new Error('Failed to get swap quote'); + } + + return { + quote, + sundaeswap, + cardano: sundaeswap.cardano, + baseTokenObj, + quoteTokenObj, + }; +} + +// Fixed formatSwapQuote function with corrected balance changes +async function formatSwapQuote( + fastify: FastifyInstance, + network: string, + poolIdent: string, + baseToken: string, + quoteToken: string, + amount: number, + side: 'BUY' | 'SELL', + slippagePct: number = 1, +): Promise { + logger.info( + `formatSwapQuote: poolIdent=${poolIdent}, baseToken=${baseToken}, quoteToken=${quoteToken}, amount=${amount}, side=${side}, slippagePct=${slippagePct}, network=${network}`, + ); + + try { + // Use the extracted quote function with slippage percentage + const { quote, sundaeswap, cardano, baseTokenObj, quoteTokenObj } = + await getSundaeswapAmmQuote( + fastify, + network, + poolIdent, + baseToken, + quoteToken, + amount, + side, + slippagePct, + ); + + logger.info( + `Quote result: estimatedAmountIn=${quote.estimatedAmountIn}, estimatedAmountOut=${quote.estimatedAmountOut}, slippagePct=${quote.slippagePct}`, + ); + + // Calculate balance changes based on which tokens are being swapped + // The quote object tells us which token is input and which is output + let baseTokenBalanceChange: number; + let quoteTokenBalanceChange: number; + + if (side === 'SELL') { + // SELL: spending quoteToken, receiving baseToken + // Input token is quoteToken, output token is baseToken + baseTokenBalanceChange = quote.estimatedAmountOut; // positive (receiving) + quoteTokenBalanceChange = -quote.estimatedAmountIn; // negative (spending) + } else { + // BUY: spending baseToken, receiving quoteToken + // Input token is baseToken, output token is quoteToken + baseTokenBalanceChange = -quote.estimatedAmountIn; // negative (spending) + quoteTokenBalanceChange = quote.estimatedAmountOut; // positive (receiving) + } + + logger.info( + `Balance changes: baseTokenBalanceChange=${baseTokenBalanceChange}, quoteTokenBalanceChange=${quoteTokenBalanceChange}`, + ); + + // Calculate price based on side + // For SELL: price = quote received / base sold + // For BUY: price = quote needed / base received + const price = + side === 'SELL' + ? quote.estimatedAmountOut / quote.estimatedAmountIn + : quote.estimatedAmountIn / quote.estimatedAmountOut; + + return { + estimatedAmountIn: quote.estimatedAmountIn, + estimatedAmountOut: quote.estimatedAmountOut, + minAmountOut: quote.minAmountOut, + maxAmountIn: quote.maxAmountIn, + baseTokenBalanceChange, + quoteTokenBalanceChange, + price, + gasPrice: 0, + gasLimit: 0, + gasCost: 0, + }; + } catch (error) { + logger.error(`Error formatting swap quote: ${error.message}`); + if (error.stack) { + logger.debug(`Stack trace: ${error.stack}`); + } + throw error; + } +} + +export const quoteSwapRoute: FastifyPluginAsync = async (fastify) => { + // Import the httpErrors plugin to ensure it's available + await fastify.register(require('@fastify/sensible')); + + fastify.get<{ + Querystring: GetSwapQuoteRequestType; + Reply: GetSwapQuoteResponseType; + }>( + '/quote-swap', + { + schema: { + description: 'Get swap quote for Sundaeswap AMM', + tags: ['sundaeswap/amm'], + querystring: { + ...GetSwapQuoteRequest, + properties: { + ...GetSwapQuoteRequest.properties, + network: { type: 'string', default: 'mainnet' }, + baseToken: { type: 'string', examples: ['ADA'] }, + quoteToken: { type: 'string', examples: ['SUNDAE'] }, + amount: { type: 'number', examples: [0.001] }, + side: { type: 'string', enum: ['BUY', 'SELL'], examples: ['SELL'] }, + poolIdent: { type: 'string', examples: [''] }, + slippagePct: { type: 'number', examples: [1] }, + }, + }, + response: { + 200: { + properties: { + ...GetSwapQuoteResponse.properties, + }, + }, + }, + }, + }, + async (request) => { + try { + const { + network, + poolAddress: requestedpoolIdent, + baseToken, + quoteToken, + amount, + side, + slippagePct, + } = request.query; + + const networkToUse = network || 'mainnet'; + const slippageToUse = slippagePct || 1; // Default to 1% if not provided + + const sundaeswap = await Sundaeswap.getInstance(networkToUse); + let poolIdent = requestedpoolIdent; + + if (!poolIdent) { + // Look up the pool from configuration pools dictionary + poolIdent = await sundaeswap.findDefaultPool( + baseToken, + quoteToken, + 'amm', + ); + + if (!poolIdent) { + throw fastify.httpErrors.notFound( + `No AMM pool found for pair ${baseToken}-${quoteToken}`, + ); + } + } + + return await formatSwapQuote( + fastify, + networkToUse, + poolIdent, + baseToken, + quoteToken, + amount, + side as 'BUY' | 'SELL', + slippageToUse, + ); + } catch (e) { + logger.error(`Error in quote-swap route: ${e.message}`); + + // If it's already a Fastify HTTP error, re-throw it + if (e.statusCode) { + throw e; + } + + // Check for specific error types + if (e.message?.includes('Insufficient liquidity')) { + throw fastify.httpErrors.badRequest(e.message); + } + if ( + e.message?.includes('Pool not found') || + e.message?.includes('No AMM pool found') + ) { + throw fastify.httpErrors.notFound(e.message); + } + if (e.message?.includes('token not found')) { + throw fastify.httpErrors.badRequest(e.message); + } + + // Default to internal server error with the actual error message + throw fastify.httpErrors.internalServerError( + `Error getting swap quote: ${e.message || 'Unknown error'}`, + ); + } + }, + ); +}; + +export default quoteSwapRoute; diff --git a/src/connectors/sundaeswap/amm-routes/removeLiquidity.ts b/src/connectors/sundaeswap/amm-routes/removeLiquidity.ts new file mode 100644 index 0000000000..2daf595cda --- /dev/null +++ b/src/connectors/sundaeswap/amm-routes/removeLiquidity.ts @@ -0,0 +1,216 @@ +import { BigNumber } from 'ethers'; +import { FastifyPluginAsync } from 'fastify'; + +import { + RemoveLiquidityRequestType, + RemoveLiquidityRequest, + RemoveLiquidityResponseType, + RemoveLiquidityResponse, +} from '../../../schemas/amm-schema'; +import { logger } from '../../../services/logger'; +import { Sundaeswap } from '../sundaeswap'; + +import { formatTokenAmount } from '../sundaeswap.utils'; +import { AssetAmount } from '@sundaeswap/asset'; +import { + EDatumType, + IWithdrawConfigArgs, + TSupportedNetworks, +} from '@aiquant/sundaeswap-core'; +import { + DatumBuilderLucidV3, + TxBuilderLucidV3, +} from '@aiquant/sundaeswap-core/lucid'; + +export const removeLiquidityRoute: FastifyPluginAsync = async (fastify) => { + fastify.post<{ + Body: RemoveLiquidityRequestType; + Reply: RemoveLiquidityResponseType; + }>( + '/remove-liquidity', + { + schema: { + description: 'Remove liquidity from a Sundaeswap pool', + tags: ['sundaeswap/amm'], + body: { + ...RemoveLiquidityRequest, + properties: { + ...RemoveLiquidityRequest.properties, + network: { type: 'string', default: 'mainnet' }, + walletAddress: { type: 'string', examples: [''] }, + poolAddress: { + type: 'string', + examples: [''], + }, + baseToken: { type: 'string', examples: ['ADA'] }, + quoteToken: { type: 'string', examples: ['SUNDAE'] }, + percentageToRemove: { type: 'number', examples: [100] }, + }, + }, + response: { + 200: RemoveLiquidityResponse, + }, + }, + }, + async (request) => { + try { + const { + network, + poolAddress: requestedPoolAddress, + baseToken, + quoteToken, + percentageToRemove, + walletAddress: requestedWalletAddress, + } = request.body; + + const networkToUse = network || 'mainnet'; + + // Validate essential parameters + if (!baseToken || !quoteToken || !percentageToRemove) { + throw fastify.httpErrors.badRequest('Missing required parameters'); + } + + if (percentageToRemove <= 0 || percentageToRemove > 100) { + throw fastify.httpErrors.badRequest( + 'Percentage to remove must be between 0 and 100', + ); + } + + // Get Sundaeswap and Cardano instances + const sundaeswap = await Sundaeswap.getInstance(networkToUse); + + // Get wallet address - either from request or first available + let walletAddress = requestedWalletAddress; + if (!walletAddress) { + walletAddress = await sundaeswap.cardano.getFirstWalletAddress(); + if (!walletAddress) { + throw fastify.httpErrors.badRequest( + 'No wallet address provided and no default wallet found', + ); + } + logger.info(`Using first available wallet address: ${walletAddress}`); + } + + // Resolve tokens + const baseTokenObj = sundaeswap.cardano.getTokenBySymbol(baseToken); + const quoteTokenObj = sundaeswap.cardano.getTokenBySymbol(quoteToken); + + if (!baseTokenObj || !quoteTokenObj) { + throw fastify.httpErrors.badRequest( + `Token not found: ${!baseTokenObj ? baseToken : quoteToken}`, + ); + } + + // Find pool address if not provided + let poolAddress = requestedPoolAddress; + if (!poolAddress) { + poolAddress = await sundaeswap.findDefaultPool( + baseToken, + quoteToken, + 'amm', + ); + + if (!poolAddress) { + throw fastify.httpErrors.notFound( + `No AMM pool found for pair ${baseToken}-${quoteToken}`, + ); + } + } + + const poolData = await sundaeswap.getPoolData(poolAddress); + const wallet = + await sundaeswap.cardano.getWalletFromAddress(walletAddress); + sundaeswap.cardano.lucidInstance.selectWalletFromPrivateKey(wallet); + const utxos = + await sundaeswap.cardano.lucidInstance.utxosAt(walletAddress); + + // 8) Calculate withdrawal amounts + const totalLpInWallet = sundaeswap.calculateAssetAmount( + utxos, + poolData.assetLP, + ); + + // Calculate how much LP token will be withdrawn based on the percentage + const withdrawalAmount = BigInt( + (BigInt(totalLpInWallet) * BigInt(percentageToRemove)) / BigInt(100), + ); + + // Define the LP Token to withdraw + const lpTokenAmount = new AssetAmount( + withdrawalAmount, + poolData.assetLP, + ); // Specify LP token amount + + // Build withdraw arguments (Added `pool` property) + const withdrawArgs: IWithdrawConfigArgs = { + suppliedLPAsset: lpTokenAmount, + pool: poolData, + orderAddresses: { + DestinationAddress: { + address: walletAddress, + datum: { + type: EDatumType.NONE, + }, + }, + }, + }; + + // Initialize transaction builder + const txBuilder = new TxBuilderLucidV3( + sundaeswap.cardano.lucidInstance, + new DatumBuilderLucidV3(network as TSupportedNetworks), + ); + + // Execute withdrawal transaction + const result = await txBuilder.withdraw({ ...withdrawArgs }); + + // Build the transaction + const builtTx = await result.build(); + // Sign and submit the transaction + const { submit, cbor } = await builtTx.sign(); + const txHash = await submit(); + + // Calculate the proportional amounts that will be received + const totalLpSupply = poolData.liquidity.lpTotal; // Total LP token supply + const lpTokensToWithdraw = withdrawalAmount; // Amount of LP tokens being withdrawn + + // Calculate the proportion of the pool being withdrawn + const withdrawalProportion = + Number(lpTokensToWithdraw) / Number(totalLpSupply); + + // Get current pool reserves + const baseTokenReserve = poolData.liquidity.aReserve; // Base token reserve in the pool + const quoteTokenReserve = poolData.liquidity.bReserve; // Quote token reserve in the pool + + // Calculate the amounts that will be received (proportional to LP tokens withdrawn) + const baseTokenAmountRemoved = Math.floor( + (Number(baseTokenReserve) * withdrawalProportion) / + baseTokenObj.decimals, + ); + + const quoteTokenAmountRemoved = Math.floor( + (Number(quoteTokenReserve) * withdrawalProportion) / + quoteTokenObj.decimals, + ); + + return { + signature: txHash, + fee: builtTx.builtTx.fee, + baseTokenAmountRemoved: baseTokenAmountRemoved, + quoteTokenAmountRemoved: quoteTokenAmountRemoved, + }; + } catch (e) { + logger.error(e); + if (e.statusCode) { + throw e; + } + + throw fastify.httpErrors.internalServerError( + 'Failed to remove liquidity', + ); + } + }, + ); +}; + +export default removeLiquidityRoute; diff --git a/src/connectors/sundaeswap/sundaeswap.config.ts b/src/connectors/sundaeswap/sundaeswap.config.ts new file mode 100644 index 0000000000..f0e2633499 --- /dev/null +++ b/src/connectors/sundaeswap/sundaeswap.config.ts @@ -0,0 +1,62 @@ +import { ConfigManagerV2 } from '../../services/config-manager-v2'; + +interface AvailableNetworks { + chain: string; + networks: Array; +} + +export namespace SundaeswapConfig { + // Supported networks for Sundaeswap + export const chain = 'cardano'; + export const networks = ['mainnet', 'preview']; + + export interface PoolsConfig { + [pairKey: string]: string; + } + + export interface NetworkConfig { + // Pool configurations + amm: PoolsConfig; + } + + export interface NetworkPoolsConfig { + // Dictionary of predefined pool addresses and settings by network + [network: string]: NetworkConfig; + } + + export interface RootConfig { + // Global configuration + allowedSlippage: string; + + // Network-specific configurations + networks: NetworkPoolsConfig; + + // Available networks + availableNetworks: Array; + } + + export const config: RootConfig = { + // Global configuration + allowedSlippage: ConfigManagerV2.getInstance().get( + 'sundaeswap.allowedSlippage', + ), + + // Network-specific pools + networks: ConfigManagerV2.getInstance().get('sundaeswap.networks'), + + availableNetworks: [ + { + chain: 'cardano', + networks: ['mainnet', 'preview'], + }, + ], + }; + + // Helper methods to get pools for a specific network + export const getNetworkPools = ( + network: string, + poolType: 'amm', + ): PoolsConfig => { + return config.networks[network]?.[poolType] || {}; + }; +} diff --git a/src/connectors/sundaeswap/sundaeswap.routes.ts b/src/connectors/sundaeswap/sundaeswap.routes.ts new file mode 100644 index 0000000000..e143533b5f --- /dev/null +++ b/src/connectors/sundaeswap/sundaeswap.routes.ts @@ -0,0 +1,33 @@ +import sensible from '@fastify/sensible'; +import type { FastifyPluginAsync } from 'fastify'; +import { ammPoolInfoRoute } from './amm-routes/poolInfo'; +import { quoteSwapRoute as ammQuoteSwapRoute } from './amm-routes/quoteSwap'; +import quoteLiquidityRoute from './amm-routes/quoteLiquidity'; +import { executeSwapRoute as ammExecuteSwapRoute } from './amm-routes/executeSwap'; +import { addLiquidityRoute as ammAddLiquidityRoute } from './amm-routes/addLiquidity'; +import { removeLiquidityRoute as ammRemoveLiquidityRoute } from './amm-routes/removeLiquidity'; + +// AMM routes including swap endpoints +const sundaeswapAmmRoutes: FastifyPluginAsync = async (fastify) => { + await fastify.register(sensible); + + await fastify.register(async (instance) => { + instance.addHook('onRoute', (routeOptions) => { + if (routeOptions.schema && routeOptions.schema.tags) { + routeOptions.schema.tags = ['sundaeswap/amm']; + } + }); + + await instance.register(ammPoolInfoRoute); + await instance.register(ammQuoteSwapRoute); + await instance.register(quoteLiquidityRoute); + await instance.register(ammExecuteSwapRoute); + await instance.register(ammAddLiquidityRoute); + await instance.register(ammRemoveLiquidityRoute); + }); +}; + +// Main export that combines all routes +export const sundaeswapRoutes = { + amm: sundaeswapAmmRoutes, +}; diff --git a/src/connectors/sundaeswap/sundaeswap.ts b/src/connectors/sundaeswap/sundaeswap.ts new file mode 100644 index 0000000000..88b1e5fd57 --- /dev/null +++ b/src/connectors/sundaeswap/sundaeswap.ts @@ -0,0 +1,190 @@ +// Monkey-patch Math.pow to support BigInt when both arguments are BigInts. +const originalMathPow = Math.pow; +Math.pow = function (base, exponent) { + if (typeof base === 'bigint' && typeof exponent === 'bigint') { + return base ** exponent; // Use BigInt exponentiation operator. + } + return originalMathPow(base, exponent); +}; + +import { Cardano, CardanoTokenInfo } from '../../chains/cardano/cardano'; +import { PrivateKey, UTxO } from '@aiquant/lucid-cardano'; +import { + IPoolDataAsset, + QueryProviderSundaeSwap, + TSupportedNetworks, +} from '@aiquant/sundaeswap-core'; + +import { + percentRegexp, + ConfigManagerV2, +} from '../../services/config-manager-v2'; +import { logger } from '../../services/logger'; + +import { SundaeswapConfig } from './sundaeswap.config'; +import { PoolInfo } from '../../schemas/amm-schema'; +import { isFractionString } from './sundaeswap.utils'; + +export class Sundaeswap { + private static _instances: { [name: string]: Sundaeswap }; + public cardano: Cardano; + public config: SundaeswapConfig.RootConfig; + private owner?: PrivateKey; + // Network information + private networkName: string; + + private constructor(network: string) { + this.networkName = network; + this.config = SundaeswapConfig.config as SundaeswapConfig.RootConfig; + this.cardano = null; + } + + /** Gets singleton instance of Sundaeswap */ + public static async getInstance(network: string): Promise { + if (!Sundaeswap._instances) { + Sundaeswap._instances = {}; + } + + if (!Sundaeswap._instances[network]) { + const instance = new Sundaeswap(network); + await instance.init(network); + Sundaeswap._instances[network] = instance; + } + + return Sundaeswap._instances[network]; + } + + /** Initializes Sundaeswap instance */ + private async init(network: string) { + try { + this.cardano = await Cardano.getInstance(network); + + // Load first wallet if available + const walletAddress = await this.cardano.getFirstWalletAddress(); + if (walletAddress) { + this.owner = await this.cardano.getWalletFromAddress(walletAddress); + } + + logger.info( + 'Sundaeswap initialized' + + (walletAddress ? ` with wallet: ${walletAddress}` : 'with no wallet'), + ); + } catch (error) { + logger.error('Sundaeswap initialization failed:', error); + throw error; + } + } + + /** + * Gets the allowed slippage percentage from config + * @returns Slippage as a percentage (e.g., 1.0 for 1%) + */ + getSlippagePct(): number { + const allowedSlippage = SundaeswapConfig.config.allowedSlippage; + const nd = allowedSlippage.match(percentRegexp); + let slippage = 0.0; + if (nd) { + slippage = Number(nd[1]) / Number(nd[2]); + } else { + logger.error('Failed to parse slippage value:', allowedSlippage); + } + return slippage * 100; + } + + private getPairKey(baseToken: string, quoteToken: string): string { + return `${baseToken}-${quoteToken}`; + } + + async findDefaultPool( + baseToken: string, + quoteToken: string, + routeType: 'amm', + ): Promise { + // Get the network-specific pools + const network = this.cardano.network; + const pools = SundaeswapConfig.getNetworkPools(network, routeType); + + if (!pools) return null; + + const pairKey = this.getPairKey(baseToken, quoteToken); + const reversePairKey = this.getPairKey(quoteToken, baseToken); + + return pools[pairKey] || pools[reversePairKey] || null; + } + + async getAmmPoolInfo(ident: string): Promise { + const queryProvider = new QueryProviderSundaeSwap( + this.networkName as TSupportedNetworks, + ); + const raw = await queryProvider.findPoolData({ ident }); + + const aReserveSmallest = + raw.liquidity.aReserve / BigInt(10 ** raw.assetA.decimals); + const bReserveSmallest = + raw.liquidity.bReserve / BigInt(10 ** raw.assetB.decimals); + + const info: PoolInfo = { + address: raw.ident, + baseTokenAddress: raw.assetA.assetId, + quoteTokenAddress: raw.assetB.assetId, + feePct: raw.currentFee * 100, + price: + raw.liquidity.aReserve > 0n + ? Number(aReserveSmallest) / Number(bReserveSmallest) + : 0, + baseTokenAmount: Number(raw.liquidity.aReserve), // ← explicit cast + quoteTokenAmount: Number(raw.liquidity.bReserve), // ← explicit cast + poolType: 'amm', + lpMint: { + address: raw.assetLP.assetId, + decimals: raw.assetLP.decimals, + }, + }; + + return info; + } + + /** + * Get the allowed slippage as a decimal from string or config + * @param allowedSlippageStr Optional string representation of slippage value + * @returns A decimal number (e.g., 0.05 for 5%) + */ + public getAllowedSlippage(allowedSlippageStr?: string): number { + if (allowedSlippageStr != null && isFractionString(allowedSlippageStr)) { + const fractionSplit = allowedSlippageStr.split('/'); + return Number(fractionSplit[0]) / Number(fractionSplit[1]); + } + + // Use the global allowedSlippage setting + const allowedSlippage = this.config.allowedSlippage; + + const nd = allowedSlippage.match(percentRegexp); + if (nd) return Number(nd[1]) / Number(nd[2]); + + throw new Error( + 'Encountered a malformed percent string in the config for allowed slippage.', + ); + } + + public calculateAssetAmount(utxos: UTxO[], asset: IPoolDataAsset): bigint { + return utxos.reduce((acc, utxo) => { + const [policyId, assetName] = asset.assetId.split('.'); + const assetValue = utxo.assets[policyId + assetName]; + if (assetValue) { + return acc + BigInt(assetValue); // Ensure addition is performed with BigInt + } + return acc; + }, 0n); // Initialize the accumulator with BigInt zero + } + + async getPoolData(poolIdent: string) { + const queryProvider = new QueryProviderSundaeSwap( + this.networkName as TSupportedNetworks, + ); + + // 2) Fetch the raw pool data + const raw = await queryProvider.findPoolData({ ident: poolIdent }); + + return raw; + } +} diff --git a/src/connectors/sundaeswap/sundaeswap.utils.ts b/src/connectors/sundaeswap/sundaeswap.utils.ts new file mode 100644 index 0000000000..59d713765e --- /dev/null +++ b/src/connectors/sundaeswap/sundaeswap.utils.ts @@ -0,0 +1,65 @@ +import { logger } from '../../services/logger'; +import { SundaeswapConfig } from './sundaeswap.config'; + +/** + * Find a pool Ident for a token pair in the configured pools + * + * @param baseToken Base token symbol + * @param quoteToken Quote token symbol + * @param poolType Type of pool ('amm' or 'clmm') + * @param network Network name (defaults to 'mainnet-beta') + * @returns Pool address or null if not found + */ +export const findPoolIdent = ( + baseToken: string, + quoteToken: string, + poolType: 'amm', + network: string = 'mainnet', +): string | null => { + // Get the network-specific pools + const pools = SundaeswapConfig.getNetworkPools(network, poolType); + if (!pools) return null; + + // Try standard order (BASE-QUOTE) + const standardKey = `${baseToken}-${quoteToken}`; + if (pools[standardKey]) return pools[standardKey]; + + // Try reverse order (QUOTE-BASE) + const reverseKey = `${quoteToken}-${baseToken}`; + if (pools[reverseKey]) return pools[reverseKey]; + + return null; +}; + +/** + * Format token amounts for display + * @param amount The raw amount as a string or number + * @param decimals The token decimals + * @returns The formatted token amount + */ +export const formatTokenAmount = ( + amount: string | number | bigint, + decimals: number, +): number => { + try { + if (typeof amount === 'string') { + return parseFloat(amount) / Math.pow(10, decimals); + } + if (typeof amount === 'bigint') { + return Number(amount) / Math.pow(10, decimals); + } + return amount / Math.pow(10, decimals); + } catch (error) { + logger.error(`Error formatting token amount: ${error}`); + return 0; + } +}; + +/** + * Check if a string is a valid fraction (in the form of 'a/b') + * @param value The string to check + * @returns True if the string is a valid fraction, false otherwise + */ +export function isFractionString(value: string): boolean { + return value.includes('/') && value.split('/').length === 2; +} diff --git a/src/services/connection-manager.ts b/src/services/connection-manager.ts index 62a0800954..b369496e33 100644 --- a/src/services/connection-manager.ts +++ b/src/services/connection-manager.ts @@ -1,11 +1,12 @@ import { Ethereum } from '../chains/ethereum/ethereum'; import { Solana } from '../chains/solana/solana'; +import { Cardano } from '../chains/cardano/cardano'; export interface Chain { // TODO: Add shared chain properties (e.g., network, chainId, etc.) } -export type ChainInstance = Ethereum | Solana; +export type ChainInstance = Ethereum | Solana | Cardano; export class UnsupportedChainException extends Error { constructor(message?: string) { @@ -41,7 +42,7 @@ export async function getInitializedChain<_T>( */ export function getSupportedChains(): string[] { // These should match the chains in getChainInstance - return ['ethereum', 'solana']; + return ['ethereum', 'solana', 'cardano']; } export async function getChainInstance( @@ -55,6 +56,8 @@ export async function getChainInstance( connection = await Ethereum.getInstance(network); } else if (chainLower === 'solana') { connection = await Solana.getInstance(network); + } else if (chainLower === 'cardano') { + connection = await Cardano.getInstance(network); } else { connection = undefined; } diff --git a/src/templates/cardano.yml b/src/templates/cardano.yml new file mode 100644 index 0000000000..933bebbb6c --- /dev/null +++ b/src/templates/cardano.yml @@ -0,0 +1,20 @@ +networks: + mainnet: + tokenListType: "FILE" + tokenListSource: "/home/gateway/conf/lists/cardano_mainnet_tokens.json" + nativeCurrencySymbol: 'ADA' + apiurl: 'https://cardano-mainnet.blockfrost.io/api/v0' + projectId: 'your_api_key' + preprod: + tokenListType: "FILE" + tokenListSource: "/home/gateway/conf/lists/cardano_preprod_tokens.json" + nativeCurrencySymbol: 'ADA' + apiurl: 'https://cardano-preprod.blockfrost.io/api/v0' + projectId: 'your_api_key' + preview: + tokenListType: "FILE" + tokenListSource: "/home/gateway/conf/lists/cardano_preview_tokens.json" + nativeCurrencySymbol: 'ADA' + apiurl: 'https://cardano-preview.blockfrost.io/api/v0' + projectId: 'your_api_key' + diff --git a/src/templates/json/cardano-schema.json b/src/templates/json/cardano-schema.json new file mode 100644 index 0000000000..5567f077e4 --- /dev/null +++ b/src/templates/json/cardano-schema.json @@ -0,0 +1,31 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "properties": { + "networks": { + "type": "object", + "patternProperties": { + "^\\w+$": { + "type": "object", + "properties": { + "tokenListType": { "type": "string" }, + "tokenListSource": { "type": "string" }, + "nativeCurrencySymbol": { "type": "string" }, + "apiurl": { "type": "string" }, + "projectId": { "type": "string" } + }, + "required": [ + "tokenListType", + "tokenListSource", + "nativeCurrencySymbol", + "apiurl", + "projectId" + ], + "additionalProperties": false + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false +} diff --git a/src/templates/json/minswap-schema.json b/src/templates/json/minswap-schema.json new file mode 100644 index 0000000000..477ddc589d --- /dev/null +++ b/src/templates/json/minswap-schema.json @@ -0,0 +1,31 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "properties": { + "allowedSlippage": { "type": "string" }, + "networks": { + "type": "object", + "patternProperties": { + "^\\w+(-\\w+)?$": { + "type": "object", + "properties": { + "amm": { + "type": "object", + "patternProperties": { + "^[A-Za-z0-9.-]+-[A-Za-z0-9.-]+$": { + "type": "string" + } + }, + "additionalProperties": false + } + }, + "required": ["amm"], + "additionalProperties": false + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false, + "required": ["allowedSlippage", "networks"] +} diff --git a/src/templates/json/sundaeswap-schema.json b/src/templates/json/sundaeswap-schema.json new file mode 100644 index 0000000000..477ddc589d --- /dev/null +++ b/src/templates/json/sundaeswap-schema.json @@ -0,0 +1,31 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "properties": { + "allowedSlippage": { "type": "string" }, + "networks": { + "type": "object", + "patternProperties": { + "^\\w+(-\\w+)?$": { + "type": "object", + "properties": { + "amm": { + "type": "object", + "patternProperties": { + "^[A-Za-z0-9.-]+-[A-Za-z0-9.-]+$": { + "type": "string" + } + }, + "additionalProperties": false + } + }, + "required": ["amm"], + "additionalProperties": false + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false, + "required": ["allowedSlippage", "networks"] +} diff --git a/src/templates/lists/cardano_mainnet_tokens.json b/src/templates/lists/cardano_mainnet_tokens.json new file mode 100644 index 0000000000..01457bbabf --- /dev/null +++ b/src/templates/lists/cardano_mainnet_tokens.json @@ -0,0 +1,53 @@ +{ + "name": "Cardano Tokenlist", + "logoURI": "https://ibb.co/N1Jmswk", + "keywords": ["cardano", "tokens", "MIN"], + "timestamp": "2024-12-12T12:00:00+00:00", + "tokens": [ + { + "policyId": "29d222ce763455e3d7a09a665ce554f00ac89d2e99a1a83d267170c6", + "assetName": "4d494e", + "decimals": 6, + "name": "Minswap Token", + "symbol": "MIN", + "logoURI": "https://ibb.co/L1Tp0rQ", + "address": "29d222ce763455e3d7a09a665ce554f00ac89d2e99a1a83d267170c6.4d494e" + }, + { + "policyId": "9a9693a9a37912a5097918f97918d15240c92ab729a0b7c4aa144d77", + "assetName": "53554e444145", + "decimals": 6, + "name": "SUNDAE Token", + "symbol": "SUNDAE", + "logoURI": "https://ibb.co/Q31Nv1TK", + "address": "9a9693a9a37912a5097918f97918d15240c92ab729a0b7c4aa144d77.53554e444145" + }, + { + "policyId": "", + "assetName": "", + "decimals": 6, + "name": "Cardano Native Token", + "symbol": "ADA", + "logoURI": "https://ibb.co/N1Jmswk", + "address": "ada.lovelace" + }, + { + "policyId": "e0302560ced2fdcbfcb2602697df970cd0d6a38f94b32703f51c312b", + "assetName": "0014df102f36866691fa75a9aab66dec99f7cc2d297ca09e34d9ce68cde04773", + "decimals": 0, + "name": "SundaeSwap LP Token", + "symbol": "LP-SUNDAE", + "logoURI": "", + "address": "e0302560ced2fdcbfcb2602697df970cd0d6a38f94b32703f51c312b.0014df102f36866691fa75a9aab66dec99f7cc2d297ca09e34d9ce68cde04773" + }, + { + "policyId": "f5808c2c990d86da54bfc97d89cee6efa20cd8461616359478d96b4c", + "assetName": "82e2b1fd27a7712a1a9cf750dfbea1a5778611b20e06dd6a611df7a643f8cb75", + "decimals": 0, + "name": "Minswap LP Token", + "symbol": "LP-MIN", + "logoURI": "", + "address": "addr1z84q0denmyep98ph3tmzwsmw0j7zau9ljmsqx6a4rvaau66j2c79gy9l76sdg0xwhd7r0c0kna0tycz4y5s6mlenh8pq777e2a.0014df102f36866691fa75a9aab66dec99f7cc2d297ca09e34d9ce68cde04773" + } + ] +} diff --git a/src/templates/lists/cardano_preprod_tokens.json b/src/templates/lists/cardano_preprod_tokens.json new file mode 100644 index 0000000000..1964df10e0 --- /dev/null +++ b/src/templates/lists/cardano_preprod_tokens.json @@ -0,0 +1,44 @@ +{ + "name": "Cardano Tokenlist", + "logoURI": "https://ibb.co/N1Jmswk", + "keywords": ["cardano", "tokens", "MIN"], + "timestamp": "2024-12-12T12:00:00+00:00", + "tokens": [ + { + "policyId": "e16c2dc8ae937e8d3790c7fd7168d7b994621ba14ca11415f39fed72", + "assetName": "4d494e", + "decimals": 0, + "name": "Minswap Token", + "symbol": "MIN", + "logoURI": "https://ibb.co/L1Tp0rQ", + "address": "e16c2dc8ae937e8d3790c7fd7168d7b994621ba14ca11415f39fed72.4d494e" + }, + { + "policyId": "", + "assetName": "", + "decimals": 6, + "name": "Cardano Native Token", + "symbol": "ADA", + "logoURI": "https://ibb.co/N1Jmswk", + "address": "ada.lovelace" + }, + { + "policyId": "e4214b7cce62ac6fbba385d164df48e157eae5863521b4b67ca71d86", + "assetName": "3bb0079303c57812462dec9de8fb867cef8fd3768de7f12c77f6f0dd80381d0d", + "decimals": 0, + "name": "Minswap Liquidity pool token", + "symbol": "LP", + "logoURI": "https://ibb.co/L1Tp0rQ", + "address": "e4214b7cce62ac6fbba385d164df48e157eae5863521b4b67ca71d86.3bb0079303c57812462dec9de8fb867cef8fd3768de7f12c77f6f0dd80381d0d" + }, + { + "policyId": "d4fece6b39f7cd78a3f036b2ae6508c13524b863922da80f68dd9ab7", + "assetName": "5553444d", + "decimals": 6, + "name": "USDM", + "symbol": "USDM", + "logoURI": "", + "address": "d4fece6b39f7cd78a3f036b2ae6508c13524b863922da80f68dd9ab7.5553444d" + } + ] +} diff --git a/src/templates/lists/cardano_preview_tokens.json b/src/templates/lists/cardano_preview_tokens.json new file mode 100644 index 0000000000..647f83f783 --- /dev/null +++ b/src/templates/lists/cardano_preview_tokens.json @@ -0,0 +1,35 @@ +{ + "name": "Cardano Tokenlist", + "logoURI": "https://ibb.co/N1Jmswk", + "keywords": ["cardano", "tokens", "SUNDAE"], + "timestamp": "2024-12-12T12:00:00+00:00", + "tokens": [ + { + "policyId": "99b071ce8580d6a3a11b4902145adb8bfd0d2a03935af8cf66403e15", + "assetName": "534245525259", + "decimals": 0, + "name": "SBERRY Token", + "symbol": "SBERRY", + "logoURI": "https://ibb.co/hJbVKRJW", + "address": "99b071ce8580d6a3a11b4902145adb8bfd0d2a03935af8cf66403e15.534245525259" + }, + { + "policyId": "", + "assetName": "", + "decimals": 6, + "name": "Cardano Native Token", + "symbol": "ADA", + "logoURI": "https://ibb.co/N1Jmswk", + "address": "ada.lovelace" + }, + { + "policyId": "44a1eb2d9f58add4eb1932bd0048e6a1947e85e3fe4f32956a110414", + "assetName": "0014df102baab4c73a1cd60176f903a29a9c92ed4237c88622da51e9179121a3", + "decimals": 0, + "name": "Sundaeswap Liquidity pool token", + "symbol": "LP", + "logoURI": "hhttps://ibb.co/JWr1GWs3", + "address": "44a1eb2d9f58add4eb1932bd0048e6a1947e85e3fe4f32956a110414.0014df102baab4c73a1cd60176f903a29a9c92ed4237c88622da51e9179121a3" + } + ] +} diff --git a/src/templates/minswap.yml b/src/templates/minswap.yml new file mode 100644 index 0000000000..5b297f6010 --- /dev/null +++ b/src/templates/minswap.yml @@ -0,0 +1,20 @@ +# Global settings for Minswap +# how much the execution price is allowed to move unfavorably +allowedSlippage: '1/100' + +# Network-specific pool configurations +networks: + # Cardano mainnet pools + mainnet: + # AMM pools for Cardano mainnet + amm: + # Format: base-quote: pool_address + ADA-MIN: '6aa2153e1ae896a95539c9d62f76cedcdabdcdf144e564b8955f609d660cf6a2' + + # Cardano preprod pools + preprod: + # AMM pools for Cardano preprod + amm: + # Format: base-quote: pool_address + ADA-MIN: '3bb0079303c57812462dec9de8fb867cef8fd3768de7f12c77f6f0dd80381d0d' + ADA-USDM: '3bb0079303c57812462dec9de8fb867cef8fd3768de7f12c77f6f0dd80381d0d' \ No newline at end of file diff --git a/src/templates/root.yml b/src/templates/root.yml index f7dca86f9f..53381945d7 100644 --- a/src/templates/root.yml +++ b/src/templates/root.yml @@ -16,6 +16,10 @@ configurations: configurationPath: solana.yml schemaPath: solana-schema.json + $namespace cardano: + configurationPath: cardano.yml + schemaPath: cardano-schema.json + $namespace jupiter: configurationPath: jupiter.yml schemaPath: jupiter-schema.json @@ -27,3 +31,11 @@ configurations: $namespace raydium: configurationPath: raydium.yml schemaPath: raydium-schema.json + + $namespace minswap: + configurationPath: minswap.yml + schemaPath: minswap-schema.json + + $namespace sundaeswap: + configurationPath: sundaeswap.yml + schemaPath: sundaeswap-schema.json \ No newline at end of file diff --git a/src/templates/sundaeswap.yml b/src/templates/sundaeswap.yml new file mode 100644 index 0000000000..9927720322 --- /dev/null +++ b/src/templates/sundaeswap.yml @@ -0,0 +1,22 @@ +# Global settings for Minswap +# how much the execution price is allowed to move unfavorably +allowedSlippage: '1/100' + +# Network-specific pool configurations +networks: + # Cardano mainnet pools + mainnet: + # AMM pools for Cardano mainnet + amm: + # Format: base-quote: pool_address + ADA-SUNDAE: '2f36866691fa75a9aab66dec99f7cc2d297ca09e34d9ce68cde04773' + + # Cardano preview pools + preview: + # AMM pools for Cardano preprod + amm: + # Format: base-quote: pool_address + ADA-SBERRY: '2baab4c73a1cd60176f903a29a9c92ed4237c88622da51e9179121a3' + + + diff --git a/src/wallet/schemas.ts b/src/wallet/schemas.ts index 41bf9001b1..51634f51e7 100644 --- a/src/wallet/schemas.ts +++ b/src/wallet/schemas.ts @@ -6,6 +6,7 @@ export const WalletAddressSchema = Type.String(); export const AddWalletRequestSchema = Type.Object({ chain: Type.String(), privateKey: Type.String(), + network: Type.Optional(Type.String()), }); export const AddWalletResponseSchema = Type.Object({ diff --git a/src/wallet/utils.ts b/src/wallet/utils.ts index 10056a2f73..247cc9bb5d 100644 --- a/src/wallet/utils.ts +++ b/src/wallet/utils.ts @@ -3,6 +3,7 @@ import fse from 'fs-extra'; import { Ethereum } from '../chains/ethereum/ethereum'; import { Solana } from '../chains/solana/solana'; +import { Cardano } from '../chains/cardano/cardano'; import { ConfigManagerCertPassphrase } from '../services/config-manager-cert-passphrase'; import { getInitializedChain, @@ -44,7 +45,7 @@ export function validateChainName(chain: string): boolean { logger.warn( `Failed to get supported chains: ${error.message}. Using fallback list.`, ); - return ['ethereum', 'solana'].includes(chain.toLowerCase()); + return ['ethereum', 'solana', 'cardano'].includes(chain.toLowerCase()); } } @@ -96,9 +97,18 @@ export async function addWallet( // Default to mainnet-beta for Solana or mainnet for other chains const network = req.chain === 'solana' ? 'mainnet-beta' : 'mainnet'; + const cardanoNetwork = req.network ? req.network : 'mainnet'; try { - connection = await getInitializedChain(req.chain, network); + if (req.chain.toLowerCase() === 'cardano') { + connection = await getInitializedChain( + req.chain, + cardanoNetwork, + ); + } else { + // For Ethereum and Solana, use the default network + connection = await getInitializedChain(req.chain, network); + } } catch (e) { if (e instanceof UnsupportedChainException) { throw fastify.httpErrors.badRequest( @@ -127,6 +137,17 @@ export async function addWallet( req.privateKey, passphrase, ); + } else if (connection instanceof Cardano) { + const cardanoWallet = await connection.getWalletFromPrivateKey( + req.privateKey, + ); + address = cardanoWallet.address; + // Further validate Cardano address + address = Cardano.validateAddress(address); + encryptedPrivateKey = await connection.encrypt( + req.privateKey, + passphrase, + ); } if (address === undefined || encryptedPrivateKey === undefined) { @@ -171,6 +192,8 @@ export async function removeWallet( validatedAddress = Ethereum.validateAddress(req.address); } else if (req.chain.toLowerCase() === 'solana') { validatedAddress = Solana.validateAddress(req.address); + } else if (req.chain.toLowerCase() === 'cardano') { + validatedAddress = Cardano.validateAddress(req.address); } else { // This should not happen due to validateChainName check, but just in case throw new Error(`Unsupported chain: ${req.chain}`); @@ -283,7 +306,7 @@ export async function getWallets( await mkdirIfDoesNotExist(walletPath); // Get only valid chain directories - const validChains = ['ethereum', 'solana']; + const validChains = ['ethereum', 'solana', 'cardano']; const allDirs = await getDirectories(walletPath); const chains = allDirs.filter((dir) => validChains.includes(dir.toLowerCase()), @@ -307,6 +330,9 @@ export async function getWallets( } else if (chain.toLowerCase() === 'solana') { // Basic Solana address length check return address.length >= 32 && address.length <= 44; + } else if (chain.toLowerCase() === 'cardano') { + // Basic Cardano address validation (starts with addr or addr_test) + return /^(addr|addr_test)[0-9a-zA-Z]{1,}$/i.test(address); } return false; } catch { diff --git a/test/chains/cardano/cardano.test.js b/test/chains/cardano/cardano.test.js new file mode 100644 index 0000000000..861fbe8252 --- /dev/null +++ b/test/chains/cardano/cardano.test.js @@ -0,0 +1,184 @@ +// test/chains/cardano/cardano.test.js + +const fs = require('fs'); +const path = require('path'); + +const { test, describe, expect, beforeEach } = require('@jest/globals'); +const axios = require('axios'); + +// Constants for this test file +const CHAIN = 'cardano'; +const NETWORK = 'preprod'; // for balance‐endpoint only +const TEST_WALLET = + 'addr_test1vrvqa7ytgmptew2qy3ec0lqdk9n94vcgwu4wy07kqp2he0srll8mg'; + +// Mock API calls +jest.mock('axios'); + +// Helper to load mock responses +function loadMockResponse(name) { + return JSON.parse( + fs.readFileSync(path.join(__dirname, 'mocks', `${name}.json`), 'utf8'), + ); +} + +// Validate balance response shape +function validateBalanceResponse(resp) { + return ( + resp && + typeof resp.network === 'string' && + typeof resp.wallet === 'string' && + Array.isArray(resp.balances) && + resp.balances.every( + (b) => + ['symbol', 'address', 'name', 'balance'].every( + (k) => typeof b[k] === 'string', + ) && typeof b.decimals === 'number', + ) + ); +} + +describe('Cardano Chain Tests (Preprod Network)', () => { + beforeEach(() => { + axios.get = jest.fn(); + axios.post = jest.fn(); + }); + + describe('Balance Endpoint', () => { + test('returns and validates wallet balances', async () => { + const mockResponse = loadMockResponse('balance'); + + axios.get.mockResolvedValueOnce({ + status: 200, + data: mockResponse, + }); + + const response = await axios.get( + `http://localhost:15888/chains/${CHAIN}/balances`, + { + params: { + network: NETWORK, + wallet: TEST_WALLET, + tokens: ['ADA', 'MIN', 'LP'], + }, + }, + ); + + expect(response.status).toBe(200); + expect(validateBalanceResponse(response.data)).toBe(true); + + // must match the fixture exactly + expect(response.data.network).toBe(mockResponse.network); + expect(response.data.wallet).toBe(mockResponse.wallet); + expect(response.data.balances).toHaveLength(mockResponse.balances.length); + + expect(axios.get).toHaveBeenCalledWith( + `http://localhost:15888/chains/${CHAIN}/balances`, + expect.objectContaining({ + params: { + network: NETWORK, + wallet: TEST_WALLET, + tokens: ['ADA', 'MIN', 'LP'], + }, + }), + ); + }); + + test('handles error response for invalid wallet', async () => { + axios.get.mockRejectedValueOnce({ + response: { + status: 400, + data: { error: 'Invalid wallet address', code: 400 }, + }, + }); + + await expect( + axios.get(`http://localhost:15888/chains/${CHAIN}/balances`, { + params: { network: NETWORK, wallet: 'invalid', tokens: ['ADA'] }, + }), + ).rejects.toMatchObject({ + response: { + status: 400, + data: { error: 'Invalid wallet address' }, + }, + }); + }); + }); + + describe('Tokens Endpoint', () => { + test('returns and validates token list', async () => { + const mockResponse = loadMockResponse('tokens'); + + axios.get.mockResolvedValueOnce({ status: 200, data: mockResponse }); + + const response = await axios.get( + `http://localhost:15888/chains/${CHAIN}/tokens`, + { params: { network: mockResponse.network } }, + ); + + expect(response.status).toBe(200); + expect(Array.isArray(response.data.tokens)).toBe(true); + response.data.tokens.forEach((t) => { + expect(typeof t.symbol).toBe('string'); + expect(typeof t.address).toBe('string'); + expect(typeof t.decimals).toBe('number'); + expect(typeof t.name).toBe('string'); + }); + + // derive network from the fixture + if ('network' in mockResponse) { + expect(response.data.network).toBe(mockResponse.network); + } + expect(response.data.tokens.length).toBeGreaterThan(0); + + expect(axios.get).toHaveBeenCalledWith( + `http://localhost:15888/chains/${CHAIN}/tokens`, + expect.objectContaining({ + params: { network: mockResponse.network }, + }), + ); + }); + }); + + describe('Status Endpoint', () => { + test('returns and validates chain status', async () => { + const mockResponse = loadMockResponse('status'); + + axios.get.mockResolvedValueOnce({ status: 200, data: mockResponse }); + + const response = await axios.get( + `http://localhost:15888/chains/${CHAIN}/status`, + { params: { network: mockResponse.network } }, + ); + + expect(response.status).toBe(200); + + if ('network' in mockResponse) { + expect(response.data.network).toBe(mockResponse.network); + } + + if ('chain' in mockResponse) { + expect(response.data.chain).toBe(mockResponse.chain); + } + + if ('latestBlock' in mockResponse) { + expect(typeof response.data.latestBlock).toBe('number'); + } + + if ('rpcUrl' in mockResponse) { + expect(typeof response.data.rpcUrl).toBe('string'); + } + + if ('nativeCurrency' in mockResponse) { + expect(response.data.nativeCurrency).toBe('ADA'); + } + + expect(axios.get).toHaveBeenCalledWith( + `http://localhost:15888/chains/${CHAIN}/status`, + expect.objectContaining({ + params: { network: mockResponse.network }, + }), + ); + }); + }); +}); diff --git a/test/chains/cardano/mocks/balance.json b/test/chains/cardano/mocks/balance.json new file mode 100644 index 0000000000..1d4d20b658 --- /dev/null +++ b/test/chains/cardano/mocks/balance.json @@ -0,0 +1,20 @@ +{ + "network": "preprod", + "wallet": "addr_test1vrvqa7ytgmptew2qy3ec0lqdk9n94vcgwu4wy07kqp2he0srll8mg", + "balances": [ + { + "symbol": "ADA", + "address": "ada.lovelace", + "decimals": 6, + "name": "ADA", + "balance": "25" + }, + { + "symbol": "MIN", + "address": "e16c2dc8ae937e8d3790c7fd7168d7b994621ba14ca11415f39fed72.4d494e", + "decimals": 0, + "name": "MIN Token", + "balance": "1500" + } + ] +} diff --git a/test/chains/cardano/mocks/status.json b/test/chains/cardano/mocks/status.json new file mode 100644 index 0000000000..0318d6f156 --- /dev/null +++ b/test/chains/cardano/mocks/status.json @@ -0,0 +1,7 @@ +{ + "chain": "cardano", + "network": "preprod", + "rpcUrl": "https://cardano-preprod.blockfrost.io/api/v0", + "currentBlockNumber": 12080947, + "nativeCurrency": "ADA" +} diff --git a/test/chains/cardano/mocks/tokens.json b/test/chains/cardano/mocks/tokens.json new file mode 100644 index 0000000000..a14f80c472 --- /dev/null +++ b/test/chains/cardano/mocks/tokens.json @@ -0,0 +1,22 @@ +{ + "tokens": [ + { + "symbol": "ADA", + "address": "ada.lovelace", + "decimals": 6, + "name": "Cardano Native Token" + }, + { + "symbol": "MIN", + "address": "e16c2dc8ae937e8d3790c7fd7168d7b994621ba14ca11415f39fed72.4d494e", + "decimals": 0, + "name": "Minswap Token" + }, + { + "symbol": "LP", + "address": "e4214b7cce62ac6fbba385d164df48e157eae5863521b4b67ca71d86.3bb0079303c57812462dec9de8fb867cef8fd3768de7f12c77f6f0dd80381d0d", + "decimals": 0, + "name": "Minswap Liquidity pool token" + } + ] +} diff --git a/test/chains/cardano/wallet.test.ts b/test/chains/cardano/wallet.test.ts new file mode 100644 index 0000000000..5a55f3a4c0 --- /dev/null +++ b/test/chains/cardano/wallet.test.ts @@ -0,0 +1,339 @@ +// Mock fs-extra to prevent actual file writes +jest.mock('fs-extra'); + +import * as fse from 'fs-extra'; + +import { gatewayApp } from '../../../src/app'; +import { Cardano } from '../../../src/chains/cardano/cardano'; +import { ConfigManagerCertPassphrase } from '../../../src/services/config-manager-cert-passphrase'; +import { GetWalletResponse } from '../../../src/wallet/schemas'; +import { patch, unpatch } from '../../services/patch'; + +const mockFse = fse as jest.Mocked; + +let cardano: Cardano; + +// Test wallet data +const testAddress = + 'addr_test1vrvqa7ytgmptew2qy3ec0lqdk9n94vcgwu4wy07kqp2he0srll8mg'; +const testPrivateKey = + 'ed25519_sk1n24dk27xar2skjef5a5xvpk0uy0sqw62tt7hlv7wcpd4xp4fhy5sdask94'; // noqa: mock + +// Mock the encoded private key response +const encodedPrivateKey = { + address: 'addr_test1vrvqa7ytgmptew2qy3ec0lqdk9n94vcgwu4wy07kqp2he0srll8mg', + id: '7bb58a6c-06d3-4ede-af06-5f4a5cb87f0b', + version: 3, + Crypto: { + cipher: 'aes-128-ctr', + cipherparams: { iv: 'test-iv-12345' }, + ciphertext: 'mock-encrypted-key', // noqa: mock + kdf: 'scrypt', + kdfparams: { + salt: 'mock-salt', // noqa: mock + n: 131072, + dklen: 32, + p: 1, + r: 8, + }, + mac: 'mock-mac', // noqa: mock + }, +}; + +// Track wallet operations in memory to avoid file system pollution +const mockWallets: { [key: string]: Set } = { + cardano: new Set(), +}; + +beforeAll(async () => { + patch(ConfigManagerCertPassphrase, 'readPassphrase', () => 'a'); + cardano = await Cardano.getInstance('preprod'); + await gatewayApp.ready(); +}); + +beforeEach(() => { + patch(ConfigManagerCertPassphrase, 'readPassphrase', () => 'a'); + + // Clear mock wallets + mockWallets.cardano.clear(); + + // Mock wallet operations to work with in-memory storage + patch(cardano, 'getWalletFromPrivateKey', () => { + return { address: testAddress }; + }); + + patch(cardano, 'encrypt', () => { + return JSON.stringify(encodedPrivateKey); + }); + + // Setup fs-extra mocks + (mockFse.writeFile as jest.Mock).mockImplementation(async (path: any) => { + const pathStr = path.toString(); + const pathParts = pathStr.split('/'); + const chain = pathParts[pathParts.length - 2]; + const address = pathParts[pathParts.length - 1].replace('.json', ''); + + if (chain && address) { + mockWallets[chain].add(address); + } + return undefined; + }); + + (mockFse.readdir as jest.Mock).mockImplementation( + async (dirPath: any, options?: any) => { + const pathStr = dirPath.toString(); + + // If asking for directories in wallet path + if (pathStr.endsWith('/wallets') && options?.withFileTypes) { + return Object.keys(mockWallets).map((chain) => ({ + name: chain, + isDirectory: () => true, + isFile: () => false, + })); + } + + // If asking for files in a chain directory + const chain = pathStr.split('/').pop(); + if (chain && mockWallets[chain]) { + if (options?.withFileTypes) { + return Array.from(mockWallets[chain]).map((addr) => ({ + name: `${addr}.json`, + isDirectory: () => false, + isFile: () => true, + })); + } + return Array.from(mockWallets[chain]).map((addr) => `${addr}.json`); + } + + return []; + }, + ); + + (mockFse.readFile as jest.Mock).mockResolvedValue( + Buffer.from(JSON.stringify(encodedPrivateKey)), + ); + (mockFse.pathExists as jest.Mock).mockResolvedValue(true); + (mockFse.ensureDir as jest.Mock).mockResolvedValue(undefined); + + (mockFse.remove as jest.Mock).mockImplementation(async (filePath: any) => { + const pathStr = filePath.toString(); + const pathParts = pathStr.split('/'); + const chain = pathParts[pathParts.length - 2]; + const address = pathParts[pathParts.length - 1].replace('.json', ''); + + if (chain && mockWallets[chain]) { + mockWallets[chain].delete(address); + } + return undefined; + }); +}); + +afterAll(async () => { + await cardano.close(); + await gatewayApp.close(); +}); + +afterEach(() => { + unpatch(); + jest.clearAllMocks(); +}); + +describe('Cardano Wallet Operations', () => { + describe('POST /wallet/add', () => { + it('should add an Cardano wallet successfully', async () => { + const response = await gatewayApp.inject({ + method: 'POST', + url: '/wallet/add', + payload: { + privateKey: testPrivateKey, + chain: 'cardano', + network: 'preprod', + }, + }); + + expect(response.statusCode).toBe(200); + expect(response.headers['content-type']).toMatch(/json/); + + const result = JSON.parse(response.payload); + expect(result).toMatchObject({ + address: testAddress, + }); + }); + + it('should fail with invalid private key', async () => { + // Override the mock to simulate invalid key + patch(cardano, 'getWalletFromPrivateKey', () => { + throw new Error('Invalid private key'); + }); + + const response = await gatewayApp.inject({ + method: 'POST', + url: '/wallet/add', + payload: { + privateKey: 'invalid-key', + chain: 'cardano', + network: 'preprod', + }, + }); + + expect(response.statusCode).toBe(500); + }); + + it('should fail with missing parameters', async () => { + const response = await gatewayApp.inject({ + method: 'POST', + url: '/wallet/add', + payload: { + chain: 'cardano', + // missing privateKey + }, + }); + + expect(response.statusCode).toBe(400); + }); + }); + + describe('GET /wallet', () => { + it('should fetch wallets for Cardano', async () => { + // First add a wallet + mockWallets.cardano.add(testAddress); + + const response = await gatewayApp.inject({ + method: 'GET', + url: '/wallet', + }); + + expect(response.statusCode).toBe(200); + expect(response.headers['content-type']).toMatch(/json/); + + const wallets: GetWalletResponse[] = JSON.parse(response.payload); + const cardanoWallet = wallets.find((w) => w.chain === 'cardano'); + + expect(cardanoWallet).toBeDefined(); + expect(cardanoWallet?.walletAddresses).toContain(testAddress); + }); + + it('should return empty array when no wallets exist', async () => { + // Clear wallets + mockWallets.cardano.clear(); + + const response = await gatewayApp.inject({ + method: 'GET', + url: '/wallet', + }); + + expect(response.statusCode).toBe(200); + + const wallets: GetWalletResponse[] = JSON.parse(response.payload); + const cardanoWallet = wallets.find((w) => w.chain === 'cardano'); + + expect(cardanoWallet?.walletAddresses).toHaveLength(0); + }); + }); + + describe('DELETE /wallet/remove', () => { + it('should remove an Cardano wallet successfully', async () => { + // First add the wallet to mock storage + mockWallets.cardano.add(testAddress); + + const response = await gatewayApp.inject({ + method: 'DELETE', + url: '/wallet/remove', + payload: { + address: testAddress, + chain: 'cardano', + }, + }); + + expect(response.statusCode).toBe(200); + expect(response.headers['content-type']).toMatch(/json/); + + expect(response.payload).toBe('null'); + expect(mockWallets.cardano.has(testAddress)).toBe(false); + }); + + it('should fail when removing non-existent wallet', async () => { + (mockFse.pathExists as jest.Mock).mockResolvedValue(false); + + const response = await gatewayApp.inject({ + method: 'DELETE', + url: '/wallet/remove', + payload: { + address: + 'addr_test1vrvqa7ytgmptew2qy3ec0lqdk9n94vcgwu4wy07kqp2he0srll8mg', + chain: 'cardano', + }, + }); + + // The endpoint doesn't check if wallet exists, just removes the file + expect(response.statusCode).toBe(200); + }); + + it('should fail with invalid address format', async () => { + const response = await gatewayApp.inject({ + method: 'DELETE', + url: '/wallet/remove', + payload: { + address: 'invalid-address', + chain: 'cardano', + }, + }); + + // Address validation happens and throws 500 on invalid format + expect(response.statusCode).toBe(500); + }); + }); + + describe('Wallet Operations Integration', () => { + it('should handle full wallet lifecycle: add, fetch, and remove', async () => { + // 1. Add wallet + const addResponse = await gatewayApp.inject({ + method: 'POST', + url: '/wallet/add', + payload: { + privateKey: testPrivateKey, + chain: 'cardano', + network: 'preprod', + }, + }); + expect(addResponse.statusCode).toBe(200); + + // 2. Fetch wallets + const getResponse = await gatewayApp.inject({ + method: 'GET', + url: '/wallet', + }); + expect(getResponse.statusCode).toBe(200); + + const wallets: GetWalletResponse[] = JSON.parse(getResponse.payload); + const cardanoWallet = wallets.find((w) => w.chain === 'cardano'); + expect(cardanoWallet?.walletAddresses).toContain(testAddress); + + // 3. Remove wallet + const removeResponse = await gatewayApp.inject({ + method: 'DELETE', + url: '/wallet/remove', + payload: { + address: testAddress, + chain: 'cardano', + }, + }); + expect(removeResponse.statusCode).toBe(200); + + // 4. Verify wallet is removed + const finalGetResponse = await gatewayApp.inject({ + method: 'GET', + url: '/wallet', + }); + expect(finalGetResponse.statusCode).toBe(200); + + const finalWallets: GetWalletResponse[] = JSON.parse( + finalGetResponse.payload, + ); + const finalCardanoWallet = finalWallets.find( + (w) => w.chain === 'cardano', + ); + expect(finalCardanoWallet?.walletAddresses).not.toContain(testAddress); + }); + }); +}); diff --git a/test/connectors/minswap/amm.test.js b/test/connectors/minswap/amm.test.js new file mode 100644 index 0000000000..8616c1b09e --- /dev/null +++ b/test/connectors/minswap/amm.test.js @@ -0,0 +1,545 @@ +const fs = require('fs'); +const path = require('path'); + +const { test, describe, expect, beforeEach } = require('@jest/globals'); +const axios = require('axios'); + +// Constants for this test file +const CONNECTOR = 'minswap'; +const PROTOCOL = 'amm'; +const CHAIN = 'cardano'; +const NETWORK = 'preprod'; +const BASE_TOKEN = 'ADA'; +const QUOTE_TOKEN = 'MIN'; +const TEST_POOL = + '3bb0079303c57812462dec9de8fb867cef8fd3768de7f12c77f6f0dd80381d0d'; +const TEST_WALLET = + 'addr_test1vrvqa7ytgmptew2qy3ec0lqdk9n94vcgwu4wy07kqp2he0srll8mg'; + +// Mock API calls (axios.get and axios.post) +jest.mock('axios'); + +// Mock implementation for axios +axios.get = jest.fn(); +axios.post = jest.fn(); + +// Helper to load mock responses +function loadMockResponse(filename) { + // Use mocks from the same directory + const filePath = path.join( + __dirname, + 'mocks', + `${PROTOCOL}-${filename}.json`, + ); + return JSON.parse(fs.readFileSync(filePath, 'utf8')); +} + +// Function to validate pool info response structure +function validatePoolInfo(response) { + return ( + response && + typeof response.address === 'string' && + typeof response.baseTokenAddress === 'string' && + typeof response.quoteTokenAddress === 'string' && + typeof response.feePct === 'number' && + typeof response.price === 'number' && + typeof response.baseTokenAmount === 'number' && + typeof response.quoteTokenAmount === 'number' && + response.poolType === 'amm' && + response.lpMint && + typeof response.lpMint.address === 'string' && + typeof response.lpMint.decimals === 'number' + ); +} + +// Function to validate swap quote response structure +function validateSwapQuote(response) { + return ( + response && + typeof response.poolAddress === 'string' && + typeof response.estimatedAmountIn === 'number' && + typeof response.estimatedAmountOut === 'number' && + typeof response.minAmountOut === 'number' && + typeof response.maxAmountIn === 'number' && + typeof response.baseTokenBalanceChange === 'number' && + typeof response.quoteTokenBalanceChange === 'number' && + typeof response.price === 'number' + ); +} + +// Tests +describe('Minswap AMM Tests (Preprod Network)', () => { + beforeEach(() => { + // Reset axios mocks before each test + axios.get.mockClear(); + axios.post.mockClear(); + }); + + describe('Pool Info Endpoint', () => { + test('returns and validates pool info', async () => { + // Load mock response + const mockResponse = loadMockResponse('pool-info'); + + // Setup mock axios + axios.get.mockResolvedValueOnce({ + status: 200, + data: mockResponse, + }); + + // Make the request + const response = await axios.get( + `http://localhost:15888/connectors/${CONNECTOR}/${PROTOCOL}/pool-info`, + { + params: { + network: NETWORK, + baseToken: BASE_TOKEN, + quoteToken: QUOTE_TOKEN, + }, + }, + ); + + // Validate the response + expect(response.status).toBe(200); + expect(validatePoolInfo(response.data)).toBe(true); + + // Check expected mock values + expect(response.data.address).toBe(TEST_POOL); + expect(response.data.poolType).toBe('amm'); + + // Verify axios was called with correct parameters + expect(axios.get).toHaveBeenCalledWith( + `http://localhost:15888/connectors/${CONNECTOR}/${PROTOCOL}/pool-info`, + expect.objectContaining({ + params: expect.objectContaining({ + network: NETWORK, + baseToken: BASE_TOKEN, + quoteToken: QUOTE_TOKEN, + }), + }), + ); + }); + + test('handles error for non-existent pool', async () => { + // Setup mock axios with error response + axios.get.mockRejectedValueOnce({ + response: { + status: 404, + data: { + error: 'Pool not found', + code: 404, + }, + }, + }); + + // Make the request and expect it to be rejected + await expect( + axios.get( + `http://localhost:15888/connectors/${CONNECTOR}/${PROTOCOL}/pool-info`, + { + params: { + network: NETWORK, + baseToken: 'UNKNOWN', + quoteToken: QUOTE_TOKEN, + }, + }, + ), + ).rejects.toMatchObject({ + response: { + status: 404, + data: { + error: 'Pool not found', + }, + }, + }); + }); + }); + + describe('Quote Swap Endpoint', () => { + test('returns and validates swap quote for SELL', async () => { + // Load mock response + const mockResponse = loadMockResponse('quote-swap-sell'); + + // Setup mock axios + axios.get.mockResolvedValueOnce({ + status: 200, + data: mockResponse, + }); + + // Make the request + const response = await axios.get( + `http://localhost:15888/connectors/${CONNECTOR}/${PROTOCOL}/quote-swap`, + { + params: { + network: NETWORK, + baseToken: BASE_TOKEN, + quoteToken: QUOTE_TOKEN, + side: 'SELL', + amount: 1.0, + }, + }, + ); + + // Validate the response + expect(response.status).toBe(200); + expect(validateSwapQuote(response.data)).toBe(true); + + // Check expected mock values + expect(response.data.poolAddress).toBe(TEST_POOL); + expect(response.data.baseTokenBalanceChange).toBeLessThan(0); // SELL means negative base token change + expect(response.data.quoteTokenBalanceChange).toBeGreaterThan(0); // SELL means positive quote token change + + // Verify axios was called with correct parameters + expect(axios.get).toHaveBeenCalledWith( + `http://localhost:15888/connectors/${CONNECTOR}/${PROTOCOL}/quote-swap`, + expect.objectContaining({ + params: expect.objectContaining({ + network: NETWORK, + baseToken: BASE_TOKEN, + quoteToken: QUOTE_TOKEN, + side: 'SELL', + amount: 1.0, + }), + }), + ); + }); + + test('returns and validates swap quote for BUY', async () => { + // Modify the mock response for BUY direction + const mockBuyResponse = loadMockResponse('quote-swap'); + + // Setup mock axios + axios.get.mockResolvedValueOnce({ + status: 200, + data: mockBuyResponse, + }); + + // Make the request + const response = await axios.get( + `http://localhost:15888/connectors/${CONNECTOR}/${PROTOCOL}/quote-swap`, + { + params: { + network: NETWORK, + baseToken: BASE_TOKEN, + quoteToken: QUOTE_TOKEN, + side: 'BUY', + amount: 1.0, + }, + }, + ); + + // Validate the response + expect(response.status).toBe(200); + expect(validateSwapQuote(response.data)).toBe(true); + + // Check expected mock values + expect(response.data.poolAddress).toBe(TEST_POOL); + expect(response.data.baseTokenBalanceChange).toBeGreaterThan(0); // BUY means positive base token change + expect(response.data.quoteTokenBalanceChange).toBeLessThan(0); // BUY means negative quote token change + }); + }); + + describe('Execute Swap Endpoint', () => { + test('returns successful swap execution', async () => { + // Mock a quote-swap response to use as input for execute-swap + const quoteResponse = loadMockResponse('quote-swap'); + + // Mock a successful execution response + const executeResponse = { + signature: + '0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef', + totalInputSwapped: quoteResponse.estimatedAmountIn, + totalOutputSwapped: quoteResponse.estimatedAmountOut, + fee: 0.003, + baseTokenBalanceChange: quoteResponse.baseTokenBalanceChange, + quoteTokenBalanceChange: quoteResponse.quoteTokenBalanceChange, + }; + + // Setup mock axios for the execute-swap request + axios.post.mockResolvedValueOnce({ + status: 200, + data: executeResponse, + }); + + // Make the request + const response = await axios.post( + `http://localhost:15888/connectors/${CONNECTOR}/${PROTOCOL}/execute-swap`, + { + network: NETWORK, + baseToken: BASE_TOKEN, + quoteToken: QUOTE_TOKEN, + side: 'SELL', + amount: 1.0, + wallet: TEST_WALLET, + }, + ); + + // Validate the response + expect(response.status).toBe(200); + expect(response.data.signature).toBeDefined(); + expect(response.data.totalInputSwapped).toBe( + quoteResponse.estimatedAmountIn, + ); + expect(response.data.totalOutputSwapped).toBe( + quoteResponse.estimatedAmountOut, + ); + }); + + test('handles transaction simulation error', async () => { + // Setup mock axios with error response + axios.post.mockRejectedValueOnce({ + response: { + status: 500, + data: { + error: 'InternalServerError', + message: 'Transaction simulation failed', + code: 500, + }, + }, + }); + + // Make the request and expect it to be rejected + await expect( + axios.post( + `http://localhost:15888/connectors/${CONNECTOR}/${PROTOCOL}/execute-swap`, + { + network: NETWORK, + baseToken: BASE_TOKEN, + quoteToken: QUOTE_TOKEN, + side: 'SELL', + amount: 1000000.0, + wallet: TEST_WALLET, + }, + ), + ).rejects.toMatchObject({ + response: { + status: 500, + data: { + error: 'InternalServerError', + }, + }, + }); + }); + }); + + describe('Quote Liquidity Endpoint', () => { + test('returns and validates liquidity quote', async () => { + const mockResponse = { + poolAddress: TEST_POOL, + baseTokenLiquidity: 1.0, + quoteTokenLiquidity: 2340.5, + lpTokenAmount: 54.32, + shareOfPool: 0.0001, + }; + + // Setup mock axios + axios.get.mockResolvedValueOnce({ + status: 200, + data: mockResponse, + }); + + // Make the request + const response = await axios.get( + `http://localhost:15888/connectors/${CONNECTOR}/${PROTOCOL}/quote-liquidity`, + { + params: { + network: NETWORK, + poolAddress: TEST_POOL, + baseTokenAmount: 1.0, + quoteTokenAmount: 2340.5, + }, + }, + ); + + // Validate the response + expect(response.status).toBe(200); + expect(response.data.poolAddress).toBe(TEST_POOL); + expect(response.data.lpTokenAmount).toBeGreaterThan(0); + expect(response.data.shareOfPool).toBeGreaterThan(0); + }); + + test('handles imbalanced liquidity error', async () => { + // Setup mock axios with error response + axios.get.mockRejectedValueOnce({ + response: { + status: 400, + data: { + error: 'BadRequest', + message: 'Token amounts do not match pool ratio', + code: 400, + }, + }, + }); + + // Make the request and expect it to be rejected + await expect( + axios.get( + `http://localhost:15888/connectors/${CONNECTOR}/${PROTOCOL}/quote-liquidity`, + { + params: { + network: NETWORK, + poolAddress: TEST_POOL, + baseTokenAmount: 1.0, + quoteTokenAmount: 100.0, // Wrong ratio + }, + }, + ), + ).rejects.toMatchObject({ + response: { + status: 400, + data: { + error: 'BadRequest', + message: expect.stringContaining('ratio'), + }, + }, + }); + }); + }); + + describe('Add Liquidity Endpoint', () => { + test('returns successful liquidity addition', async () => { + const mockResponse = { + signature: + '0xabcd1234567890abcdef1234567890abcdef1234567890abcdef1234567890ab', + baseTokenAmount: 1.0, + quoteTokenAmount: 2340.5, + lpTokenAmount: 54.32, + poolAddress: TEST_POOL, + fee: 0.003, + }; + + // Setup mock axios + axios.post.mockResolvedValueOnce({ + status: 200, + data: mockResponse, + }); + + // Make the request + const response = await axios.post( + `http://localhost:15888/connectors/${CONNECTOR}/${PROTOCOL}/add-liquidity`, + { + network: NETWORK, + poolAddress: TEST_POOL, + baseTokenAmount: 1.0, + quoteTokenAmount: 2340.5, + wallet: TEST_WALLET, + }, + ); + + // Validate the response + expect(response.status).toBe(200); + expect(response.data.signature).toBeDefined(); + expect(response.data.lpTokenAmount).toBeGreaterThan(0); + expect(response.data.baseTokenAmount).toBe(1.0); + expect(response.data.quoteTokenAmount).toBe(2340.5); + }); + + test('handles insufficient balance error', async () => { + // Setup mock axios with error response + axios.post.mockRejectedValueOnce({ + response: { + status: 400, + data: { + error: 'BadRequest', + message: 'Insufficient balance for ADA', + code: 400, + }, + }, + }); + + // Make the request and expect it to be rejected + await expect( + axios.post( + `http://localhost:15888/connectors/${CONNECTOR}/${PROTOCOL}/add-liquidity`, + { + network: NETWORK, + poolAddress: TEST_POOL, + baseTokenAmount: 10000.0, // Large amount + quoteTokenAmount: 23405000.0, + wallet: TEST_WALLET, + }, + ), + ).rejects.toMatchObject({ + response: { + status: 400, + data: { + error: 'BadRequest', + message: expect.stringContaining('Insufficient balance'), + }, + }, + }); + }); + }); + + describe('Remove Liquidity Endpoint', () => { + test('returns successful liquidity removal', async () => { + const mockResponse = { + signature: + '0xdef4567890abcdef1234567890abcdef1234567890abcdef1234567890abcd12', + baseTokenAmount: 0.95, + quoteTokenAmount: 2223.475, + lpTokenAmount: 54.32, + poolAddress: TEST_POOL, + fee: 0.003, + }; + + // Setup mock axios + axios.post.mockResolvedValueOnce({ + status: 200, + data: mockResponse, + }); + + // Make the request + const response = await axios.post( + `http://localhost:15888/connectors/${CONNECTOR}/${PROTOCOL}/remove-liquidity`, + { + network: NETWORK, + poolAddress: TEST_POOL, + lpTokenAmount: 54.32, + wallet: TEST_WALLET, + }, + ); + + // Validate the response + expect(response.status).toBe(200); + expect(response.data.signature).toBeDefined(); + expect(response.data.baseTokenAmount).toBeGreaterThan(0); + expect(response.data.quoteTokenAmount).toBeGreaterThan(0); + expect(response.data.lpTokenAmount).toBe(54.32); + }); + + test('handles insufficient LP token balance error', async () => { + // Setup mock axios with error response + axios.post.mockRejectedValueOnce({ + response: { + status: 400, + data: { + error: 'BadRequest', + message: 'Insufficient LP token balance', + code: 400, + }, + }, + }); + + // Make the request and expect it to be rejected + await expect( + axios.post( + `http://localhost:15888/connectors/${CONNECTOR}/${PROTOCOL}/remove-liquidity`, + { + network: NETWORK, + poolAddress: TEST_POOL, + lpTokenAmount: 10000.0, // Large amount + wallet: TEST_WALLET, + }, + ), + ).rejects.toMatchObject({ + response: { + status: 400, + data: { + error: 'BadRequest', + message: expect.stringContaining('Insufficient LP token balance'), + }, + }, + }); + }); + }); +}); diff --git a/test/connectors/minswap/mocks/amm-pool-info-invalid.json b/test/connectors/minswap/mocks/amm-pool-info-invalid.json new file mode 100644 index 0000000000..efea079c7a --- /dev/null +++ b/test/connectors/minswap/mocks/amm-pool-info-invalid.json @@ -0,0 +1,5 @@ +{ + "statusCode": 500, + "error": "Internal Server Error", + "message": "An unexpected error occurred" +} \ No newline at end of file diff --git a/test/connectors/minswap/mocks/amm-pool-info.json b/test/connectors/minswap/mocks/amm-pool-info.json new file mode 100644 index 0000000000..391f594f24 --- /dev/null +++ b/test/connectors/minswap/mocks/amm-pool-info.json @@ -0,0 +1,14 @@ +{ + "address": "3bb0079303c57812462dec9de8fb867cef8fd3768de7f12c77f6f0dd80381d0d", + "baseTokenAddress": "lovelace", + "quoteTokenAddress": "e16c2dc8ae937e8d3790c7fd7168d7b994621ba14ca11415f39fed724d494e", + "feePct": 2, + "price": 1.40074170245e-9, + "baseTokenAmount": 8078336461, + "quoteTokenAmount": 5767184946983, + "lpMint": { + "address": "e4214b7cce62ac6fbba385d164df48e157eae5863521b4b67ca71d863bb0079303c57812462dec9de8fb867cef8fd3768de7f12c77f6f0dd80381d0d", + "decimals": 0 + }, + "poolType": "amm" +} diff --git a/test/connectors/minswap/mocks/amm-quote-liquidity-imbalanced.json b/test/connectors/minswap/mocks/amm-quote-liquidity-imbalanced.json new file mode 100644 index 0000000000..2572d620c2 --- /dev/null +++ b/test/connectors/minswap/mocks/amm-quote-liquidity-imbalanced.json @@ -0,0 +1,5 @@ +{ + "statusCode": 500, + "error": "InternalServerError", + "message": "Failed to get liquidity quote" +} \ No newline at end of file diff --git a/test/connectors/minswap/mocks/amm-quote-swap-invalid-token.json b/test/connectors/minswap/mocks/amm-quote-swap-invalid-token.json new file mode 100644 index 0000000000..3f82724284 --- /dev/null +++ b/test/connectors/minswap/mocks/amm-quote-swap-invalid-token.json @@ -0,0 +1,5 @@ +{ + "statusCode": 400, + "error": "BadRequestError", + "message": "Base token not found: INVALID" +} \ No newline at end of file diff --git a/test/connectors/minswap/mocks/amm-quote-swap-sell.json b/test/connectors/minswap/mocks/amm-quote-swap-sell.json new file mode 100644 index 0000000000..ea4da04a78 --- /dev/null +++ b/test/connectors/minswap/mocks/amm-quote-swap-sell.json @@ -0,0 +1,13 @@ +{ + "poolAddress": "3bb0079303c57812462dec9de8fb867cef8fd3768de7f12c77f6f0dd80381d0d", + "estimatedAmountIn": 10000, + "estimatedAmountOut": 0.000013, + "minAmountOut": 0.000012, + "maxAmountIn": 10000, + "baseTokenBalanceChange": -10000, + "quoteTokenBalanceChange": 0.000013, + "price": 1.2999999999999999e-9, + "gasPrice": 0, + "gasLimit": 0, + "gasCost": 0 +} diff --git a/test/connectors/minswap/mocks/amm-quote-swap.json b/test/connectors/minswap/mocks/amm-quote-swap.json new file mode 100644 index 0000000000..6aef02cd97 --- /dev/null +++ b/test/connectors/minswap/mocks/amm-quote-swap.json @@ -0,0 +1,13 @@ +{ + "poolAddress": "3bb0079303c57812462dec9de8fb867cef8fd3768de7f12c77f6f0dd80381d0d", + "estimatedAmountIn": 14.07397, + "estimatedAmountOut": 10000000000, + "minAmountOut": 10000000000, + "maxAmountIn": 14.214709, + "baseTokenBalanceChange": 10000000000, + "quoteTokenBalanceChange": -14.07397, + "price": 1.407397e-9, + "gasPrice": 0, + "gasLimit": 0, + "gasCost": 0 +} diff --git a/test/connectors/minswap/mocks/execute-swap.json b/test/connectors/minswap/mocks/execute-swap.json new file mode 100644 index 0000000000..3527bf289c --- /dev/null +++ b/test/connectors/minswap/mocks/execute-swap.json @@ -0,0 +1,8 @@ +{ + "signature": "42b6c00a78b2ace7e3512a7c3a289c804baf8005f77a77a2254ace5740b33658", + "totalInputSwapped": 10000000, + "totalOutputSwapped": 10000000, + "fee": 192781, + "baseTokenBalanceChange": -10000000, + "quoteTokenBalanceChange": 10000000 +} diff --git a/test/connectors/minswap/mocks/quote-swap.json b/test/connectors/minswap/mocks/quote-swap.json new file mode 100644 index 0000000000..3fa95931c7 --- /dev/null +++ b/test/connectors/minswap/mocks/quote-swap.json @@ -0,0 +1,12 @@ +{ + "estimatedAmountIn": 1.0, + "estimatedAmountOut": 1800.0, + "minAmountOut": 1782.0, + "maxAmountIn": 1.0, + "price": 1800.0, + "baseTokenBalanceChange": -1.0, + "quoteTokenBalanceChange": 1800.0, + "gasPrice": 5.0, + "gasLimit": 250000, + "gasCost": 0.00125 +} \ No newline at end of file diff --git a/test/connectors/sundaeswap/amm.test.js b/test/connectors/sundaeswap/amm.test.js new file mode 100644 index 0000000000..5a87e807d2 --- /dev/null +++ b/test/connectors/sundaeswap/amm.test.js @@ -0,0 +1,541 @@ +const fs = require('fs'); +const path = require('path'); + +const { test, describe, expect, beforeEach } = require('@jest/globals'); +const axios = require('axios'); + +// Constants for this test file +const CONNECTOR = 'sundaeswap'; +const PROTOCOL = 'amm'; +const CHAIN = 'cardano'; +const NETWORK = 'preview'; +const BASE_TOKEN = 'ADA'; +const QUOTE_TOKEN = 'SBERRY'; +const TEST_POOL = '2baab4c73a1cd60176f903a29a9c92ed4237c88622da51e9179121a3'; +const TEST_WALLET = + 'addr_test1vz5x8hgp7tunnvm33m9mp4pwdxr3vrd5k03r4dq4yuh3znsyp3sum'; + +// Mock API calls (axios.get and axios.post) +jest.mock('axios'); + +// Mock implementation for axios +axios.get = jest.fn(); +axios.post = jest.fn(); + +// Helper to load mock responses +function loadMockResponse(filename) { + // Use mocks from the same directory + const filePath = path.join( + __dirname, + 'mocks', + `${PROTOCOL}-${filename}.json`, + ); + return JSON.parse(fs.readFileSync(filePath, 'utf8')); +} + +// Function to validate pool info response structure +function validatePoolInfo(response) { + return ( + response && + typeof response.address === 'string' && + typeof response.baseTokenAddress === 'string' && + typeof response.quoteTokenAddress === 'string' && + typeof response.feePct === 'number' && + typeof response.price === 'number' && + typeof response.baseTokenAmount === 'number' && + typeof response.quoteTokenAmount === 'number' && + response.poolType === 'amm' && + response.lpMint && + typeof response.lpMint.address === 'string' && + typeof response.lpMint.decimals === 'number' + ); +} + +// Function to validate swap quote response structure +function validateSwapQuote(response) { + return ( + response && + typeof response.estimatedAmountIn === 'number' && + typeof response.estimatedAmountOut === 'number' && + typeof response.minAmountOut === 'number' && + typeof response.maxAmountIn === 'number' && + typeof response.baseTokenBalanceChange === 'number' && + typeof response.quoteTokenBalanceChange === 'number' && + typeof response.price === 'number' + ); +} + +// Tests +describe('Sundaeswap AMM Tests (Preview Network)', () => { + beforeEach(() => { + // Reset axios mocks before each test + axios.get.mockClear(); + axios.post.mockClear(); + }); + + describe('Pool Info Endpoint', () => { + test('returns and validates pool info', async () => { + // Load mock response + const mockResponse = loadMockResponse('pool-info'); + + // Setup mock axios + axios.get.mockResolvedValueOnce({ + status: 200, + data: mockResponse, + }); + + // Make the request + const response = await axios.get( + `http://localhost:15888/connectors/${CONNECTOR}/${PROTOCOL}/pool-info`, + { + params: { + network: NETWORK, + baseToken: BASE_TOKEN, + quoteToken: QUOTE_TOKEN, + }, + }, + ); + + // Validate the response + expect(response.status).toBe(200); + expect(validatePoolInfo(response.data)).toBe(true); + + // Check expected mock values + expect(response.data.address).toBe(TEST_POOL); + expect(response.data.poolType).toBe('amm'); + + // Verify axios was called with correct parameters + expect(axios.get).toHaveBeenCalledWith( + `http://localhost:15888/connectors/${CONNECTOR}/${PROTOCOL}/pool-info`, + expect.objectContaining({ + params: expect.objectContaining({ + network: NETWORK, + baseToken: BASE_TOKEN, + quoteToken: QUOTE_TOKEN, + }), + }), + ); + }); + + test('handles error for non-existent pool', async () => { + // Setup mock axios with error response + axios.get.mockRejectedValueOnce({ + response: { + status: 404, + data: { + error: 'Pool not found', + code: 404, + }, + }, + }); + + // Make the request and expect it to be rejected + await expect( + axios.get( + `http://localhost:15888/connectors/${CONNECTOR}/${PROTOCOL}/pool-info`, + { + params: { + network: NETWORK, + baseToken: 'UNKNOWN', + quoteToken: QUOTE_TOKEN, + }, + }, + ), + ).rejects.toMatchObject({ + response: { + status: 404, + data: { + error: 'Pool not found', + }, + }, + }); + }); + }); + + describe('Quote Swap Endpoint', () => { + test('returns and validates swap quote for SELL', async () => { + // Load mock response + const mockResponse = loadMockResponse('quote-swap-sell'); + + // Setup mock axios + axios.get.mockResolvedValueOnce({ + status: 200, + data: mockResponse, + }); + + // Make the request + const response = await axios.get( + `http://localhost:15888/connectors/${CONNECTOR}/${PROTOCOL}/quote-swap`, + { + params: { + network: NETWORK, + baseToken: BASE_TOKEN, + quoteToken: QUOTE_TOKEN, + side: 'SELL', + amount: 1.0, + }, + }, + ); + + // Validate the response + expect(response.status).toBe(200); + expect(validateSwapQuote(response.data)).toBe(true); + + // Check expected mock values + expect(response.data.baseTokenBalanceChange).toBeLessThan(0); // SELL means negative base token change + expect(response.data.quoteTokenBalanceChange).toBeGreaterThan(0); // SELL means positive quote token change + + // Verify axios was called with correct parameters + expect(axios.get).toHaveBeenCalledWith( + `http://localhost:15888/connectors/${CONNECTOR}/${PROTOCOL}/quote-swap`, + expect.objectContaining({ + params: expect.objectContaining({ + network: NETWORK, + baseToken: BASE_TOKEN, + quoteToken: QUOTE_TOKEN, + side: 'SELL', + amount: 1.0, + }), + }), + ); + }); + + test('returns and validates swap quote for BUY', async () => { + // Modify the mock response for BUY direction + const mockBuyResponse = loadMockResponse('quote-swap'); + + // Setup mock axios + axios.get.mockResolvedValueOnce({ + status: 200, + data: mockBuyResponse, + }); + + // Make the request + const response = await axios.get( + `http://localhost:15888/connectors/${CONNECTOR}/${PROTOCOL}/quote-swap`, + { + params: { + network: NETWORK, + baseToken: BASE_TOKEN, + quoteToken: QUOTE_TOKEN, + side: 'BUY', + amount: 1.0, + }, + }, + ); + + // Validate the response + expect(response.status).toBe(200); + expect(validateSwapQuote(response.data)).toBe(true); + + // Check expected mock values + expect(response.data.baseTokenBalanceChange).toBeGreaterThan(0); // BUY means positive base token change + expect(response.data.quoteTokenBalanceChange).toBeLessThan(0); // BUY means negative quote token change + }); + }); + + describe('Execute Swap Endpoint', () => { + test('returns successful swap execution', async () => { + // Mock a quote-swap response to use as input for execute-swap + const quoteResponse = loadMockResponse('quote-swap'); + + // Mock a successful execution response + const executeResponse = { + signature: + '0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef', + totalInputSwapped: quoteResponse.estimatedAmountIn, + totalOutputSwapped: quoteResponse.estimatedAmountOut, + fee: 0.003, + baseTokenBalanceChange: quoteResponse.baseTokenBalanceChange, + quoteTokenBalanceChange: quoteResponse.quoteTokenBalanceChange, + }; + + // Setup mock axios for the execute-swap request + axios.post.mockResolvedValueOnce({ + status: 200, + data: executeResponse, + }); + + // Make the request + const response = await axios.post( + `http://localhost:15888/connectors/${CONNECTOR}/${PROTOCOL}/execute-swap`, + { + network: NETWORK, + baseToken: BASE_TOKEN, + quoteToken: QUOTE_TOKEN, + side: 'SELL', + amount: 1.0, + wallet: TEST_WALLET, + }, + ); + + // Validate the response + expect(response.status).toBe(200); + expect(response.data.signature).toBeDefined(); + expect(response.data.totalInputSwapped).toBe( + quoteResponse.estimatedAmountIn, + ); + expect(response.data.totalOutputSwapped).toBe( + quoteResponse.estimatedAmountOut, + ); + }); + + test('handles transaction simulation error', async () => { + // Setup mock axios with error response + axios.post.mockRejectedValueOnce({ + response: { + status: 500, + data: { + error: 'InternalServerError', + message: 'Transaction simulation failed', + code: 500, + }, + }, + }); + + // Make the request and expect it to be rejected + await expect( + axios.post( + `http://localhost:15888/connectors/${CONNECTOR}/${PROTOCOL}/execute-swap`, + { + network: NETWORK, + baseToken: BASE_TOKEN, + quoteToken: QUOTE_TOKEN, + side: 'SELL', + amount: 1000000.0, + wallet: TEST_WALLET, + }, + ), + ).rejects.toMatchObject({ + response: { + status: 500, + data: { + error: 'InternalServerError', + }, + }, + }); + }); + }); + + describe('Quote Liquidity Endpoint', () => { + test('returns and validates liquidity quote', async () => { + const mockResponse = { + poolAddress: TEST_POOL, + baseTokenLiquidity: 1.0, + quoteTokenLiquidity: 2340.5, + lpTokenAmount: 54.32, + shareOfPool: 0.0001, + }; + + // Setup mock axios + axios.get.mockResolvedValueOnce({ + status: 200, + data: mockResponse, + }); + + // Make the request + const response = await axios.get( + `http://localhost:15888/connectors/${CONNECTOR}/${PROTOCOL}/quote-liquidity`, + { + params: { + network: NETWORK, + poolAddress: TEST_POOL, + baseTokenAmount: 1.0, + quoteTokenAmount: 2340.5, + }, + }, + ); + + // Validate the response + expect(response.status).toBe(200); + expect(response.data.poolAddress).toBe(TEST_POOL); + expect(response.data.lpTokenAmount).toBeGreaterThan(0); + expect(response.data.shareOfPool).toBeGreaterThan(0); + }); + + test('handles imbalanced liquidity error', async () => { + // Setup mock axios with error response + axios.get.mockRejectedValueOnce({ + response: { + status: 400, + data: { + error: 'BadRequest', + message: 'Token amounts do not match pool ratio', + code: 400, + }, + }, + }); + + // Make the request and expect it to be rejected + await expect( + axios.get( + `http://localhost:15888/connectors/${CONNECTOR}/${PROTOCOL}/quote-liquidity`, + { + params: { + network: NETWORK, + poolAddress: TEST_POOL, + baseTokenAmount: 1.0, + quoteTokenAmount: 100.0, // Wrong ratio + }, + }, + ), + ).rejects.toMatchObject({ + response: { + status: 400, + data: { + error: 'BadRequest', + message: expect.stringContaining('ratio'), + }, + }, + }); + }); + }); + + describe('Add Liquidity Endpoint', () => { + test('returns successful liquidity addition', async () => { + const mockResponse = { + signature: + '0xabcd1234567890abcdef1234567890abcdef1234567890abcdef1234567890ab', + baseTokenAmount: 1.0, + quoteTokenAmount: 2340.5, + lpTokenAmount: 54.32, + poolAddress: TEST_POOL, + fee: 0.003, + }; + + // Setup mock axios + axios.post.mockResolvedValueOnce({ + status: 200, + data: mockResponse, + }); + + // Make the request + const response = await axios.post( + `http://localhost:15888/connectors/${CONNECTOR}/${PROTOCOL}/add-liquidity`, + { + network: NETWORK, + poolAddress: TEST_POOL, + baseTokenAmount: 1.0, + quoteTokenAmount: 2340.5, + wallet: TEST_WALLET, + }, + ); + + // Validate the response + expect(response.status).toBe(200); + expect(response.data.signature).toBeDefined(); + expect(response.data.lpTokenAmount).toBeGreaterThan(0); + expect(response.data.baseTokenAmount).toBe(1.0); + expect(response.data.quoteTokenAmount).toBe(2340.5); + }); + + test('handles insufficient balance error', async () => { + // Setup mock axios with error response + axios.post.mockRejectedValueOnce({ + response: { + status: 400, + data: { + error: 'BadRequest', + message: 'Insufficient balance for ADA', + code: 400, + }, + }, + }); + + // Make the request and expect it to be rejected + await expect( + axios.post( + `http://localhost:15888/connectors/${CONNECTOR}/${PROTOCOL}/add-liquidity`, + { + network: NETWORK, + poolAddress: TEST_POOL, + baseTokenAmount: 10000.0, // Large amount + quoteTokenAmount: 23405000.0, + wallet: TEST_WALLET, + }, + ), + ).rejects.toMatchObject({ + response: { + status: 400, + data: { + error: 'BadRequest', + message: expect.stringContaining('Insufficient balance'), + }, + }, + }); + }); + }); + + describe('Remove Liquidity Endpoint', () => { + test('returns successful liquidity removal', async () => { + const mockResponse = { + signature: + '0xdef4567890abcdef1234567890abcdef1234567890abcdef1234567890abcd12', + baseTokenAmount: 0.95, + quoteTokenAmount: 2223.475, + lpTokenAmount: 54.32, + poolAddress: TEST_POOL, + fee: 0.003, + }; + + // Setup mock axios + axios.post.mockResolvedValueOnce({ + status: 200, + data: mockResponse, + }); + + // Make the request + const response = await axios.post( + `http://localhost:15888/connectors/${CONNECTOR}/${PROTOCOL}/remove-liquidity`, + { + network: NETWORK, + poolAddress: TEST_POOL, + lpTokenAmount: 54.32, + wallet: TEST_WALLET, + }, + ); + + // Validate the response + expect(response.status).toBe(200); + expect(response.data.signature).toBeDefined(); + expect(response.data.baseTokenAmount).toBeGreaterThan(0); + expect(response.data.quoteTokenAmount).toBeGreaterThan(0); + expect(response.data.lpTokenAmount).toBe(54.32); + }); + + test('handles insufficient LP token balance error', async () => { + // Setup mock axios with error response + axios.post.mockRejectedValueOnce({ + response: { + status: 400, + data: { + error: 'BadRequest', + message: 'Insufficient LP token balance', + code: 400, + }, + }, + }); + + // Make the request and expect it to be rejected + await expect( + axios.post( + `http://localhost:15888/connectors/${CONNECTOR}/${PROTOCOL}/remove-liquidity`, + { + network: NETWORK, + poolAddress: TEST_POOL, + lpTokenAmount: 10000.0, // Large amount + wallet: TEST_WALLET, + }, + ), + ).rejects.toMatchObject({ + response: { + status: 400, + data: { + error: 'BadRequest', + message: expect.stringContaining('Insufficient LP token balance'), + }, + }, + }); + }); + }); +}); diff --git a/test/connectors/sundaeswap/mocks/amm-pool-info-invalid.json b/test/connectors/sundaeswap/mocks/amm-pool-info-invalid.json new file mode 100644 index 0000000000..efea079c7a --- /dev/null +++ b/test/connectors/sundaeswap/mocks/amm-pool-info-invalid.json @@ -0,0 +1,5 @@ +{ + "statusCode": 500, + "error": "Internal Server Error", + "message": "An unexpected error occurred" +} \ No newline at end of file diff --git a/test/connectors/sundaeswap/mocks/amm-pool-info.json b/test/connectors/sundaeswap/mocks/amm-pool-info.json new file mode 100644 index 0000000000..b1eba3c32a --- /dev/null +++ b/test/connectors/sundaeswap/mocks/amm-pool-info.json @@ -0,0 +1,14 @@ +{ + "address": "2baab4c73a1cd60176f903a29a9c92ed4237c88622da51e9179121a3", + "baseTokenAddress": "ada.lovelace", + "quoteTokenAddress": "99b071ce8580d6a3a11b4902145adb8bfd0d2a03935af8cf66403e15.534245525259", + "feePct": 0.5, + "price": 96.28482095218703, + "baseTokenAmount": 880467013, + "quoteTokenAmount": 9144401, + "lpMint": { + "address": "44a1eb2d9f58add4eb1932bd0048e6a1947e85e3fe4f32956a110414.0014df102baab4c73a1cd60176f903a29a9c92ed4237c88622da51e9179121a3", + "decimals": 0 + }, + "poolType": "amm" +} diff --git a/test/connectors/sundaeswap/mocks/amm-quote-liquidity-imbalanced.json b/test/connectors/sundaeswap/mocks/amm-quote-liquidity-imbalanced.json new file mode 100644 index 0000000000..2572d620c2 --- /dev/null +++ b/test/connectors/sundaeswap/mocks/amm-quote-liquidity-imbalanced.json @@ -0,0 +1,5 @@ +{ + "statusCode": 500, + "error": "InternalServerError", + "message": "Failed to get liquidity quote" +} \ No newline at end of file diff --git a/test/connectors/sundaeswap/mocks/amm-quote-swap-invalid-token.json b/test/connectors/sundaeswap/mocks/amm-quote-swap-invalid-token.json new file mode 100644 index 0000000000..3f82724284 --- /dev/null +++ b/test/connectors/sundaeswap/mocks/amm-quote-swap-invalid-token.json @@ -0,0 +1,5 @@ +{ + "statusCode": 400, + "error": "BadRequestError", + "message": "Base token not found: INVALID" +} \ No newline at end of file diff --git a/test/connectors/sundaeswap/mocks/amm-quote-swap-sell.json b/test/connectors/sundaeswap/mocks/amm-quote-swap-sell.json new file mode 100644 index 0000000000..ec317a0731 --- /dev/null +++ b/test/connectors/sundaeswap/mocks/amm-quote-swap-sell.json @@ -0,0 +1,12 @@ +{ + "estimatedAmountIn": 10000, + "estimatedAmountOut": 0.956992, + "minAmountOut": 0.947422, + "maxAmountIn": 10000, + "baseTokenBalanceChange": -10000, + "quoteTokenBalanceChange": 0.956992, + "price": 0.0000956992, + "gasPrice": 0, + "gasLimit": 0, + "gasCost": 0 +} diff --git a/test/connectors/sundaeswap/mocks/amm-quote-swap.json b/test/connectors/sundaeswap/mocks/amm-quote-swap.json new file mode 100644 index 0000000000..2384dd2811 --- /dev/null +++ b/test/connectors/sundaeswap/mocks/amm-quote-swap.json @@ -0,0 +1,12 @@ +{ + "estimatedAmountIn": 0.968746, + "estimatedAmountOut": 10000, + "minAmountOut": 10000, + "maxAmountIn": 0.978433, + "baseTokenBalanceChange": 10000, + "quoteTokenBalanceChange": -0.968746, + "price": 0.0000968746, + "gasPrice": 0, + "gasLimit": 0, + "gasCost": 0 +} diff --git a/test/connectors/sundaeswap/mocks/execute-swap.json b/test/connectors/sundaeswap/mocks/execute-swap.json new file mode 100644 index 0000000000..3e07d37d89 --- /dev/null +++ b/test/connectors/sundaeswap/mocks/execute-swap.json @@ -0,0 +1,8 @@ +{ + "signature": "5db28c84b78d59fbc522030e6619076c6bc2fc841cb8715a92e134d112c5573b", + "totalInputSwapped": 0.968746, + "totalOutputSwapped": 10000, + "fee": 186181, + "baseTokenBalanceChange": 10000, + "quoteTokenBalanceChange": -0.968746 +} diff --git a/test/connectors/sundaeswap/mocks/quote-swap.json b/test/connectors/sundaeswap/mocks/quote-swap.json new file mode 100644 index 0000000000..3fa95931c7 --- /dev/null +++ b/test/connectors/sundaeswap/mocks/quote-swap.json @@ -0,0 +1,12 @@ +{ + "estimatedAmountIn": 1.0, + "estimatedAmountOut": 1800.0, + "minAmountOut": 1782.0, + "maxAmountIn": 1.0, + "price": 1800.0, + "baseTokenBalanceChange": -1.0, + "quoteTokenBalanceChange": 1800.0, + "gasPrice": 5.0, + "gasLimit": 250000, + "gasCost": 0.00125 +} \ No newline at end of file