From f4eef4291da2a40ed88a094370737b4e1aeeca11 Mon Sep 17 00:00:00 2001
From: Robin <70903912+Robeartt@users.noreply.github.com>
Date: Sun, 14 Jul 2024 18:30:24 +0200
Subject: [PATCH] New UI
---
.env | 7 +
.env.production | 7 +
.env.testnet | 2 +-
.vscode/extensions.json | 7 -
.vscode/launch.json | 28 -
.vscode/settings.json | 14 -
next.config.mjs | 14 +-
package-lock.json | 670 ++++++++++++++++--
package.json | 20 +-
public/icons/Orbit_Logo.svg | 31 +
.../backstop/BackstopDepositAnvil.tsx | 2 +-
src/components/backstop/BackstopExitAnvil.tsx | 2 +-
src/components/backstop/BackstopJoinAnvil.tsx | 2 +-
.../backstop/BackstopQueueAnvil.tsx | 2 +-
src/components/backstop/BackstopQueueMod.tsx | 3 +-
src/components/borrow/BorrowAnvil.tsx | 110 ++-
src/components/borrow/BorrowPositionCard.tsx | 2 +-
src/components/common/AnvilAlert.tsx | 1 +
src/components/common/CoinSelectMenu.tsx | 113 +++
src/components/common/Divider.tsx | 5 +-
src/components/common/ReserveDropdown.tsx | 82 ++-
src/components/common/SectionBase.tsx | 2 +-
src/components/common/ToggleButton.tsx | 2 +-
src/components/common/WalletWarning.tsx | 34 +-
src/components/dashboard/PositionOverview.tsx | 1 -
src/components/lend/LendAnvil.tsx | 412 ++++++++---
src/components/lend/LendPositionCard.tsx | 2 +-
src/components/markets/MarketCard.tsx | 1 -
src/components/nav/NavBar.tsx | 28 +-
src/components/nav/NavMenu.tsx | 10 -
src/components/nav/WalletMenu.tsx | 36 +-
src/components/repay/RepayAnvil.tsx | 2 +-
.../swap/SwapCurrencyInputPanel.tsx | 51 ++
src/components/swap/styled.tsx | 45 ++
src/components/withdraw/WithdrawAnvil.tsx | 2 +-
src/contexts/wallet.tsx | 22 +-
src/functions/getCurrentTimePlusOneHour.ts | 9 +
src/helpers/aggregator/index.ts | 36 +
src/helpers/convert.ts | 170 +++++
src/helpers/utils.tsx | 205 ++++++
src/helpers/xdr/bigint-encoder.ts | 77 ++
src/helpers/xdr/errors.ts | 23 +
src/helpers/xdr/i128.ts | 17 +
src/helpers/xdr/index.ts | 1 +
src/helpers/xdr/large-int.ts | 116 +++
src/helpers/xdr/serialization/xdr-reader.ts | 86 +++
src/helpers/xdr/serialization/xdr-writer.ts | 105 +++
src/helpers/xdr/xdr-type.ts | 170 +++++
src/hooks/useRouterAddress.tsx | 25 +
src/hooks/useRouterCallback.tsx | 74 ++
src/hooks/useSwapCallback.tsx | 111 +++
src/interfaces/adminKeys.ts | 10 +
src/interfaces/currency.ts | 6 +
src/interfaces/index.ts | 3 +
src/interfaces/pairs.ts | 18 +
src/interfaces/tokens.ts | 23 +
src/layouts/DefaultLayout.tsx | 13 +-
src/pages/borrow.tsx | 84 +--
src/pages/dashboard.tsx | 50 --
src/pages/index.tsx | 140 +++-
src/pages/swap.tsx | 256 +++++++
src/pages/termsofservice.tsx | 23 -
src/services/axios.ts | 10 +
src/services/router.ts | 10 +
src/state/routing/types.ts | 301 ++++++++
src/store/blendSlice.ts | 4 +-
src/store/userSlice.ts | 2 +-
src/theme.ts | 20 +-
tsconfig.json | 3 +-
69 files changed, 3529 insertions(+), 446 deletions(-)
create mode 100644 .env
create mode 100644 .env.production
delete mode 100644 .vscode/extensions.json
delete mode 100644 .vscode/launch.json
delete mode 100644 .vscode/settings.json
create mode 100644 public/icons/Orbit_Logo.svg
create mode 100644 src/components/common/CoinSelectMenu.tsx
create mode 100644 src/components/swap/SwapCurrencyInputPanel.tsx
create mode 100644 src/components/swap/styled.tsx
create mode 100644 src/functions/getCurrentTimePlusOneHour.ts
create mode 100644 src/helpers/aggregator/index.ts
create mode 100644 src/helpers/convert.ts
create mode 100644 src/helpers/utils.tsx
create mode 100644 src/helpers/xdr/bigint-encoder.ts
create mode 100644 src/helpers/xdr/errors.ts
create mode 100644 src/helpers/xdr/i128.ts
create mode 100644 src/helpers/xdr/index.ts
create mode 100644 src/helpers/xdr/large-int.ts
create mode 100644 src/helpers/xdr/serialization/xdr-reader.ts
create mode 100644 src/helpers/xdr/serialization/xdr-writer.ts
create mode 100644 src/helpers/xdr/xdr-type.ts
create mode 100644 src/hooks/useRouterAddress.tsx
create mode 100644 src/hooks/useRouterCallback.tsx
create mode 100644 src/hooks/useSwapCallback.tsx
create mode 100644 src/interfaces/adminKeys.ts
create mode 100644 src/interfaces/currency.ts
create mode 100644 src/interfaces/index.ts
create mode 100644 src/interfaces/pairs.ts
create mode 100644 src/interfaces/tokens.ts
create mode 100644 src/pages/swap.tsx
delete mode 100644 src/pages/termsofservice.tsx
create mode 100644 src/services/axios.ts
create mode 100644 src/services/router.ts
create mode 100644 src/state/routing/types.ts
diff --git a/.env b/.env
new file mode 100644
index 0000000..69c022c
--- /dev/null
+++ b/.env
@@ -0,0 +1,7 @@
+NEXT_PUBLIC_STELLAR_EXPERT_URL=https://stellar.expert/explorer/testnet
+NEXT_PUBLIC_RPC_URL=https://soroban-testnet.stellar.org
+NEXT_PUBLIC_HORIZON_URL=https://horizon-testnet.stellar.org
+NEXT_PUBLIC_PASSPHRASE=Test SDF Network ; September 2015
+NEXT_PUBLIC_BACKSTOP=CBNRD2GEJP4Y3H3TG3TDNJFGOVBIBBL6SDQ5LUPT4LUQP62T3LLRGHPK
+NEXT_PUBLIC_USDC_ISSUER=GATALTGTWIOT6BUDBCZM3Q4OQ4BO2COLOAZ7IYSKPLC2PMSOPPGF5V56
+NEXT_PUBLIC_BLND_ISSUER=GATALTGTWIOT6BUDBCZM3Q4OQ4BO2COLOAZ7IYSKPLC2PMSOPPGF5V56
\ No newline at end of file
diff --git a/.env.production b/.env.production
new file mode 100644
index 0000000..ccfabd4
--- /dev/null
+++ b/.env.production
@@ -0,0 +1,7 @@
+NEXT_PUBLIC_STELLAR_EXPERT_URL=https://stellar.expert/explorer/public
+NEXT_PUBLIC_RPC_URL=https://soroban-rpc.creit.tech/
+NEXT_PUBLIC_HORIZON_URL=https://horizon.stellar.org
+NEXT_PUBLIC_PASSPHRASE=Public Global Stellar Network ; September 2015
+NEXT_PUBLIC_BACKSTOP=CAO3AGAMZVRMHITL36EJ2VZQWKYRPWMQAPDQD5YEOF3GIF7T44U4JAL3
+NEXT_PUBLIC_USDC_ISSUER=GA5ZSEJYB37JRC5AVCIA5MOP4RHTM335X2KGX3IHOJAPP5RE34K4KZVN
+NEXT_PUBLIC_BLND_ISSUER=GDJEHTBE6ZHUXSWFI642DCGLUOECLHPF3KSXHPXTSTJ7E3JF6MQ5EZYY
\ No newline at end of file
diff --git a/.env.testnet b/.env.testnet
index 02f0bcb..69c022c 100644
--- a/.env.testnet
+++ b/.env.testnet
@@ -4,4 +4,4 @@ NEXT_PUBLIC_HORIZON_URL=https://horizon-testnet.stellar.org
NEXT_PUBLIC_PASSPHRASE=Test SDF Network ; September 2015
NEXT_PUBLIC_BACKSTOP=CBNRD2GEJP4Y3H3TG3TDNJFGOVBIBBL6SDQ5LUPT4LUQP62T3LLRGHPK
NEXT_PUBLIC_USDC_ISSUER=GATALTGTWIOT6BUDBCZM3Q4OQ4BO2COLOAZ7IYSKPLC2PMSOPPGF5V56
-NEXT_PUBLIC_BLND_ISSUER=GBUYQYM4HJ6PRTLB77W2HNMY37KJGP5PLY367V7SYCO24NMA6TGWQOSW
\ No newline at end of file
+NEXT_PUBLIC_BLND_ISSUER=GATALTGTWIOT6BUDBCZM3Q4OQ4BO2COLOAZ7IYSKPLC2PMSOPPGF5V56
\ No newline at end of file
diff --git a/.vscode/extensions.json b/.vscode/extensions.json
deleted file mode 100644
index daaa5ee..0000000
--- a/.vscode/extensions.json
+++ /dev/null
@@ -1,7 +0,0 @@
-{
- "recommendations": [
- "arcanis.vscode-zipfs",
- "dbaeumer.vscode-eslint",
- "esbenp.prettier-vscode"
- ]
-}
diff --git a/.vscode/launch.json b/.vscode/launch.json
deleted file mode 100644
index cbb9f4a..0000000
--- a/.vscode/launch.json
+++ /dev/null
@@ -1,28 +0,0 @@
-{
- "version": "0.2.0",
- "configurations": [
- {
- "name": "Next.js: debug server-side",
- "type": "node-terminal",
- "request": "launch",
- "command": "npm run dev"
- },
- {
- "name": "Next.js: debug client-side",
- "type": "chrome",
- "request": "launch",
- "url": "http://localhost:3000"
- },
- {
- "name": "Next.js: debug full stack",
- "type": "node-terminal",
- "request": "launch",
- "command": "npm run dev",
- "serverReadyAction": {
- "pattern": "started server on .+, url: (https?://.+)",
- "uriFormat": "%s",
- "action": "debugWithChrome"
- }
- }
- ]
-}
diff --git a/.vscode/settings.json b/.vscode/settings.json
deleted file mode 100644
index a60b790..0000000
--- a/.vscode/settings.json
+++ /dev/null
@@ -1,14 +0,0 @@
-{
- "search.exclude": {
- "**/.yarn": true,
- "**/.pnp.*": true
- },
- "typescript.enablePromptUseWorkspaceTsdk": true,
- "editor.defaultFormatter": "esbenp.prettier-vscode",
- "editor.formatOnSave": true,
- "editor.tabSize": 2,
- "editor.codeActionsOnSave": {
- "source.fixAll": "explicit",
- "source.organizeImports": "explicit"
- }
-}
diff --git a/next.config.mjs b/next.config.mjs
index da19137..02f593b 100644
--- a/next.config.mjs
+++ b/next.config.mjs
@@ -7,6 +7,18 @@ const nextConfig = {
unoptimized: true, // Note: Required for static builds
},
trailingSlash: true,
+ env: {
+ BASE_URL: process.env.BASE_URL,
+ },
+ async redirects() {
+ return [
+ {
+ source: '/',
+ destination: '/borrow',
+ permanent: true,
+ },
+ ];
+ },
};
-export default nextConfig
+export default nextConfig;
diff --git a/package-lock.json b/package-lock.json
index 3fa1c64..562129e 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,27 +1,33 @@
{
"name": "blend-ui",
- "version": "1.0.0",
+ "version": "1.0.1",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "blend-ui",
- "version": "1.0.0",
+ "version": "1.0.1",
"dependencies": {
- "@blend-capital/blend-sdk": "^1.1.0",
- "@creit.tech/stellar-wallets-kit": "0.8.1",
+ "@blend-capital/blend-sdk": "1.2.0",
+ "@creit.tech/stellar-wallets-kit": "0.8.2",
"@emotion/react": "^11.9.3",
"@emotion/styled": "^11.9.3",
"@mui/icons-material": "^5.8.4",
"@mui/material": "^5.8.6",
+ "@soroban-react/contracts": "^9.1.10",
+ "@soroban-react/core": "^9.1.10",
"@stellar/freighter-api": "^2.0.0",
- "@stellar/stellar-sdk": "11.3.0",
+ "@stellar/stellar-sdk": "^12.1.0",
+ "axios": "^1.7.2",
+ "bigint-conversion": "^2.4.3",
"bignumber.js": "^9.0.2",
"copy-to-clipboard": "^3.3.3",
"next": "^12.3.4",
"react": "^18.2.0",
"react-countdown": "^2.3.5",
"react-dom": "^18.2.0",
+ "soroswap-router-sdk": "^1.2.9",
+ "swr": "^2.2.5",
"zustand": "^4.3.7"
},
"devDependencies": {
@@ -191,11 +197,11 @@
}
},
"node_modules/@blend-capital/blend-sdk": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/@blend-capital/blend-sdk/-/blend-sdk-1.1.0.tgz",
- "integrity": "sha512-kHo7isdrGzdliO90Ip4uNUMu/07MaaP1c0wB+gESJPUMYkxJ/rzsfC/QkHE1xjisKFhiBIc75wjkBG0o+D5LTw==",
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/@blend-capital/blend-sdk/-/blend-sdk-1.2.0.tgz",
+ "integrity": "sha512-6DcJ043mikVH0HfegHHUsbiOt/KfGaw3CFpcHmOMClOb9O6Biwz+Gra0ugld+XfVo0eXjYbC8CPOaCD7jVty9Q==",
"dependencies": {
- "@stellar/stellar-sdk": "11.3.0",
+ "@stellar/stellar-sdk": "12.1.0",
"buffer": "6.0.3",
"follow-redirects": ">=1.15.6"
}
@@ -210,9 +216,9 @@
}
},
"node_modules/@creit.tech/stellar-wallets-kit": {
- "version": "0.8.1",
- "resolved": "https://registry.npmjs.org/@creit.tech/stellar-wallets-kit/-/stellar-wallets-kit-0.8.1.tgz",
- "integrity": "sha512-80k3GIHdxiyzTqLAC6YVM3FgBf30xHD5jdAcRqLRumoQXikQkkQs2cvAxK58GrQtBvighlWsNkMOzprkUQ7ryw==",
+ "version": "0.8.2",
+ "resolved": "https://registry.npmjs.org/@creit.tech/stellar-wallets-kit/-/stellar-wallets-kit-0.8.2.tgz",
+ "integrity": "sha512-Uqa7ywA/vj+8+LTuDbLoE12OhFfuL/y9lziTKHv6jmmUnN9oPr1e6qiSX1kMJ+y9HOrDcj/e65kSck5Ao0i1dQ==",
"dependencies": {
"@albedo-link/intent": "0.12.0",
"@creit-tech/xbull-wallet-connect": "github:Creit-Tech/xBull-Wallet-Connect#0.2.0",
@@ -437,6 +443,11 @@
"integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==",
"dev": true
},
+ "node_modules/@juanelas/base64": {
+ "version": "1.1.5",
+ "resolved": "https://registry.npmjs.org/@juanelas/base64/-/base64-1.1.5.tgz",
+ "integrity": "sha512-mjAF27LzwfYobdwqnxZgeucbKT5wRRNvILg3h5OvCWK+3F7mw/A1tnjHnNiTYtLmTvT/bM1jA5AX7eQawDGs1w=="
+ },
"node_modules/@lit-labs/ssr-dom-shim": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/@lit-labs/ssr-dom-shim/-/ssr-dom-shim-1.2.0.tgz",
@@ -1321,6 +1332,245 @@
"integrity": "sha512-S3Kq8e7LqxkA9s7HKLqXGTGck1uwis5vAXan3FnU5yw1Ec5hsSGnq4s/UCaSqABPOnOTg7zASLyst7+ohgWexg==",
"dev": true
},
+ "node_modules/@sinonjs/commons": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz",
+ "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==",
+ "dependencies": {
+ "type-detect": "4.0.8"
+ }
+ },
+ "node_modules/@sinonjs/fake-timers": {
+ "version": "11.2.2",
+ "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-11.2.2.tgz",
+ "integrity": "sha512-G2piCSxQ7oWOxwGSAyFHfPIsyeJGXYtc6mFbnFA+kRXkiEnTl8c/8jul2S329iFBnDI9HGoeWWAZvuvOkZccgw==",
+ "dependencies": {
+ "@sinonjs/commons": "^3.0.0"
+ }
+ },
+ "node_modules/@sinonjs/samsam": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-8.0.0.tgz",
+ "integrity": "sha512-Bp8KUVlLp8ibJZrnvq2foVhP0IVX2CIprMJPK0vqGqgrDa0OHVKeZyBykqskkrdxV6yKBPmGasO8LVjAKR3Gew==",
+ "dependencies": {
+ "@sinonjs/commons": "^2.0.0",
+ "lodash.get": "^4.4.2",
+ "type-detect": "^4.0.8"
+ }
+ },
+ "node_modules/@sinonjs/samsam/node_modules/@sinonjs/commons": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-2.0.0.tgz",
+ "integrity": "sha512-uLa0j859mMrg2slwQYdO/AkrOfmH+X6LTVmNTS9CqexuE2IvVORIkSpJLqePAbEnKJ77aMmCwr1NUZ57120Xcg==",
+ "dependencies": {
+ "type-detect": "4.0.8"
+ }
+ },
+ "node_modules/@sinonjs/text-encoding": {
+ "version": "0.7.2",
+ "resolved": "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.2.tgz",
+ "integrity": "sha512-sXXKG+uL9IrKqViTtao2Ws6dy0znu9sOaP1di/jKGW1M6VssO8vlpXCQcpZ+jisQ1tTFAC5Jo/EOzFbggBagFQ=="
+ },
+ "node_modules/@soroban-react/contracts": {
+ "version": "9.1.10",
+ "resolved": "https://registry.npmjs.org/@soroban-react/contracts/-/contracts-9.1.10.tgz",
+ "integrity": "sha512-hneHC9cDiQ/MqpQ8OAz16RtEivZSdYg5rDDpjWr1QpNWSgGIcEA6J0FsLb1PYbMeKbFaskO7Rc6PD047TpiBfQ==",
+ "dependencies": {
+ "@soroban-react/core": "^9.1.10",
+ "@stellar/stellar-sdk": "11.3.0"
+ },
+ "peerDependencies": {
+ "react": ">=16.8"
+ }
+ },
+ "node_modules/@soroban-react/contracts/node_modules/@stellar/stellar-base": {
+ "version": "11.0.1",
+ "resolved": "https://registry.npmjs.org/@stellar/stellar-base/-/stellar-base-11.0.1.tgz",
+ "integrity": "sha512-VQh+1KEtFjegD6spx08+lENt8tQOkQQQZoLtqExjpRXyWlqDhEe+bXMlBTYKDc5MIynHyD42RPEib27UG17trA==",
+ "dependencies": {
+ "@stellar/js-xdr": "^3.1.1",
+ "base32.js": "^0.1.0",
+ "bignumber.js": "^9.1.2",
+ "buffer": "^6.0.3",
+ "sha.js": "^2.3.6",
+ "tweetnacl": "^1.0.3"
+ },
+ "optionalDependencies": {
+ "sodium-native": "^4.0.10"
+ }
+ },
+ "node_modules/@soroban-react/contracts/node_modules/@stellar/stellar-sdk": {
+ "version": "11.3.0",
+ "resolved": "https://registry.npmjs.org/@stellar/stellar-sdk/-/stellar-sdk-11.3.0.tgz",
+ "integrity": "sha512-i+heopibJNRA7iM8rEPz0AXphBPYvy2HDo8rxbDwWpozwCfw8kglP9cLkkhgJe8YicgLrdExz/iQZaLpqLC+6w==",
+ "dependencies": {
+ "@stellar/stellar-base": "^11.0.1",
+ "axios": "^1.6.8",
+ "bignumber.js": "^9.1.2",
+ "eventsource": "^2.0.2",
+ "randombytes": "^2.1.0",
+ "toml": "^3.0.0",
+ "urijs": "^1.19.1"
+ }
+ },
+ "node_modules/@soroban-react/core": {
+ "version": "9.1.10",
+ "resolved": "https://registry.npmjs.org/@soroban-react/core/-/core-9.1.10.tgz",
+ "integrity": "sha512-6FpdFXtyOOxl27XsNZ9PccHsYJB9z3Vmx815pqJ/nUE0PMT78BuEOhox4F56Lkpb1/YijiQ8TuN6xWoBJ29hbg==",
+ "dependencies": {
+ "@soroban-react/freighter": "^9.1.10",
+ "@soroban-react/lobstr": "^9.1.10",
+ "@soroban-react/types": "^9.1.10",
+ "@soroban-react/xbull": "^1.0.1",
+ "@stellar/stellar-sdk": "11.3.0"
+ },
+ "peerDependencies": {
+ "react": ">=16.8"
+ }
+ },
+ "node_modules/@soroban-react/core/node_modules/@stellar/stellar-base": {
+ "version": "11.0.1",
+ "resolved": "https://registry.npmjs.org/@stellar/stellar-base/-/stellar-base-11.0.1.tgz",
+ "integrity": "sha512-VQh+1KEtFjegD6spx08+lENt8tQOkQQQZoLtqExjpRXyWlqDhEe+bXMlBTYKDc5MIynHyD42RPEib27UG17trA==",
+ "dependencies": {
+ "@stellar/js-xdr": "^3.1.1",
+ "base32.js": "^0.1.0",
+ "bignumber.js": "^9.1.2",
+ "buffer": "^6.0.3",
+ "sha.js": "^2.3.6",
+ "tweetnacl": "^1.0.3"
+ },
+ "optionalDependencies": {
+ "sodium-native": "^4.0.10"
+ }
+ },
+ "node_modules/@soroban-react/core/node_modules/@stellar/stellar-sdk": {
+ "version": "11.3.0",
+ "resolved": "https://registry.npmjs.org/@stellar/stellar-sdk/-/stellar-sdk-11.3.0.tgz",
+ "integrity": "sha512-i+heopibJNRA7iM8rEPz0AXphBPYvy2HDo8rxbDwWpozwCfw8kglP9cLkkhgJe8YicgLrdExz/iQZaLpqLC+6w==",
+ "dependencies": {
+ "@stellar/stellar-base": "^11.0.1",
+ "axios": "^1.6.8",
+ "bignumber.js": "^9.1.2",
+ "eventsource": "^2.0.2",
+ "randombytes": "^2.1.0",
+ "toml": "^3.0.0",
+ "urijs": "^1.19.1"
+ }
+ },
+ "node_modules/@soroban-react/freighter": {
+ "version": "9.1.10",
+ "resolved": "https://registry.npmjs.org/@soroban-react/freighter/-/freighter-9.1.10.tgz",
+ "integrity": "sha512-fLIG3ZmCOMQg2Vd31xwv4E2Pzrjs573YBIK5Rrd9r0qoIeCBzVOxCpaYD7N1sJO53+VFxUGlYs6wtYM77TW76w==",
+ "dependencies": {
+ "@soroban-react/types": "^9.1.10",
+ "@stellar/freighter-api": "1.7.1"
+ }
+ },
+ "node_modules/@soroban-react/freighter/node_modules/@stellar/freighter-api": {
+ "version": "1.7.1",
+ "resolved": "https://registry.npmjs.org/@stellar/freighter-api/-/freighter-api-1.7.1.tgz",
+ "integrity": "sha512-XvPO+XgEbkeP0VhP0U1edOkds+rGS28+y8GRGbCVXeZ9ZslbWqRFQoETAdX8IXGuykk2ib/aPokiLc5ZaWYP7w=="
+ },
+ "node_modules/@soroban-react/lobstr": {
+ "version": "9.1.10",
+ "resolved": "https://registry.npmjs.org/@soroban-react/lobstr/-/lobstr-9.1.10.tgz",
+ "integrity": "sha512-1HP64JbNA5C+kbCud4c+dufX439EeNfkpxhscUOAm04/j8VGLUJJpZecwi05BBlEaOB7SEIUl6+OA55ubht0Nw==",
+ "dependencies": {
+ "@lobstrco/signer-extension-api": "^1.0.0-beta.0",
+ "@soroban-react/types": "^9.1.10",
+ "@stellar/stellar-sdk": "11.3.0"
+ },
+ "peerDependencies": {
+ "react": ">=16.8"
+ }
+ },
+ "node_modules/@soroban-react/lobstr/node_modules/@stellar/stellar-base": {
+ "version": "11.0.1",
+ "resolved": "https://registry.npmjs.org/@stellar/stellar-base/-/stellar-base-11.0.1.tgz",
+ "integrity": "sha512-VQh+1KEtFjegD6spx08+lENt8tQOkQQQZoLtqExjpRXyWlqDhEe+bXMlBTYKDc5MIynHyD42RPEib27UG17trA==",
+ "dependencies": {
+ "@stellar/js-xdr": "^3.1.1",
+ "base32.js": "^0.1.0",
+ "bignumber.js": "^9.1.2",
+ "buffer": "^6.0.3",
+ "sha.js": "^2.3.6",
+ "tweetnacl": "^1.0.3"
+ },
+ "optionalDependencies": {
+ "sodium-native": "^4.0.10"
+ }
+ },
+ "node_modules/@soroban-react/lobstr/node_modules/@stellar/stellar-sdk": {
+ "version": "11.3.0",
+ "resolved": "https://registry.npmjs.org/@stellar/stellar-sdk/-/stellar-sdk-11.3.0.tgz",
+ "integrity": "sha512-i+heopibJNRA7iM8rEPz0AXphBPYvy2HDo8rxbDwWpozwCfw8kglP9cLkkhgJe8YicgLrdExz/iQZaLpqLC+6w==",
+ "dependencies": {
+ "@stellar/stellar-base": "^11.0.1",
+ "axios": "^1.6.8",
+ "bignumber.js": "^9.1.2",
+ "eventsource": "^2.0.2",
+ "randombytes": "^2.1.0",
+ "toml": "^3.0.0",
+ "urijs": "^1.19.1"
+ }
+ },
+ "node_modules/@soroban-react/types": {
+ "version": "9.1.10",
+ "resolved": "https://registry.npmjs.org/@soroban-react/types/-/types-9.1.10.tgz",
+ "integrity": "sha512-WHZ0HLZjC0+MIhtlhmrz/danPd3XE7LcRnwa1c2eyXX2tKaI+QIMBR2Qd7GYEWJ/9xJPPF2ThgGFbDqh5XXIsg==",
+ "dependencies": {
+ "@stellar/stellar-sdk": "11.3.0"
+ }
+ },
+ "node_modules/@soroban-react/types/node_modules/@stellar/stellar-base": {
+ "version": "11.0.1",
+ "resolved": "https://registry.npmjs.org/@stellar/stellar-base/-/stellar-base-11.0.1.tgz",
+ "integrity": "sha512-VQh+1KEtFjegD6spx08+lENt8tQOkQQQZoLtqExjpRXyWlqDhEe+bXMlBTYKDc5MIynHyD42RPEib27UG17trA==",
+ "dependencies": {
+ "@stellar/js-xdr": "^3.1.1",
+ "base32.js": "^0.1.0",
+ "bignumber.js": "^9.1.2",
+ "buffer": "^6.0.3",
+ "sha.js": "^2.3.6",
+ "tweetnacl": "^1.0.3"
+ },
+ "optionalDependencies": {
+ "sodium-native": "^4.0.10"
+ }
+ },
+ "node_modules/@soroban-react/types/node_modules/@stellar/stellar-sdk": {
+ "version": "11.3.0",
+ "resolved": "https://registry.npmjs.org/@stellar/stellar-sdk/-/stellar-sdk-11.3.0.tgz",
+ "integrity": "sha512-i+heopibJNRA7iM8rEPz0AXphBPYvy2HDo8rxbDwWpozwCfw8kglP9cLkkhgJe8YicgLrdExz/iQZaLpqLC+6w==",
+ "dependencies": {
+ "@stellar/stellar-base": "^11.0.1",
+ "axios": "^1.6.8",
+ "bignumber.js": "^9.1.2",
+ "eventsource": "^2.0.2",
+ "randombytes": "^2.1.0",
+ "toml": "^3.0.0",
+ "urijs": "^1.19.1"
+ }
+ },
+ "node_modules/@soroban-react/xbull": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/@soroban-react/xbull/-/xbull-1.0.1.tgz",
+ "integrity": "sha512-dk/qoF6CsRMgKWyO++woJmq5bTgo9ZCGBtGaNFOiljliQ7bX6MzvMoeZSwTvNNJZhL18AWpaiWmxCvv2bJJoQg==",
+ "dependencies": {
+ "@creit-tech/xbull-wallet-connect": "github:Creit-Tech/xBull-Wallet-Connect",
+ "@soroban-react/types": "8.0.0",
+ "stellar-sdk": "11.1.0"
+ },
+ "peerDependencies": {
+ "react": ">=16.8"
+ }
+ },
+ "node_modules/@soroban-react/xbull/node_modules/@soroban-react/types": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/@soroban-react/types/-/types-8.0.0.tgz",
+ "integrity": "sha512-t8eohOlmb4LAD1e3bfI01KKK7oCcm468QKsKrD0fL67fnZYcx9K61tSCqwWEbFCWGMGPkwaOwI3sE/bYKKDMIQ=="
+ },
"node_modules/@stablelib/aead": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@stablelib/aead/-/aead-1.0.1.tgz",
@@ -1478,9 +1728,9 @@
"integrity": "sha512-3gnPjAz78htgqsNEDkEsKHKosV2BF2iZkoHCNxpmZwUxiPsw+2VaXMed8RRMe0rGk3d5GZe7RrSba8zV80J3Ag=="
},
"node_modules/@stellar/stellar-base": {
- "version": "11.0.1",
- "resolved": "https://registry.npmjs.org/@stellar/stellar-base/-/stellar-base-11.0.1.tgz",
- "integrity": "sha512-VQh+1KEtFjegD6spx08+lENt8tQOkQQQZoLtqExjpRXyWlqDhEe+bXMlBTYKDc5MIynHyD42RPEib27UG17trA==",
+ "version": "12.0.1",
+ "resolved": "https://registry.npmjs.org/@stellar/stellar-base/-/stellar-base-12.0.1.tgz",
+ "integrity": "sha512-g6c27MNsDgEdUmoNQJn7zCWoCY50WHt0OIIOq3PhWaJRtUaT++qs1Jpb8+1bny2GmhtfRGOfPUFSyQBuHT9Mvg==",
"dependencies": {
"@stellar/js-xdr": "^3.1.1",
"base32.js": "^0.1.0",
@@ -1490,16 +1740,16 @@
"tweetnacl": "^1.0.3"
},
"optionalDependencies": {
- "sodium-native": "^4.0.10"
+ "sodium-native": "^4.1.1"
}
},
"node_modules/@stellar/stellar-sdk": {
- "version": "11.3.0",
- "resolved": "https://registry.npmjs.org/@stellar/stellar-sdk/-/stellar-sdk-11.3.0.tgz",
- "integrity": "sha512-i+heopibJNRA7iM8rEPz0AXphBPYvy2HDo8rxbDwWpozwCfw8kglP9cLkkhgJe8YicgLrdExz/iQZaLpqLC+6w==",
+ "version": "12.1.0",
+ "resolved": "https://registry.npmjs.org/@stellar/stellar-sdk/-/stellar-sdk-12.1.0.tgz",
+ "integrity": "sha512-Va0hu9SaPezmMbO5eMwL5D15Wrx1AGWRtxayUDRWV2Fr3ynY58mvCZS1vsgNQ4kE8MZe3nBVKv6T9Kzqwgx1PQ==",
"dependencies": {
- "@stellar/stellar-base": "^11.0.1",
- "axios": "^1.6.8",
+ "@stellar/stellar-base": "^12.0.1",
+ "axios": "^1.7.2",
"bignumber.js": "^9.1.2",
"eventsource": "^2.0.2",
"randombytes": "^2.1.0",
@@ -2321,9 +2571,9 @@
}
},
"node_modules/axios": {
- "version": "1.6.8",
- "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.8.tgz",
- "integrity": "sha512-v/ZHtJDU39mDpyBoFVkETcd/uNdxrWRrg3bKpOKzXFA6Bvqopts6ALSMU3y6ijYxbw2B+wPrIv46egTzJXCLGQ==",
+ "version": "1.7.2",
+ "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.2.tgz",
+ "integrity": "sha512-2A8QhOMrbomlDuiLeK9XibIBzuHeRcqqNOHp0Cyp5EoJ1IFDh+XZH3A6BkXtv0K4gFGCI0Y4BM7B1wOEi0Rmgw==",
"dependencies": {
"follow-redirects": "^1.15.6",
"form-data": "^4.0.0",
@@ -2357,7 +2607,7 @@
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
- "dev": true
+ "devOptional": true
},
"node_modules/base32.js": {
"version": "0.1.0",
@@ -2386,6 +2636,26 @@
}
]
},
+ "node_modules/big.js": {
+ "version": "6.2.1",
+ "resolved": "https://registry.npmjs.org/big.js/-/big.js-6.2.1.tgz",
+ "integrity": "sha512-bCtHMwL9LeDIozFn+oNhhFoq+yQ3BNdnsLSASUxLciOb1vgvpHsIO1dsENiGMgbb4SkP5TrzWzRiLddn8ahVOQ==",
+ "engines": {
+ "node": "*"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/bigjs"
+ }
+ },
+ "node_modules/bigint-conversion": {
+ "version": "2.4.3",
+ "resolved": "https://registry.npmjs.org/bigint-conversion/-/bigint-conversion-2.4.3.tgz",
+ "integrity": "sha512-eM76IXlhXQD6HAoE6A7QLQ3jdC04EJdjH3zrlU1Jtt4/jj+O/pMGjGR5FY8/55FOIBsK25kly0RoG4GA4iKdvg==",
+ "dependencies": {
+ "@juanelas/base64": "^1.1.2"
+ }
+ },
"node_modules/bignumber.js": {
"version": "9.1.2",
"resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.1.2.tgz",
@@ -2409,18 +2679,18 @@
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
- "dev": true,
+ "devOptional": true,
"dependencies": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
}
},
"node_modules/braces": {
- "version": "3.0.2",
- "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
- "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
+ "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
"dependencies": {
- "fill-range": "^7.0.1"
+ "fill-range": "^7.1.1"
},
"engines": {
"node": ">=8"
@@ -2449,6 +2719,23 @@
"ieee754": "^1.2.1"
}
},
+ "node_modules/bunyan": {
+ "version": "1.8.15",
+ "resolved": "https://registry.npmjs.org/bunyan/-/bunyan-1.8.15.tgz",
+ "integrity": "sha512-0tECWShh6wUysgucJcBAoYegf3JJoZWibxdqhTm7OHPeT42qdjkZ29QCMcKwbgU1kiH+auSIasNRXMLWXafXig==",
+ "engines": [
+ "node >=0.10.0"
+ ],
+ "bin": {
+ "bunyan": "bin/bunyan"
+ },
+ "optionalDependencies": {
+ "dtrace-provider": "~0.8",
+ "moment": "^2.19.3",
+ "mv": "~2",
+ "safe-json-stringify": "~1"
+ }
+ },
"node_modules/call-bind": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz",
@@ -2561,6 +2848,11 @@
"consola": "^3.2.3"
}
},
+ "node_modules/client-only": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz",
+ "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA=="
+ },
"node_modules/clipboardy": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/clipboardy/-/clipboardy-4.0.0.tgz",
@@ -2626,7 +2918,7 @@
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
"integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
- "dev": true
+ "devOptional": true
},
"node_modules/confbox": {
"version": "0.1.7",
@@ -2787,6 +3079,11 @@
"node": ">=0.10.0"
}
},
+ "node_modules/decimal.js-light": {
+ "version": "2.5.1",
+ "resolved": "https://registry.npmjs.org/decimal.js-light/-/decimal.js-light-2.5.1.tgz",
+ "integrity": "sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg=="
+ },
"node_modules/decode-uri-component": {
"version": "0.2.2",
"resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.2.tgz",
@@ -2878,6 +3175,14 @@
"node": ">=0.10"
}
},
+ "node_modules/diff": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/diff/-/diff-5.2.0.tgz",
+ "integrity": "sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==",
+ "engines": {
+ "node": ">=0.3.1"
+ }
+ },
"node_modules/dijkstrajs": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/dijkstrajs/-/dijkstrajs-1.0.3.tgz",
@@ -2916,6 +3221,30 @@
"csstype": "^3.0.2"
}
},
+ "node_modules/dotenv": {
+ "version": "16.4.5",
+ "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.5.tgz",
+ "integrity": "sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://dotenvx.com"
+ }
+ },
+ "node_modules/dtrace-provider": {
+ "version": "0.8.8",
+ "resolved": "https://registry.npmjs.org/dtrace-provider/-/dtrace-provider-0.8.8.tgz",
+ "integrity": "sha512-b7Z7cNtHPhH9EJhNNbbeqTcXB8LGFFZhq1PGgEvpeHlzd36bhbdTWoE/Ba/YguqpBSlAPKnARWhVlhunCMwfxg==",
+ "hasInstallScript": true,
+ "optional": true,
+ "dependencies": {
+ "nan": "^2.14.0"
+ },
+ "engines": {
+ "node": ">=0.10"
+ }
+ },
"node_modules/duplexify": {
"version": "4.1.3",
"resolved": "https://registry.npmjs.org/duplexify/-/duplexify-4.1.3.tgz",
@@ -3686,9 +4015,9 @@
}
},
"node_modules/fill-range": {
- "version": "7.0.1",
- "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
- "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
+ "version": "7.1.1",
+ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
+ "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
"dependencies": {
"to-regex-range": "^5.0.1"
},
@@ -4044,7 +4373,6 @@
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
- "dev": true,
"engines": {
"node": ">=8"
}
@@ -4207,7 +4535,7 @@
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
"integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
- "dev": true,
+ "devOptional": true,
"dependencies": {
"once": "^1.3.0",
"wrappy": "1"
@@ -4725,6 +5053,11 @@
"js-yaml": "bin/js-yaml.js"
}
},
+ "node_modules/jsbi": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/jsbi/-/jsbi-4.3.0.tgz",
+ "integrity": "sha512-SnZNcinB4RIcnEyZqFPdGPVgrg2AcnykiBy0sHVJQKHYeaLUvi3Exj+iaPpLnFVkDPZIV4U0yvgC9/R4uEAZ9g=="
+ },
"node_modules/json-buffer": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz",
@@ -4775,6 +5108,11 @@
"node": ">=4.0"
}
},
+ "node_modules/just-extend": {
+ "version": "6.2.0",
+ "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-6.2.0.tgz",
+ "integrity": "sha512-cYofQu2Xpom82S6qD778jBDpwvvy39s1l/hrYij2u9AMdQcGRpaBu6kY4mVhuno5kJVi1DAz4aiphA2WI1/OAw=="
+ },
"node_modules/keyv": {
"version": "4.5.4",
"resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz",
@@ -4893,6 +5231,16 @@
"node": ">=8"
}
},
+ "node_modules/lodash": {
+ "version": "4.17.21",
+ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
+ "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
+ },
+ "node_modules/lodash.get": {
+ "version": "4.4.2",
+ "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz",
+ "integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ=="
+ },
"node_modules/lodash.isequal": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz",
@@ -4998,7 +5346,7 @@
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
- "dev": true,
+ "devOptional": true,
"dependencies": {
"brace-expansion": "^1.1.7"
},
@@ -5010,11 +5358,23 @@
"version": "1.2.8",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
"integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
- "dev": true,
+ "devOptional": true,
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/mkdirp": {
+ "version": "0.5.6",
+ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz",
+ "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==",
+ "optional": true,
+ "dependencies": {
+ "minimist": "^1.2.6"
+ },
+ "bin": {
+ "mkdirp": "bin/cmd.js"
+ }
+ },
"node_modules/mlly": {
"version": "1.7.0",
"resolved": "https://registry.npmjs.org/mlly/-/mlly-1.7.0.tgz",
@@ -5026,6 +5386,15 @@
"ufo": "^1.5.3"
}
},
+ "node_modules/moment": {
+ "version": "2.30.1",
+ "resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz",
+ "integrity": "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==",
+ "optional": true,
+ "engines": {
+ "node": "*"
+ }
+ },
"node_modules/motion": {
"version": "10.16.2",
"resolved": "https://registry.npmjs.org/motion/-/motion-10.16.2.tgz",
@@ -5058,6 +5427,56 @@
"resolved": "https://registry.npmjs.org/multiformats/-/multiformats-9.9.0.tgz",
"integrity": "sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg=="
},
+ "node_modules/mv": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/mv/-/mv-2.1.1.tgz",
+ "integrity": "sha512-at/ZndSy3xEGJ8i0ygALh8ru9qy7gWW1cmkaqBN29JmMlIvM//MEO9y1sk/avxuwnPcfhkejkLsuPxH81BrkSg==",
+ "optional": true,
+ "dependencies": {
+ "mkdirp": "~0.5.1",
+ "ncp": "~2.0.0",
+ "rimraf": "~2.4.0"
+ },
+ "engines": {
+ "node": ">=0.8.0"
+ }
+ },
+ "node_modules/mv/node_modules/glob": {
+ "version": "6.0.4",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-6.0.4.tgz",
+ "integrity": "sha512-MKZeRNyYZAVVVG1oZeLaWie1uweH40m9AZwIwxyPbTSX4hHrVYSzLg0Ro5Z5R7XKkIX+Cc6oD1rqeDJnwsB8/A==",
+ "deprecated": "Glob versions prior to v9 are no longer supported",
+ "optional": true,
+ "dependencies": {
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "2 || 3",
+ "once": "^1.3.0",
+ "path-is-absolute": "^1.0.0"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/mv/node_modules/rimraf": {
+ "version": "2.4.5",
+ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.4.5.tgz",
+ "integrity": "sha512-J5xnxTyqaiw06JjMftq7L9ouA448dw/E7dKghkP9WpKNuwmARNNg+Gk8/u5ryb9N/Yo2+z3MCwuqFK/+qPOPfQ==",
+ "deprecated": "Rimraf versions prior to v4 are no longer supported",
+ "optional": true,
+ "dependencies": {
+ "glob": "^6.0.1"
+ },
+ "bin": {
+ "rimraf": "bin.js"
+ }
+ },
+ "node_modules/nan": {
+ "version": "2.20.0",
+ "resolved": "https://registry.npmjs.org/nan/-/nan-2.20.0.tgz",
+ "integrity": "sha512-bk3gXBZDGILuuo/6sKtr0DQmSThYHLtNCdSdXk9YkxD/jK6X2vmCyyXBBxyqZ4XcnzTyYEAThfX3DCEnLf6igw==",
+ "optional": true
+ },
"node_modules/nanoid": {
"version": "3.3.7",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz",
@@ -5081,6 +5500,15 @@
"integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==",
"dev": true
},
+ "node_modules/ncp": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ncp/-/ncp-2.0.0.tgz",
+ "integrity": "sha512-zIdGUrPRFTUELUvr3Gmc7KZ2Sw/h1PiVM0Af/oHB6zgnV1ikqSfRk+TOufi79aHYCW3NiOXmr1BP5nWbzojLaA==",
+ "optional": true,
+ "bin": {
+ "ncp": "bin/ncp"
+ }
+ },
"node_modules/next": {
"version": "12.3.4",
"resolved": "https://registry.npmjs.org/next/-/next-12.3.4.tgz",
@@ -5133,6 +5561,18 @@
}
}
},
+ "node_modules/nise": {
+ "version": "5.1.9",
+ "resolved": "https://registry.npmjs.org/nise/-/nise-5.1.9.tgz",
+ "integrity": "sha512-qOnoujW4SV6e40dYxJOb3uvuoPHtmLzIk4TFo+j0jPJoC+5Z9xja5qH5JZobEPsa8+YYphMrOSwnrshEhG2qww==",
+ "dependencies": {
+ "@sinonjs/commons": "^3.0.0",
+ "@sinonjs/fake-timers": "^11.2.2",
+ "@sinonjs/text-encoding": "^0.7.2",
+ "just-extend": "^6.2.0",
+ "path-to-regexp": "^6.2.1"
+ }
+ },
"node_modules/node-addon-api": {
"version": "7.1.0",
"resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.0.tgz",
@@ -5174,9 +5614,9 @@
}
},
"node_modules/node-gyp-build": {
- "version": "4.8.0",
- "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.0.tgz",
- "integrity": "sha512-u6fs2AEUljNho3EYTJNBfImO5QTo/J/1Etd+NVdCj7qWKUSN/bSLkZwhDv7I+w/MSC6qJ4cknepkAYykDdK8og==",
+ "version": "4.8.1",
+ "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.1.tgz",
+ "integrity": "sha512-OSs33Z9yWr148JZcbZd5WiAXhh/n9z8TxQcdMhIOlpN9AhWpLfvVFO73+m77bBABQMaY9XSvIa+qk0jlI7Gcaw==",
"optional": true,
"bin": {
"node-gyp-build": "bin.js",
@@ -5473,7 +5913,7 @@
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
"integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
- "dev": true,
+ "devOptional": true,
"engines": {
"node": ">=0.10.0"
}
@@ -5491,6 +5931,11 @@
"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
"integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw=="
},
+ "node_modules/path-to-regexp": {
+ "version": "6.2.2",
+ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.2.2.tgz",
+ "integrity": "sha512-GQX3SSMokngb36+whdpRXE+3f9V8UzyAorlYvOGx87ufGHehNTn5lCxrKtLyZ4Yl/wEKnNnr98ZzOwwDZV5ogw=="
+ },
"node_modules/path-type": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
@@ -6022,6 +6467,12 @@
}
]
},
+ "node_modules/safe-json-stringify": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/safe-json-stringify/-/safe-json-stringify-1.2.0.tgz",
+ "integrity": "sha512-gH8eh2nZudPQO6TytOvbxnuhYBOvDBBLW52tz5q6X58lJcd/tkmqFR+5Z9adS8aJtURSXWThWy/xJtJwixErvg==",
+ "optional": true
+ },
"node_modules/safe-regex-test": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.3.tgz",
@@ -6167,6 +6618,23 @@
"url": "https://github.com/sponsors/isaacs"
}
},
+ "node_modules/sinon": {
+ "version": "17.0.1",
+ "resolved": "https://registry.npmjs.org/sinon/-/sinon-17.0.1.tgz",
+ "integrity": "sha512-wmwE19Lie0MLT+ZYNpDymasPHUKTaZHUH/pKEubRXIzySv9Atnlw+BUMGCzWgV7b7wO+Hw6f1TEOr0IUnmU8/g==",
+ "dependencies": {
+ "@sinonjs/commons": "^3.0.0",
+ "@sinonjs/fake-timers": "^11.2.2",
+ "@sinonjs/samsam": "^8.0.0",
+ "diff": "^5.1.0",
+ "nise": "^5.1.5",
+ "supports-color": "^7.2.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/sinon"
+ }
+ },
"node_modules/slash": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
@@ -6194,6 +6662,56 @@
"atomic-sleep": "^1.0.0"
}
},
+ "node_modules/soroswap-router-sdk": {
+ "version": "1.2.9",
+ "resolved": "https://registry.npmjs.org/soroswap-router-sdk/-/soroswap-router-sdk-1.2.9.tgz",
+ "integrity": "sha512-rcN1KGh+gMFFTugGpbDhdsGV8ePB9IV3E7AzoeXaKr+spCU4UU0kcvpSmpG9BZwjjoQvWxf9gce7AI1KIEUDYg==",
+ "dependencies": {
+ "@stellar/stellar-sdk": "^11.3.0",
+ "axios": "^1.6.5",
+ "big.js": "^6.2.1",
+ "bigint-conversion": "^2.4.3",
+ "bignumber.js": "^9.1.2",
+ "bunyan": "^1.8.15",
+ "decimal.js-light": "^2.5.1",
+ "dotenv": "^16.4.0",
+ "jsbi": "^4.3.0",
+ "lodash": "^4.17.21",
+ "sinon": "^17.0.1",
+ "tiny-invariant": "^1.3.1",
+ "toformat": "^2.0.0"
+ }
+ },
+ "node_modules/soroswap-router-sdk/node_modules/@stellar/stellar-base": {
+ "version": "11.0.1",
+ "resolved": "https://registry.npmjs.org/@stellar/stellar-base/-/stellar-base-11.0.1.tgz",
+ "integrity": "sha512-VQh+1KEtFjegD6spx08+lENt8tQOkQQQZoLtqExjpRXyWlqDhEe+bXMlBTYKDc5MIynHyD42RPEib27UG17trA==",
+ "dependencies": {
+ "@stellar/js-xdr": "^3.1.1",
+ "base32.js": "^0.1.0",
+ "bignumber.js": "^9.1.2",
+ "buffer": "^6.0.3",
+ "sha.js": "^2.3.6",
+ "tweetnacl": "^1.0.3"
+ },
+ "optionalDependencies": {
+ "sodium-native": "^4.0.10"
+ }
+ },
+ "node_modules/soroswap-router-sdk/node_modules/@stellar/stellar-sdk": {
+ "version": "11.3.0",
+ "resolved": "https://registry.npmjs.org/@stellar/stellar-sdk/-/stellar-sdk-11.3.0.tgz",
+ "integrity": "sha512-i+heopibJNRA7iM8rEPz0AXphBPYvy2HDo8rxbDwWpozwCfw8kglP9cLkkhgJe8YicgLrdExz/iQZaLpqLC+6w==",
+ "dependencies": {
+ "@stellar/stellar-base": "^11.0.1",
+ "axios": "^1.6.8",
+ "bignumber.js": "^9.1.2",
+ "eventsource": "^2.0.2",
+ "randombytes": "^2.1.0",
+ "toml": "^3.0.0",
+ "urijs": "^1.19.1"
+ }
+ },
"node_modules/source-map": {
"version": "0.5.7",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
@@ -6231,6 +6749,37 @@
"resolved": "https://registry.npmjs.org/std-env/-/std-env-3.7.0.tgz",
"integrity": "sha512-JPbdCEQLj1w5GilpiHAx3qJvFndqybBysA3qUOnznweH4QbNYUsW/ea8QzSrnh0vNsezMMw5bcVool8lM0gwzg=="
},
+ "node_modules/stellar-sdk": {
+ "version": "11.1.0",
+ "resolved": "https://registry.npmjs.org/stellar-sdk/-/stellar-sdk-11.1.0.tgz",
+ "integrity": "sha512-fIdo77ogpU+ecHgs59pk9velpXd4F/ch0DzOI4QZw8zVZApc3oeNWP3+X6ui7BWpeRHAGsP2CHQzBLxm0JTIgg==",
+ "deprecated": "⚠️ This package has moved to @stellar/stellar-sdk! 🚚",
+ "dependencies": {
+ "@stellar/stellar-base": "10.0.1",
+ "axios": "^1.6.0",
+ "bignumber.js": "^9.1.2",
+ "eventsource": "^2.0.2",
+ "randombytes": "^2.1.0",
+ "toml": "^3.0.0",
+ "urijs": "^1.19.1"
+ }
+ },
+ "node_modules/stellar-sdk/node_modules/@stellar/stellar-base": {
+ "version": "10.0.1",
+ "resolved": "https://registry.npmjs.org/@stellar/stellar-base/-/stellar-base-10.0.1.tgz",
+ "integrity": "sha512-BDbx7VHOEQh+4J3Q+gStNXgPaNckVFmD4aOlBBGwxlF6vPFmVnW8IoJdkX7T58zpX55eWI6DXvEhDBlrqTlhAQ==",
+ "dependencies": {
+ "@stellar/js-xdr": "^3.0.1",
+ "base32.js": "^0.1.0",
+ "bignumber.js": "^9.1.2",
+ "buffer": "^6.0.3",
+ "sha.js": "^2.3.6",
+ "tweetnacl": "^1.0.3"
+ },
+ "optionalDependencies": {
+ "sodium-native": "^4.0.1"
+ }
+ },
"node_modules/stream-shift": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.3.tgz",
@@ -6416,7 +6965,6 @@
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
- "dev": true,
"dependencies": {
"has-flag": "^4.0.0"
},
@@ -6435,6 +6983,18 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/swr": {
+ "version": "2.2.5",
+ "resolved": "https://registry.npmjs.org/swr/-/swr-2.2.5.tgz",
+ "integrity": "sha512-QtxqyclFeAsxEUeZIYmsaQ0UjimSq1RZ9Un7I68/0ClKK/U3LoyQunwkQfJZr2fc22DfIXLNDc2wFyTEikCUpg==",
+ "dependencies": {
+ "client-only": "^0.0.1",
+ "use-sync-external-store": "^1.2.0"
+ },
+ "peerDependencies": {
+ "react": "^16.11.0 || ^17.0.0 || ^18.0.0"
+ }
+ },
"node_modules/system-architecture": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/system-architecture/-/system-architecture-0.1.0.tgz",
@@ -6469,6 +7029,11 @@
"real-require": "^0.1.0"
}
},
+ "node_modules/tiny-invariant": {
+ "version": "1.3.3",
+ "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.3.tgz",
+ "integrity": "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg=="
+ },
"node_modules/to-fast-properties": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz",
@@ -6488,6 +7053,11 @@
"node": ">=8.0"
}
},
+ "node_modules/toformat": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/toformat/-/toformat-2.0.0.tgz",
+ "integrity": "sha512-03SWBVop6nU8bpyZCx7SodpYznbZF5R4ljwNLBcTQzKOD9xuihRo/psX58llS1BMFhhAI08H3luot5GoXJz2pQ=="
+ },
"node_modules/toggle-selection": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/toggle-selection/-/toggle-selection-1.0.6.tgz",
@@ -6554,6 +7124,14 @@
"node": ">= 0.8.0"
}
},
+ "node_modules/type-detect": {
+ "version": "4.0.8",
+ "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz",
+ "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==",
+ "engines": {
+ "node": ">=4"
+ }
+ },
"node_modules/type-fest": {
"version": "0.20.2",
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz",
@@ -6989,9 +7567,9 @@
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="
},
"node_modules/ws": {
- "version": "7.5.9",
- "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz",
- "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==",
+ "version": "7.5.10",
+ "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz",
+ "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==",
"engines": {
"node": ">=8.3.0"
},
diff --git a/package.json b/package.json
index 863714f..f1e59eb 100644
--- a/package.json
+++ b/package.json
@@ -1,34 +1,40 @@
{
"name": "blend-ui",
- "version": "1.0.0",
+ "version": "1.0.1",
"private": true,
"type": "module",
"scripts": {
- "dev": "TARGET_ENV=testnet node loadEnv.js && next dev",
+ "dev": "next dev",
"build": "TARGET_ENV=testnet node loadEnv.js && next build",
"build:mainnet": "TARGET_ENV=production node loadEnv.js && next build",
"build:testnet": "TARGET_ENV=testnet node loadEnv.js && next build",
- "build-static": "next build && next export",
+ "build-static": "TARGET_ENV=testnet node loadEnv.js && next build && next export",
"build-static:mainnet": "TARGET_ENV=production node loadEnv.js && next build && next export",
"build-static:testnet": "TARGET_ENV=testnet node loadEnv.js && next build && next export",
"start": "next start",
"lint": "next lint"
},
"dependencies": {
- "@blend-capital/blend-sdk": "^1.1.0",
- "@creit.tech/stellar-wallets-kit": "0.8.1",
+ "@blend-capital/blend-sdk": "1.2.0",
+ "@creit.tech/stellar-wallets-kit": "0.8.2",
"@emotion/react": "^11.9.3",
"@emotion/styled": "^11.9.3",
"@mui/icons-material": "^5.8.4",
"@mui/material": "^5.8.6",
+ "@soroban-react/contracts": "^9.1.10",
+ "@soroban-react/core": "^9.1.10",
"@stellar/freighter-api": "^2.0.0",
+ "@stellar/stellar-sdk": "^12.1.0",
+ "axios": "^1.7.2",
+ "bigint-conversion": "^2.4.3",
"bignumber.js": "^9.0.2",
"copy-to-clipboard": "^3.3.3",
"next": "^12.3.4",
"react": "^18.2.0",
"react-countdown": "^2.3.5",
"react-dom": "^18.2.0",
- "@stellar/stellar-sdk": "11.3.0",
+ "soroswap-router-sdk": "^1.2.9",
+ "swr": "^2.2.5",
"zustand": "^4.3.7"
},
"devDependencies": {
@@ -42,4 +48,4 @@
"typescript": "4.7.4"
},
"packageManager": "^npm@9.5.0"
-}
\ No newline at end of file
+}
diff --git a/public/icons/Orbit_Logo.svg b/public/icons/Orbit_Logo.svg
new file mode 100644
index 0000000..c7b387d
--- /dev/null
+++ b/public/icons/Orbit_Logo.svg
@@ -0,0 +1,31 @@
+
+
\ No newline at end of file
diff --git a/src/components/backstop/BackstopDepositAnvil.tsx b/src/components/backstop/BackstopDepositAnvil.tsx
index a616129..0c35828 100644
--- a/src/components/backstop/BackstopDepositAnvil.tsx
+++ b/src/components/backstop/BackstopDepositAnvil.tsx
@@ -96,7 +96,7 @@ export const BackstopDepositAnvil: React.FC = ({ poolId }) =
borderRadius: '5px',
padding: '12px',
marginBottom: '12px',
- boxShadow: '0px 4px 4px rgba(0, 0, 0, 0.25)',
+ boxShadow: '0px 4px 4px rgba(0, 0, 0, 0.1)',
}}
>
diff --git a/src/components/backstop/BackstopExitAnvil.tsx b/src/components/backstop/BackstopExitAnvil.tsx
index 4189ca2..4038a5c 100644
--- a/src/components/backstop/BackstopExitAnvil.tsx
+++ b/src/components/backstop/BackstopExitAnvil.tsx
@@ -221,7 +221,7 @@ export const BackstopExitAnvil = () => {
borderRadius: '5px',
padding: '12px',
marginBottom: '12px',
- boxShadow: '0px 4px 4px rgba(0, 0, 0, 0.25)',
+ boxShadow: '0px 4px 4px rgba(0, 0, 0, 0.1)',
}}
>
diff --git a/src/components/backstop/BackstopJoinAnvil.tsx b/src/components/backstop/BackstopJoinAnvil.tsx
index 85c2ba0..333d858 100644
--- a/src/components/backstop/BackstopJoinAnvil.tsx
+++ b/src/components/backstop/BackstopJoinAnvil.tsx
@@ -356,7 +356,7 @@ export const BackstopJoinAnvil = () => {
borderRadius: '5px',
padding: '12px',
marginBottom: '12px',
- boxShadow: '0px 4px 4px rgba(0, 0, 0, 0.25)',
+ boxShadow: '0px 4px 4px rgba(0, 0, 0, 0.1)',
}}
>
diff --git a/src/components/backstop/BackstopQueueAnvil.tsx b/src/components/backstop/BackstopQueueAnvil.tsx
index 4ef7da6..028a895 100644
--- a/src/components/backstop/BackstopQueueAnvil.tsx
+++ b/src/components/backstop/BackstopQueueAnvil.tsx
@@ -101,7 +101,7 @@ export const BackstopQueueAnvil: React.FC = ({ poolId }) =>
borderRadius: '5px',
padding: '12px',
marginBottom: '12px',
- boxShadow: '0px 4px 4px rgba(0, 0, 0, 0.25)',
+ boxShadow: '0px 4px 4px rgba(0, 0, 0, 0.1)',
}}
>
diff --git a/src/components/backstop/BackstopQueueMod.tsx b/src/components/backstop/BackstopQueueMod.tsx
index 2b84df7..9397138 100644
--- a/src/components/backstop/BackstopQueueMod.tsx
+++ b/src/components/backstop/BackstopQueueMod.tsx
@@ -16,8 +16,7 @@ export const BackstopQueueMod: React.FC = ({ poolId }) => {
if (
!poolBackstopUserData ||
!poolBackstopUserEst ||
- poolBackstopUserData.q4w == undefined ||
- poolBackstopUserData.q4w.length == 0
+ (poolBackstopUserData.totalQ4W == BigInt(0) && poolBackstopUserData.unlockedQ4W == BigInt(0))
) {
return <>>;
}
diff --git a/src/components/borrow/BorrowAnvil.tsx b/src/components/borrow/BorrowAnvil.tsx
index 241bd9c..d705036 100644
--- a/src/components/borrow/BorrowAnvil.tsx
+++ b/src/components/borrow/BorrowAnvil.tsx
@@ -6,7 +6,7 @@ import {
SubmitArgs,
UserPositions,
} from '@blend-capital/blend-sdk';
-import { Box, CircularProgress, Typography, useTheme } from '@mui/material';
+import { Box, CircularProgress, Slider, TextField, Typography, useTheme } from '@mui/material';
import { SorobanRpc } from '@stellar/stellar-sdk';
import Image from 'next/image';
import { useMemo, useState } from 'react';
@@ -29,6 +29,10 @@ import { TxOverview } from '../common/TxOverview';
import { Value } from '../common/Value';
import { ValueChange } from '../common/ValueChange';
+const XLM_ADDRESS = 'CDLZFC3SYJYDZT7K67VZ75HPJVIEUVNIXF47ZG2FB2RMQQVU2HHGCYSC';
+
+const USDC_ADDRESS = 'CAQCFVLOBK5GIULPNZRGATJJMIZL5BSP7X5YJVMGCPTUEPFM4AVSRCJU';
+
export const BorrowAnvil: React.FC = ({ poolId, assetId }) => {
const theme = useTheme();
const { viewType } = useSettings();
@@ -41,6 +45,8 @@ export const BorrowAnvil: React.FC = ({ poolId, assetId }
const userAccount = useStore((state) => state.account);
const [toBorrow, setToBorrow] = useState('');
+ const [collateralRatio, setCollateralRatio] = useState(110);
+ const [collateralAmount, setCollateralAmount] = useState('0');
const [simResponse, setSimResponse] = useState();
const [parsedSimResult, setParsedSimResult] = useState();
const [loadingEstimate, setLoadingEstimate] = useState(false);
@@ -147,6 +153,11 @@ export const BorrowAnvil: React.FC = ({ poolId, assetId }
address: reserve.assetId,
request_type: RequestType.Borrow,
},
+ {
+ amount: scaleInputToBigInt(toBorrow, reserve.config.decimals),
+ request_type: RequestType.SupplyCollateral,
+ address: reserve.assetId,
+ },
],
};
return await poolSubmit(poolId, submitArgs, sim);
@@ -160,6 +171,24 @@ export const BorrowAnvil: React.FC = ({ poolId, assetId }
}
}
+ const handleCollateralChange = (event: any, value: number | number[]) => {
+ if (typeof value === 'number') {
+ const fixedValues = [110, 200, 300, 500];
+ const closestFixedValue = fixedValues.reduce((prev, curr) =>
+ Math.abs(curr - value) < Math.abs(prev - value) ? curr : prev
+ );
+
+ if (fixedValues.includes(value)) {
+ setCollateralRatio(value);
+ } else {
+ setCollateralRatio(value);
+ }
+
+ const newCollateralAmount = ((Number(toBorrow) * value) / 100).toFixed(2);
+ setCollateralAmount(newCollateralAmount);
+ }
+ };
+
return (
= ({ poolId, assetId }
borderRadius: '5px',
padding: '12px',
marginBottom: '12px',
- boxShadow: '0px 4px 4px rgba(0, 0, 0, 0.25)',
+ boxShadow: '0px 4px 4px rgba(0, 0, 0, 0.1)',
}}
>
@@ -196,7 +225,7 @@ export const BorrowAnvil: React.FC = ({ poolId, assetId }
setLoadingEstimate(true);
}}
palette={theme.palette.borrow}
- sx={{ width: '100%' }}
+ sx={{ width: '100%', background: '#F1F3F4' }}
>
= ({ poolId, assetId }
)}
+
+
+ Collateral Ratio
+
+
+
+
+
+
+
+
+
+ Info Fields
+
+
+
+
+
+
+
+
+
{!isError && (
{!isLoading && (
diff --git a/src/components/borrow/BorrowPositionCard.tsx b/src/components/borrow/BorrowPositionCard.tsx
index 93f2f49..6b08dc2 100644
--- a/src/components/borrow/BorrowPositionCard.tsx
+++ b/src/components/borrow/BorrowPositionCard.tsx
@@ -43,7 +43,7 @@ export const BorrowPositionCard: React.FC = ({
backgroundColor: viewType == ViewType.MOBILE ? theme.palette.background.paper : 'inherit',
padding: viewType == ViewType.MOBILE ? '1rem' : '0px',
borderRadius: viewType == ViewType.MOBILE ? '6px' : '0px',
- boxShadow: viewType === ViewType.MOBILE ? '0px 4px 4px rgba(0, 0, 0, 0.25)' : 'none',
+ boxShadow: viewType === ViewType.MOBILE ? '0px 4px 4px rgba(0, 0, 0, 0.1)' : 'none',
}}
onClick={() => {
if (viewType === ViewType.MOBILE) {
diff --git a/src/components/common/AnvilAlert.tsx b/src/components/common/AnvilAlert.tsx
index 5183532..cb3d4e9 100644
--- a/src/components/common/AnvilAlert.tsx
+++ b/src/components/common/AnvilAlert.tsx
@@ -22,6 +22,7 @@ export function AnvilAlert({ severity, message, extraContent }: AnvilAlertProps)
sx={{
display: 'flex',
justifyContent: 'flex-start',
+ background: 'white',
alignItems: !!extraContent ? 'start' : 'center',
width: '100%',
}}
diff --git a/src/components/common/CoinSelectMenu.tsx b/src/components/common/CoinSelectMenu.tsx
new file mode 100644
index 0000000..7d663cf
--- /dev/null
+++ b/src/components/common/CoinSelectMenu.tsx
@@ -0,0 +1,113 @@
+import ArrowDropDownIcon from '@mui/icons-material/ArrowDropDown';
+import { Box, Button, Icon, Menu, MenuItem, TextField, useTheme } from '@mui/material';
+import Image from 'next/image';
+import React, { useEffect } from 'react';
+
+interface CoinSelectMenuProps {
+ coins: string[];
+ selectedCoin: string;
+ onSelectCoin: (coin: string) => void;
+ amount: string;
+ onAmountChange: (amount: string) => void;
+}
+
+const coinIconPaths: { [key: string]: string } = {
+ XLM: '/icons/tokens/xlm.svg', // Sample path for XLM
+ USDC: '/icons/tokens/usdc.svg', // Sample path for USDC
+ // Add other coins and their respective paths here
+};
+
+const CoinSelectMenu: React.FC = ({
+ coins,
+ selectedCoin,
+ onSelectCoin,
+ amount,
+ onAmountChange,
+}) => {
+ const theme = useTheme();
+ const [anchorEl, setAnchorEl] = React.useState(null);
+ const open = Boolean(anchorEl);
+
+ const handleClickDropdown = (event: React.MouseEvent) => {
+ setAnchorEl(event.currentTarget);
+ };
+
+ const handleClose = () => {
+ setAnchorEl(null);
+ };
+
+ const handleSelectCoin = (coin: string) => {
+ onSelectCoin(coin);
+ handleClose();
+ };
+
+ useEffect(() => {
+ if (!coins.includes(selectedCoin)) {
+ onSelectCoin(coins[0]);
+ }
+ }, [coins, selectedCoin, onSelectCoin]);
+
+ return (
+
+
+
+
+
+ onAmountChange(e.target.value)}
+ placeholder={'Amount'}
+ fullWidth
+ sx={{
+ marginTop: '8px',
+ width: '80%',
+ '& .MuiInputBase-input': {
+ textAlign: 'right',
+ paddingRight: '10px', // Adjust this value as needed
+ },
+ }}
+ />
+
+ );
+};
+
+export default CoinSelectMenu;
diff --git a/src/components/common/Divider.tsx b/src/components/common/Divider.tsx
index 4994064..f6ffa81 100644
--- a/src/components/common/Divider.tsx
+++ b/src/components/common/Divider.tsx
@@ -5,8 +5,9 @@ export const Divider: React.FC = () => {
return (
= ({ action, poolId, act
const reserves = useStore((state) => state.pools.get(poolId)?.reserves);
const activeReserve = reserves?.get(activeReserveId);
+ useEffect(() => {
+ console.log(activeReserveId);
+ }, [activeReserve]);
+
const [anchorEl, setAnchorEl] = React.useState(null);
const open = Boolean(anchorEl);
@@ -76,29 +80,59 @@ export const ReserveDropdown: React.FC = ({ action, poolId, act
sx: { width: anchorEl && anchorEl.offsetWidth },
}}
>
- {Array.from(reserves?.values() ?? []).map((reserve) => (
-
- ))}
+ {action == 'supply'
+ ? Array.from(reserves?.values() ?? []).map(
+ (reserve) =>
+ reserve.config.l_factor == 0 && (
+
+ )
+ )
+ : Array.from(reserves?.values() ?? []).map(
+ (reserve) =>
+ reserve.config.l_factor > 0 && (
+
+ )
+ )}
>
);
diff --git a/src/components/common/SectionBase.tsx b/src/components/common/SectionBase.tsx
index 433a8c3..5b8914a 100644
--- a/src/components/common/SectionBase.tsx
+++ b/src/components/common/SectionBase.tsx
@@ -7,7 +7,7 @@ export interface SectionBaseProps extends BoxProps {
export const SectionBase: React.FC = ({ children, type, sx, ...props }) => {
const theme = useTheme();
const color = type === 'alt' ? theme.palette.background.default : theme.palette.background.paper;
- const boxShadow = type === 'alt' ? 'unset' : '0px 4px 4px rgba(0, 0, 0, 0.25);';
+ const boxShadow = type === 'alt' ? 'unset' : '0px 4px 4px rgba(0, 0, 0, 0.1);';
return (
= React.forwardRef(
variant="text"
sx={{
background: theme.palette.background.paper,
- color: theme.palette.common.white,
+ color: theme.palette.primary.main,
'&:hover': { background: theme.palette.background.paper, color: palette.main },
...sx,
}}
diff --git a/src/components/common/WalletWarning.tsx b/src/components/common/WalletWarning.tsx
index 9edbbbf..9404795 100644
--- a/src/components/common/WalletWarning.tsx
+++ b/src/components/common/WalletWarning.tsx
@@ -15,9 +15,19 @@ export const WalletWarning = () => {
const loadUserData = useStore((state) => state.loadUserData);
const [openCon, setOpenCon] = React.useState(false);
+ const [openError, setOpenError] = React.useState(false);
+
+ const handleConnectWallet = (successful: boolean) => {
+ if (successful) {
+ setOpenCon(true);
+ } else {
+ setOpenError(true);
+ }
+ };
const handleSnackClose = () => {
setOpenCon(false);
+ setOpenError(false);
};
useEffect(() => {
@@ -59,8 +69,7 @@ export const WalletWarning = () => {
) : (
{
- connect();
- setOpenCon(true);
+ connect(handleConnectWallet);
}}
palette={theme.palette.warning}
sx={{
@@ -104,6 +113,27 @@ export const WalletWarning = () => {
Wallet connected.
+
+
+ Unable to connect wallet.
+
+
>
);
};
diff --git a/src/components/dashboard/PositionOverview.tsx b/src/components/dashboard/PositionOverview.tsx
index 34cd2d1..1e9285e 100644
--- a/src/components/dashboard/PositionOverview.tsx
+++ b/src/components/dashboard/PositionOverview.tsx
@@ -246,7 +246,6 @@ export const PositionOverview: React.FC = ({ poolId }) => {
- {renderClaimButton()}
)}
>
diff --git a/src/components/lend/LendAnvil.tsx b/src/components/lend/LendAnvil.tsx
index 41eb3bf..24c7504 100644
--- a/src/components/lend/LendAnvil.tsx
+++ b/src/components/lend/LendAnvil.tsx
@@ -6,47 +6,57 @@ import {
SubmitArgs,
UserPositions,
} from '@blend-capital/blend-sdk';
-import { Box, Typography, useTheme } from '@mui/material';
+import { Box, CircularProgress, Slider, TextField, Typography, useTheme } from '@mui/material';
import { SorobanRpc } from '@stellar/stellar-sdk';
-import Image from 'next/image';
import { useMemo, useState } from 'react';
import { useSettings, ViewType } from '../../contexts';
import { TxStatus, TxType, useWallet } from '../../contexts/wallet';
import { RPC_DEBOUNCE_DELAY, useDebouncedState } from '../../hooks/debounce';
import { useStore } from '../../store/store';
-import { toBalance, toPercentage } from '../../utils/formatter';
-import { getAssetReserve } from '../../utils/horizon';
+import { toBalance } from '../../utils/formatter';
+import { requiresTrustline } from '../../utils/horizon';
import { scaleInputToBigInt } from '../../utils/scval';
-import { getErrorFromSim } from '../../utils/txSim';
+import { getErrorFromSim, SubmitError } from '../../utils/txSim';
import { AnvilAlert } from '../common/AnvilAlert';
import { InputBar } from '../common/InputBar';
import { InputButton } from '../common/InputButton';
import { OpaqueButton } from '../common/OpaqueButton';
import { ReserveComponentProps } from '../common/ReserveComponentProps';
+import { ReserveDropdown } from '../common/ReserveDropdown';
import { Row } from '../common/Row';
import { Section, SectionSize } from '../common/Section';
+import { StackedText } from '../common/StackedText';
import { TxOverview } from '../common/TxOverview';
-import { Value } from '../common/Value';
-import { ValueChange } from '../common/ValueChange';
+
+const XLM_ADDRESS = 'CDLZFC3SYJYDZT7K67VZ75HPJVIEUVNIXF47ZG2FB2RMQQVU2HHGCYSC';
+
+const OUSD_ADDRESS = 'CBGO6D5Q3SIPG6QHN2MJ5LQQ6XH2SRPKEB6PLRPS3KWDDPLBMDETEZRK';
export const LendAnvil: React.FC = ({ poolId, assetId }) => {
const theme = useTheme();
const { viewType } = useSettings();
- const { connected, walletAddress, poolSubmit, txStatus, txType, isLoading } = useWallet();
+ const { connected, walletAddress, poolSubmit, txStatus, txType, createTrustline, isLoading } =
+ useWallet();
- const account = useStore((state) => state.account);
const poolData = useStore((state) => state.pools.get(poolId));
const userPoolData = useStore((state) => state.userPoolData.get(poolId));
- const userBalance = useStore((state) => state.balances.get(assetId)) ?? BigInt(0);
+ const userAccount = useStore((state) => state.account);
- const [toLend, setToLend] = useState('');
+ const [toBorrow, setToBorrow] = useState('');
+ const [toSupply, setToSupply] = useState('');
+ const [collateralRatio, setCollateralRatio] = useState(135);
+ const [collateralAmount, setCollateralAmount] = useState('0');
const [simResponse, setSimResponse] = useState();
const [parsedSimResult, setParsedSimResult] = useState();
const [loadingEstimate, setLoadingEstimate] = useState(false);
const loading = isLoading || loadingEstimate;
- useDebouncedState(toLend, RPC_DEBOUNCE_DELAY, txType, async () => {
+ if (txStatus === TxStatus.SUCCESS && txType === TxType.CONTRACT && Number(toBorrow) != 0) {
+ setToBorrow('');
+ }
+
+ useDebouncedState(toBorrow, RPC_DEBOUNCE_DELAY, txType, async () => {
setSimResponse(undefined);
setParsedSimResult(undefined);
let response = await handleSubmitTransaction(true);
@@ -62,14 +72,25 @@ export const LendAnvil: React.FC = ({ poolId, assetId })
let newPositionEstimate =
poolData && parsedSimResult ? PositionEstimates.build(poolData, parsedSimResult) : undefined;
- const reserve = poolData?.reserves.get(assetId);
+ const reserve = poolData?.reserves.get(OUSD_ADDRESS);
+ const reserve_xlm = poolData?.reserves.get(XLM_ADDRESS);
+ const assetToXlm = reserve_xlm?.oraclePrice ?? 1;
+
const assetToBase = reserve?.oraclePrice ?? 1;
const decimals = reserve?.config.decimals ?? 7;
- const scalar = 10 ** decimals;
const symbol = reserve?.tokenMetadata?.symbol ?? '';
- const curBorrowCap = userPoolData ? userPoolData.positionEstimates.borrowCap : undefined;
- const nextBorrowCap = newPositionEstimate ? newPositionEstimate.borrowCap : undefined;
+ const assetToEffectiveLiability = reserve
+ ? assetToBase * reserve.getLiabilityFactor()
+ : undefined;
+ const curBorrowCap =
+ userPoolData && assetToEffectiveLiability
+ ? userPoolData.positionEstimates.borrowCap / assetToEffectiveLiability
+ : undefined;
+ const nextBorrowCap =
+ newPositionEstimate && assetToEffectiveLiability
+ ? newPositionEstimate.borrowCap / assetToEffectiveLiability
+ : undefined;
const curBorrowLimit =
userPoolData && Number.isFinite(userPoolData?.positionEstimates.borrowLimit)
? userPoolData?.positionEstimates?.borrowLimit
@@ -78,40 +99,87 @@ export const LendAnvil: React.FC = ({ poolId, assetId })
newPositionEstimate && Number.isFinite(newPositionEstimate?.borrowLimit)
? newPositionEstimate?.borrowLimit
: 0;
-
- // calculate current wallet state
- let stellar_reserve_amount = getAssetReserve(account, reserve?.tokenMetadata?.asset);
- const freeUserBalanceScaled = Number(userBalance) / scalar - stellar_reserve_amount;
-
- if (txStatus === TxStatus.SUCCESS && txType === TxType.CONTRACT && Number(toLend) != 0) {
- setToLend('');
- }
-
- const { isSubmitDisabled, isMaxDisabled, reason, disabledType, isError, extraContent } = useMemo(
- () => getErrorFromSim(toLend, decimals, loading, simResponse, undefined),
- [freeUserBalanceScaled, toLend, simResponse, loading]
+ const AddTrustlineButton = (
+
+ Add {reserve?.tokenMetadata.asset?.code} Trustline
+
);
- const handleLendMax = () => {
- if (userPoolData) {
- if (freeUserBalanceScaled > 0) {
- setToLend(freeUserBalanceScaled.toFixed(decimals));
- setLoadingEstimate(true);
+ const { isSubmitDisabled, isMaxDisabled, reason, disabledType, extraContent, isError } =
+ useMemo(() => {
+ const hasTokenTrustline = !requiresTrustline(userAccount, reserve?.tokenMetadata?.asset);
+ if (!hasTokenTrustline) {
+ let submitError: SubmitError = {
+ isSubmitDisabled: true,
+ isError: true,
+ isMaxDisabled: true,
+ reason: 'You need a trustline for this asset in order to borrow it.',
+ disabledType: 'warning',
+ extraContent: AddTrustlineButton,
+ };
+ return submitError;
+ } else {
+ return getErrorFromSim(toBorrow, decimals, loading, simResponse, undefined);
}
+ }, [toBorrow, simResponse, userPoolData?.positionEstimates]);
+
+ const handleBorrowMax = () => {
+ if (reserve && userPoolData) {
+ let to_bounded_hf =
+ (userPoolData.positionEstimates.totalEffectiveCollateral -
+ userPoolData.positionEstimates.totalEffectiveLiabilities * 1.02) /
+ 1.02;
+ let to_borrow = Math.min(
+ to_bounded_hf / (assetToBase * reserve.getLiabilityFactor()),
+ reserve.estimates.supplied * (reserve.config.max_util / 1e7 - 0.01) -
+ reserve.estimates.borrowed
+ );
+ setToBorrow(Math.max(to_borrow, 0).toFixed(7));
+ setLoadingEstimate(true);
}
};
+ const handleChangeBorrow = (value: string) => {
+ setToBorrow(value);
+ // calculate price of usd to xlm and apply collateral ratio
+ const supplyAmount = ((Number(value) / assetToXlm) * (collateralRatio / 100)).toFixed(7);
+ setToSupply(supplyAmount);
+ setLoadingEstimate(true);
+ };
+
+ const handleChangeSupply = (value: string) => {
+ setToSupply(value);
+ const borrowAmount = (
+ (Number(toSupply) * assetToXlm) /
+ assetToBase /
+ (collateralRatio / 100)
+ ).toFixed(7);
+ setToBorrow(borrowAmount);
+ setLoadingEstimate(true);
+ };
+
const handleSubmitTransaction = async (sim: boolean) => {
- if (toLend && connected && reserve) {
+ console.log(poolData?.reserves);
+ if (toBorrow && connected && reserve_xlm) {
let submitArgs: SubmitArgs = {
from: walletAddress,
- spender: walletAddress,
to: walletAddress,
+ spender: walletAddress,
+
requests: [
{
- amount: scaleInputToBigInt(toLend, reserve.config.decimals),
+ amount: scaleInputToBigInt(toSupply, reserve_xlm.config.decimals),
request_type: RequestType.SupplyCollateral,
- address: reserve.assetId,
+ address: XLM_ADDRESS,
+ },
+ {
+ amount: scaleInputToBigInt(toBorrow, reserve_xlm.config.decimals),
+ address: OUSD_ADDRESS,
+ request_type: RequestType.Borrow,
},
],
};
@@ -119,6 +187,24 @@ export const LendAnvil: React.FC = ({ poolId, assetId })
}
};
+ async function handleAddAssetTrustline() {
+ if (connected && reserve?.tokenMetadata?.asset) {
+ const reserveAsset = reserve?.tokenMetadata?.asset;
+ await createTrustline(reserveAsset);
+ }
+ }
+
+ const handleCollateralChange = (event: any, value: number | number[]) => {
+ if (typeof value === 'number') {
+ setCollateralRatio(value);
+
+ setToSupply(((Number(toBorrow) / assetToXlm) * (value / 100)).toFixed(2));
+
+ const newCollateralAmount = ((Number(toBorrow) * value) / 100).toFixed(2);
+ setCollateralAmount(newCollateralAmount);
+ }
+ };
+
return (
= ({ poolId, assetId })
>
+
+ {
+ handleChangeBorrow(v);
+ setLoadingEstimate(true);
+ }}
+ palette={theme.palette.borrow}
+ sx={{ width: '100%', background: '#F1F3F4' }}
+ >
+
+
+
+ {`$${toBalance(Number(toBorrow ?? 0), decimals)}`}
+
+ {viewType === ViewType.MOBILE && (
+ handleSubmitTransaction(false)}
+ palette={theme.palette.borrow}
+ sx={{ minWidth: '108px', width: '100%', padding: '6px' }}
+ disabled={isSubmitDisabled}
+ >
+ Borrow
+
+ )}
+
+
+
- Amount to supply
+ Collateral Ratio
+
+
+ {
+ setCollateralAmount(((Number(toBorrow) * collateralRatio) / 100).toFixed(2));
+ setCollateralRatio(Number(e.target.value));
+ }}
+ variant="outlined"
+ sx={{ minWidth: '120px' }}
+ />
+
+
+
+
+
+
+
= ({ poolId, assetId })
}}
>
{
- setToLend(v);
+ handleChangeSupply(v);
setLoadingEstimate(true);
}}
- sx={{ width: '100%' }}
- palette={theme.palette.lend}
+ palette={theme.palette.borrow}
+ sx={{ width: '100%', background: '#F1F3F4' }}
>
- {viewType !== ViewType.MOBILE && (
- handleSubmitTransaction(false)}
- palette={theme.palette.lend}
- sx={{ minWidth: '108px', marginLeft: '12px', padding: '6px' }}
- disabled={isSubmitDisabled}
- >
- Supply
-
- )}
-
+
- {`$${toBalance(Number(toLend ?? 0) * assetToBase, decimals)}`}
+ {`$${toBalance(Number(toSupply ?? 0) * assetToXlm, decimals)}`}
{viewType === ViewType.MOBILE && (
handleSubmitTransaction(false)}
- palette={theme.palette.lend}
+ palette={theme.palette.borrow}
sx={{ minWidth: '108px', width: '100%', padding: '6px' }}
disabled={isSubmitDisabled}
>
- Supply
+ Borrow
)}
+
{!isError && (
-
- <>
-
-
- {' '}
- Gas
- >
- }
- value={`${toBalance(
- BigInt((simResponse as any)?.minResourceFee ?? 0),
- decimals
- )} XLM`}
- />
-
-
-
- >
+
+ {!isLoading && (
+ <>
+
+
+
+
+
+
+
+
+
+ handleSubmitTransaction(false)}
+ palette={theme.palette.primary.dark}
+ sx={{ minWidth: '108px', padding: '10px' }}
+ disabled={isSubmitDisabled}
+ >
+ Borrow
+
+ >
+ )}
+ {isLoading && (
+
+
+
+ )}
)}
{isError && (
diff --git a/src/components/lend/LendPositionCard.tsx b/src/components/lend/LendPositionCard.tsx
index 2612705..a1b9370 100644
--- a/src/components/lend/LendPositionCard.tsx
+++ b/src/components/lend/LendPositionCard.tsx
@@ -46,7 +46,7 @@ export const LendPositionCard: React.FC = ({
backgroundColor: viewType == ViewType.MOBILE ? theme.palette.background.paper : 'inherit',
padding: viewType == ViewType.MOBILE ? '1rem' : '0px',
borderRadius: viewType == ViewType.MOBILE ? '6px' : '0px',
- boxShadow: viewType === ViewType.MOBILE ? '0px 4px 4px rgba(0, 0, 0, 0.25)' : 'none',
+ boxShadow: viewType === ViewType.MOBILE ? '0px 4px 4px rgba(0, 0, 0, 0.1)' : 'none',
}}
onClick={() => {
if (viewType === ViewType.MOBILE) {
diff --git a/src/components/markets/MarketCard.tsx b/src/components/markets/MarketCard.tsx
index c187c96..ba7addc 100644
--- a/src/components/markets/MarketCard.tsx
+++ b/src/components/markets/MarketCard.tsx
@@ -19,7 +19,6 @@ export const MarketCard: React.FC = ({ poolId, sx }) => {
const poolData = useStore((state) => state.pools.get(poolId));
const backstopPoolData = useStore((state) => state.backstop?.pools.get(poolId));
- console.log('poolData', useStore((state) => state.backstop));
const [expand, setExpand] = useState(false);
const [rotateArrow, setRotateArrow] = useState(false);
diff --git a/src/components/nav/NavBar.tsx b/src/components/nav/NavBar.tsx
index 128ce9e..7219976 100644
--- a/src/components/nav/NavBar.tsx
+++ b/src/components/nav/NavBar.tsx
@@ -32,16 +32,16 @@ export const NavBar = () => {
return (
-
+
-
+
{viewType === ViewType.REGULAR && (
{
}}
>
@@ -67,7 +66,14 @@ export const NavBar = () => {
)}
{viewType !== ViewType.REGULAR && (
-
+
)}
diff --git a/src/components/nav/NavMenu.tsx b/src/components/nav/NavMenu.tsx
index b91499d..8262815 100644
--- a/src/components/nav/NavMenu.tsx
+++ b/src/components/nav/NavMenu.tsx
@@ -83,11 +83,6 @@ export const NavMenu = () => {
GitHub
-
-
-
)}
{viewType !== ViewType.REGULAR && (
@@ -137,11 +132,6 @@ export const NavMenu = () => {
GitHub
-
-
-
)}
diff --git a/src/components/nav/WalletMenu.tsx b/src/components/nav/WalletMenu.tsx
index a92f45b..fb8ed3a 100644
--- a/src/components/nav/WalletMenu.tsx
+++ b/src/components/nav/WalletMenu.tsx
@@ -23,10 +23,19 @@ export const WalletMenu = () => {
const theme = useTheme();
const { connect, disconnect, connected, walletAddress, isLoading } = useWallet();
- //snackbars
+ // snackbars
const [openCon, setOpenCon] = React.useState(false);
const [openDis, setOpenDis] = React.useState(false);
const [openCopy, setOpenCopy] = React.useState(false);
+ const [openError, setOpenError] = React.useState(false);
+
+ const handleConnectWallet = (successful: boolean) => {
+ if (successful) {
+ setOpenCon(true);
+ } else {
+ setOpenError(true);
+ }
+ };
const handleDisconnectWallet = () => {
disconnect();
@@ -42,6 +51,7 @@ export const WalletMenu = () => {
setOpenCon(false);
setOpenDis(false);
setOpenCopy(false);
+ setOpenError(false);
};
const [anchorElDropdown, setAnchorElDropdown] = React.useState(null);
@@ -52,10 +62,11 @@ export const WalletMenu = () => {
};
const handleClickConnect = () => {
- connect();
+ connect(handleConnectWallet);
};
const handleClose = () => {
+ handleSnackClose();
setAnchorElDropdown(null);
};
@@ -188,6 +199,27 @@ export const WalletMenu = () => {
Wallet address copied to clipboard.
+
+
+ Unable to connect wallet.
+
+
>
);
};
diff --git a/src/components/repay/RepayAnvil.tsx b/src/components/repay/RepayAnvil.tsx
index eee301a..222cee9 100644
--- a/src/components/repay/RepayAnvil.tsx
+++ b/src/components/repay/RepayAnvil.tsx
@@ -139,7 +139,7 @@ export const RepayAnvil: React.FC = ({ poolId, assetId })
borderRadius: '5px',
padding: '12px',
marginBottom: '12px',
- boxShadow: '0px 4px 4px rgba(0, 0, 0, 0.25)',
+ boxShadow: '0px 4px 4px rgba(0, 0, 0, 0.1)',
}}
>
diff --git a/src/components/swap/SwapCurrencyInputPanel.tsx b/src/components/swap/SwapCurrencyInputPanel.tsx
new file mode 100644
index 0000000..716f195
--- /dev/null
+++ b/src/components/swap/SwapCurrencyInputPanel.tsx
@@ -0,0 +1,51 @@
+import { Box, InputBase, MenuItem, Select, Typography } from '@mui/material';
+import { TokenIcon } from '../common/TokenIcon';
+
+interface SwapCurrencyInputPanelProps {
+ label: React.ReactNode;
+ value: string;
+ onUserInput: (value: string) => void;
+ onCurrencySelect: (currency: string) => void;
+ currency: string;
+ coins: string[];
+}
+
+const SwapCurrencyInputPanel: React.FC = ({
+ label,
+ value,
+ onUserInput,
+ onCurrencySelect,
+ currency,
+ coins,
+}) => {
+ return (
+
+
+ {label}
+
+
+ onUserInput(e.target.value)}
+ sx={{
+ flexGrow: 1,
+ marginRight: '12px',
+ padding: '6px',
+ border: '1px solid #ccc',
+ borderRadius: '4px',
+ }}
+ />
+
+
+
+ );
+};
+
+export default SwapCurrencyInputPanel;
diff --git a/src/components/swap/styled.tsx b/src/components/swap/styled.tsx
new file mode 100644
index 0000000..6674dc0
--- /dev/null
+++ b/src/components/swap/styled.tsx
@@ -0,0 +1,45 @@
+import { styled } from '@mui/material/styles';
+
+export const SwapSection = styled('div')(({ theme }) => ({
+ position: 'relative',
+ backgroundColor: theme.palette.background.paper,
+ borderRadius: 12,
+ padding: 16,
+ color: theme.palette.text.primary,
+ fontSize: 14,
+ lineHeight: '20px',
+ fontWeight: 500,
+ '&:before': {
+ boxSizing: 'border-box',
+ backgroundSize: '100%',
+ borderRadius: 'inherit',
+ position: 'absolute',
+ top: 0,
+ left: 0,
+ width: '100%',
+ height: '100%',
+ pointerEvents: 'none',
+ border: `1px solid ${theme.palette.background.paper}`,
+ },
+ '&:hover:before': {
+ borderColor: theme.palette.primary.main,
+ },
+ '&:focus-within:before': {
+ borderColor: theme.palette.primary.light,
+ },
+}));
+
+export const OutputSwapSection = styled(SwapSection)`
+ border-bottom: ${({ theme }) => `1px solid ${theme.palette.background.paper}`};
+ border-radius: 16px;
+ border: 1px solid rgba(180, 239, 175, 0.2);
+ background: ${({ theme }) => theme.palette.background.default};
+`;
+
+export const ArrowContainer = styled('div')`
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ width: 100%;
+ height: 100%;
+`;
diff --git a/src/components/withdraw/WithdrawAnvil.tsx b/src/components/withdraw/WithdrawAnvil.tsx
index a53f90e..d889ab9 100644
--- a/src/components/withdraw/WithdrawAnvil.tsx
+++ b/src/components/withdraw/WithdrawAnvil.tsx
@@ -181,7 +181,7 @@ export const WithdrawAnvil: React.FC = ({ poolId, assetId
borderRadius: '5px',
padding: '12px',
marginBottom: '12px',
- boxShadow: '0px 4px 4px rgba(0, 0, 0, 0.25)',
+ boxShadow: '0px 4px 4px rgba(0, 0, 0, 0.1)',
}}
>
diff --git a/src/contexts/wallet.tsx b/src/contexts/wallet.tsx
index 5084d59..2ad09c0 100644
--- a/src/contexts/wallet.tsx
+++ b/src/contexts/wallet.tsx
@@ -46,7 +46,7 @@ export interface IWalletContext {
walletId: string | undefined;
isLoading: boolean;
- connect: () => Promise;
+ connect: (handleSuccess: (success: boolean) => void) => Promise;
disconnect: () => void;
clearLastTx: () => void;
restore: (sim: SorobanRpc.Api.SimulateTransactionRestoreResponse) => Promise;
@@ -164,37 +164,41 @@ export const WalletProvider = ({ children = null as any }) => {
/**
* Connect a wallet to the application via the walletKit
*/
- async function handleSetWalletAddress() {
+ async function handleSetWalletAddress(): Promise {
try {
const publicKey = await walletKit.getPublicKey();
+ if (publicKey === '' || publicKey == undefined) {
+ console.error('Unable to load wallet key: ', publicKey);
+ return false;
+ }
setWalletAddress(publicKey);
setConnected(true);
await loadUserData(publicKey);
- setLoading(false);
+ return true;
} catch (e: any) {
- setLoading(false);
console.error('Unable to load wallet information: ', e);
+ return false;
}
}
/**
* Open up a modal to connect the user's browser wallet
*/
- async function connect() {
+ async function connect(handleSuccess: (success: boolean) => void) {
try {
setLoading(true);
await walletKit.openModal({
onWalletSelected: async (option: ISupportedWallet) => {
walletKit.setWallet(option.id);
setAutoConnect(option.id);
- await handleSetWalletAddress();
- },
- onClosed: () => {
- setLoading(false);
+ let result = await handleSetWalletAddress();
+ handleSuccess(result);
},
});
+ setLoading(false);
} catch (e: any) {
setLoading(false);
+ handleSuccess(false);
console.error('Unable to connect wallet: ', e);
}
}
diff --git a/src/functions/getCurrentTimePlusOneHour.ts b/src/functions/getCurrentTimePlusOneHour.ts
new file mode 100644
index 0000000..33f7701
--- /dev/null
+++ b/src/functions/getCurrentTimePlusOneHour.ts
@@ -0,0 +1,9 @@
+export const getCurrentTimePlusOneHour = () => {
+ // Get the current time in milliseconds
+ const now = Date.now();
+
+ // Add one hour (3600000 milliseconds)
+ const oneHourLater = now + 3600000;
+
+ return oneHourLater;
+};
diff --git a/src/helpers/aggregator/index.ts b/src/helpers/aggregator/index.ts
new file mode 100644
index 0000000..56143c0
--- /dev/null
+++ b/src/helpers/aggregator/index.ts
@@ -0,0 +1,36 @@
+import { Address, nativeToScVal, xdr } from "@stellar/stellar-sdk";
+
+export interface DexDistribution {
+ protocol_id: string;
+ path: string[],
+ parts: number,
+ is_exact_in: boolean,
+}
+
+export const dexDistributionParser = (dexDistributionRaw: DexDistribution[]) : xdr.ScVal => {
+
+ const dexDistributionScVal = dexDistributionRaw.map((distribution) => {
+ return xdr.ScVal.scvMap([
+ new xdr.ScMapEntry({
+ key: xdr.ScVal.scvSymbol('is_exact_in'),
+ val: xdr.ScVal.scvBool(distribution.is_exact_in),
+ }),
+ new xdr.ScMapEntry({
+ key: xdr.ScVal.scvSymbol('parts'),
+ val: nativeToScVal(distribution.parts, {type: "i128"}),
+ }),
+ new xdr.ScMapEntry({
+ key: xdr.ScVal.scvSymbol('path'),
+ val: nativeToScVal(distribution.path.map((pathAddress) => new Address(pathAddress))),
+ }),
+ new xdr.ScMapEntry({
+ key: xdr.ScVal.scvSymbol('protocol_id'),
+ val: xdr.ScVal.scvString(distribution.protocol_id),
+ }),
+ ]);
+ });
+
+ return xdr.ScVal.scvVec(dexDistributionScVal)
+}
+
+export const hasDistribution = (trade: any): trade is { distribution: DexDistribution[] } => trade && 'distribution' in trade;
diff --git a/src/helpers/convert.ts b/src/helpers/convert.ts
new file mode 100644
index 0000000..ffa3021
--- /dev/null
+++ b/src/helpers/convert.ts
@@ -0,0 +1,170 @@
+import { Address, xdr } from '@stellar/stellar-sdk';
+import { bufToBigint } from 'bigint-conversion';
+import { Buffer } from 'buffer';
+import { I128 } from './xdr';
+
+export const decodei128ScVal = (value: any) => {
+ try {
+ return new I128([
+ BigInt(value.i128().lo().low),
+ BigInt(value.i128().lo().high),
+ BigInt(value.i128().hi().low),
+ BigInt(value.i128().hi().high),
+ ]).toString();
+ } catch (error) {
+ return 0;
+ }
+};
+
+export function scvalToBigInt(scval: xdr.ScVal | undefined): BigInt {
+ switch (scval?.switch()) {
+ case undefined: {
+ return BigInt(0);
+ }
+ case xdr.ScValType.scvU64(): {
+ const { high, low } = scval.u64();
+ return bufToBigint(new Uint32Array([high, low]));
+ }
+ case xdr.ScValType.scvI64(): {
+ const { high, low } = scval.i64();
+ return bufToBigint(new Int32Array([high, low]));
+ }
+ case xdr.ScValType.scvU128(): {
+ const parts = scval.u128();
+ const a = parts.hi();
+ const b = parts.lo();
+ return decodei128ScVal(scval);
+ // return bufToBigint(new Uint32Array([a.high, a.low, b.high, b.low]));
+ }
+ case xdr.ScValType.scvI128(): {
+ const parts = scval.i128();
+ const a = parts.hi();
+ const b = parts.lo();
+
+ return decodei128ScVal(scval);
+ // return bufToBigint(new Int32Array([a.high, a.low, b.high, b.low]));
+ }
+ default: {
+ throw new Error(`Invalid type for scvalToBigInt: ${scval?.switch().name}`);
+ }
+ }
+}
+
+export function strToScVal(base64Xdr: string): xdr.ScVal {
+ return xdr.ScVal.fromXDR(Buffer.from(base64Xdr, 'base64'));
+}
+
+export function scValStrToJs(base64Xdr: string): T {
+ return scValToJs(strToScVal(base64Xdr));
+}
+
+export function scValToJs(val: xdr.ScVal): T {
+ switch (val?.switch()) {
+ case xdr.ScValType.scvBool(): {
+ return val.b() as unknown as T;
+ }
+ case xdr.ScValType.scvVoid():
+ case undefined: {
+ return 0 as unknown as T;
+ }
+ case xdr.ScValType.scvU32(): {
+ return val.u32() as unknown as T;
+ }
+ case xdr.ScValType.scvI32(): {
+ return val.i32() as unknown as T;
+ }
+ case xdr.ScValType.scvU64():
+ case xdr.ScValType.scvI64():
+ case xdr.ScValType.scvU128():
+ case xdr.ScValType.scvI128():
+ case xdr.ScValType.scvU256():
+ case xdr.ScValType.scvI256(): {
+ return scvalToBigInt(val) as unknown as T;
+ }
+ case xdr.ScValType.scvAddress(): {
+ return Address.fromScVal(val).toString() as unknown as T;
+ }
+ case xdr.ScValType.scvString(): {
+ return val.str().toString() as unknown as T;
+ }
+ case xdr.ScValType.scvSymbol(): {
+ return val.sym().toString() as unknown as T;
+ }
+ case xdr.ScValType.scvBytes(): {
+ return val.bytes() as unknown as T;
+ }
+ case xdr.ScValType.scvVec(): {
+ type Element = ElementType;
+ return val?.vec()?.map((v) => scValToJs(v)) as unknown as T;
+ }
+ case xdr.ScValType.scvMap(): {
+ type Key = KeyType;
+ type Value = ValueType;
+ let res: any = {};
+ val?.map()?.forEach((e) => {
+ let key = scValToJs(e.key());
+ let value;
+ let v: xdr.ScVal = e.val();
+ // For now we assume second level maps are real maps. Not perfect but better.
+ switch (v?.switch()) {
+ case xdr.ScValType.scvMap(): {
+ let inner_map = new Map() as Map;
+ v?.map()?.forEach((e) => {
+ let key = scValToJs(e.key());
+ let value = scValToJs(e.val());
+ inner_map.set(key, value);
+ });
+ value = inner_map;
+ break;
+ }
+ default: {
+ value = scValToJs(e.val());
+ }
+ }
+ //@ts-ignore
+ res[key as Key] = value as Value;
+ });
+ return res as unknown as T;
+ }
+ case xdr.ScValType.scvContractInstance():
+ return val.instance() as unknown as T;
+ case xdr.ScValType.scvLedgerKeyNonce():
+ return val.nonceKey() as unknown as T;
+ case xdr.ScValType.scvTimepoint():
+ return val.timepoint() as unknown as T;
+ case xdr.ScValType.scvDuration():
+ return val.duration() as unknown as T;
+ // TODO: Add this case when merged
+ // case xdr.ScValType.scvError():
+ default: {
+ throw new Error(`type not implemented yet: ${val?.switch().name}`);
+ }
+ }
+}
+
+type ElementType = T extends Array ? U : never;
+type KeyType = T extends Map ? K : never;
+type ValueType = T extends Map ? V : never;
+
+export function addressToScVal(addr: string): xdr.ScVal {
+ let addrObj = Address.fromString(addr);
+ return addrObj.toScVal();
+}
+
+export function i128ToScVal(i: bigint): xdr.ScVal {
+ return xdr.ScVal.scvI128(
+ new xdr.Int128Parts({
+ lo: xdr.Uint64.fromString((i & BigInt('0xffffffffffffffff')).toString()),
+ hi: xdr.Int64.fromString(((i >> BigInt('64')) & BigInt('0xffffffffffffffff')).toString()),
+ })
+ );
+}
+
+export function u128ToScVal(i: bigint): xdr.ScVal {
+ return xdr.ScVal.scvU128(
+ new xdr.UInt128Parts({
+ lo: xdr.Uint64.fromString((i & BigInt('0xffffffffffffffff')).toString()),
+ hi: xdr.Int64.fromString(((i >> BigInt('64')) & BigInt('0xffffffffffffffff')).toString()),
+ })
+ );
+}
diff --git a/src/helpers/utils.tsx b/src/helpers/utils.tsx
new file mode 100644
index 0000000..b8b3cae
--- /dev/null
+++ b/src/helpers/utils.tsx
@@ -0,0 +1,205 @@
+import * as StellarSdk from '@stellar/stellar-sdk';
+import BigNumber from 'bignumber.js';
+import { I128 } from './xdr';
+
+let xdr = StellarSdk.xdr;
+
+export function scvalToBigNumber(scval: StellarSdk.xdr.ScVal | undefined): BigNumber {
+ switch (scval?.switch()) {
+ case undefined: {
+ return BigNumber(0);
+ }
+ case xdr.ScValType.scvU32(): {
+ return BigNumber(scval.u32());
+ }
+ case xdr.ScValType.scvI32(): {
+ return BigNumber(scval.i32());
+ }
+ case xdr.ScValType.scvU64(): {
+ const { high, low } = scval.u64();
+ return bigNumberFromBytes(false, high, low);
+ }
+ case xdr.ScValType.scvI64(): {
+ const { high, low } = scval.i64();
+ return bigNumberFromBytes(true, high, low);
+ }
+ case xdr.ScValType.scvU128(): {
+ const parts = scval.u128();
+ const hi = parts.hi();
+ const lo = parts.lo();
+ return bigNumberFromBytes(false, lo.low, lo.high, hi.low, hi.high);
+ }
+ case xdr.ScValType.scvI128(): {
+ return BigNumber(decodei128ScVal(scval));
+ }
+ case xdr.ScValType.scvU256(): {
+ const parts = scval.u256();
+ const a = parts.hiHi();
+ const b = parts.hiLo();
+ const c = parts.loHi();
+ const d = parts.loLo();
+ return bigNumberFromBytes(false, a.high, a.low, b.high, b.low, c.high, c.low, d.high, d.low);
+ }
+ case xdr.ScValType.scvI256(): {
+ const parts = scval.i256();
+ const a = parts.hiHi();
+ const b = parts.hiLo();
+ const c = parts.loHi();
+ const d = parts.loLo();
+ return bigNumberFromBytes(true, a.high, a.low, b.high, b.low, c.high, c.low, d.high, d.low);
+ }
+ default: {
+ throw new Error(`Invalid type for scvalToBigNumber: ${scval?.switch().name}`);
+ }
+ }
+}
+
+function bigNumberFromBytes(signed: boolean, ...bytes: (string | number | bigint)[]): BigNumber {
+ let sign = 1;
+ if (signed && bytes[0] === 0x80) {
+ // top bit is set, negative number.
+ sign = -1;
+ bytes[0] &= 0x7f;
+ }
+ let b = BigInt(0);
+ for (let byte of bytes) {
+ b <<= BigInt(8);
+ b |= BigInt(byte);
+ }
+ return BigNumber(b.toString()).multipliedBy(sign);
+}
+
+export function bigNumberToI128(value: BigNumber): StellarSdk.xdr.ScVal {
+ const b: bigint = BigInt(value.toFixed(0));
+ const buf = bigintToBuf(b);
+ if (buf.length > 16) {
+ throw new Error('BigNumber overflows i128');
+ }
+
+ if (value.isNegative()) {
+ // Clear the top bit
+ buf[0] &= 0x7f;
+ }
+
+ // left-pad with zeros up to 16 bytes
+ let padded = Buffer.alloc(16);
+ buf.copy(padded, padded.length - buf.length);
+
+ if (value.isNegative()) {
+ // Set the top bit
+ padded[0] |= 0x80;
+ }
+
+ const hi = new xdr.Int64([
+ bigNumberFromBytes(false, ...padded.slice(4, 8)).toNumber(),
+ bigNumberFromBytes(false, ...padded.slice(0, 4)).toNumber(),
+ ]);
+ const lo = new xdr.Uint64([
+ bigNumberFromBytes(false, ...padded.slice(12, 16)).toNumber(),
+ bigNumberFromBytes(false, ...padded.slice(8, 12)).toNumber(),
+ ]);
+
+ return xdr.ScVal.scvI128(new xdr.Int128Parts({ lo, hi }));
+}
+
+function bigintToBuf(bn: bigint): Buffer {
+ var hex = BigInt(bn).toString(16).replace(/^-/, '');
+ if (hex.length % 2) {
+ hex = '0' + hex;
+ }
+
+ var len = hex.length / 2;
+ var u8 = new Uint8Array(len);
+
+ var i = 0;
+ var j = 0;
+ while (i < len) {
+ u8[i] = parseInt(hex.slice(j, j + 2), 16);
+ i += 1;
+ j += 2;
+ }
+
+ if (bn < BigInt(0)) {
+ // Set the top bit
+ u8[0] |= 0x80;
+ }
+
+ return Buffer.from(u8);
+}
+
+export function xdrUint64ToNumber(value: StellarSdk.xdr.Uint64): number {
+ let b = 0;
+ b |= value.high;
+ b <<= 8;
+ b |= value.low;
+ return b;
+}
+
+export function scvalToString(value: StellarSdk.xdr.ScVal): string | undefined {
+ return value.bytes().toString();
+}
+
+// XDR -> String
+export const decodei128ScVal = (value: StellarSdk.xdr.ScVal) => {
+ try {
+ return new I128([
+ BigInt(value.i128().lo().low),
+ BigInt(value.i128().lo().high),
+ BigInt(value.i128().hi().low),
+ BigInt(value.i128().hi().high),
+ ]).toString();
+ } catch (error) {
+ return 0;
+ }
+};
+
+export function accountToScVal(account: string): StellarSdk.xdr.ScVal {
+ return new StellarSdk.Address(account).toScVal();
+}
+
+export function contractAddressToScVal(contractAddress: string): any {
+ return StellarSdk.Address.contract(Buffer.from(contractAddress, 'hex')).toScVal();
+}
+
+export function bigNumberToU64(value: BigNumber): StellarSdk.xdr.ScVal {
+ if (value.isNegative() || value.isGreaterThan(new BigNumber(2).pow(64).minus(1))) {
+ throw new Error('BigNumber is out of u64 range');
+ }
+
+ const b: bigint = BigInt(value.toFixed(0));
+ const buf = bigintToBuf(b);
+
+ if (buf.length > 8) {
+ throw new Error('BigNumber overflows u64');
+ }
+
+ // left-pad with zeros up to 8 bytes
+ let padded = Buffer.alloc(8);
+ buf.copy(padded, padded.length - buf.length);
+
+ // Split padded into two parts for Uint64
+ const hi = bigNumberFromBytes(false, ...padded.slice(0, 4)).toNumber();
+ const lo = bigNumberFromBytes(false, ...padded.slice(4, 8)).toNumber();
+
+ return xdr.ScVal.scvU64(new xdr.Uint64([hi, lo]));
+}
+
+export function bigNumberToU32(value: BigNumber): StellarSdk.xdr.ScVal {
+ if (value.isNegative() || value.isGreaterThan(new BigNumber(2).pow(32).minus(1))) {
+ throw new Error('BigNumber is out of u32 range');
+ }
+
+ const b: bigint = BigInt(value.toFixed(0));
+ const buf = bigintToBuf(b);
+
+ if (buf.length > 4) {
+ throw new Error('BigNumber overflows u32');
+ }
+
+ let padded = Buffer.alloc(4);
+ buf.copy(padded, padded.length - buf.length);
+
+ const num = bigNumberFromBytes(false, ...padded).toNumber();
+
+ return xdr.ScVal.scvU32(num);
+}
diff --git a/src/helpers/xdr/bigint-encoder.ts b/src/helpers/xdr/bigint-encoder.ts
new file mode 100644
index 0000000..2c5ebfc
--- /dev/null
+++ b/src/helpers/xdr/bigint-encoder.ts
@@ -0,0 +1,77 @@
+// Ported from https://github.com/stellar/js-xdr/pull/96
+// Can remove this and use them through stellar base once it is merged
+
+/* eslint-disable */
+export function encodeBigIntFromBits(parts: any[], size: number, unsigned: boolean) {
+ let result = BigInt(0);
+ // check arguments length
+ if (parts.length && parts[0] instanceof Array) {
+ parts = parts[0];
+ }
+ const total = parts.length;
+ if (total === 1) {
+ try {
+ result = BigInt(parts[0]);
+ if (!unsigned) {
+ result = BigInt.asIntN(size, result);
+ }
+ } catch (e) {
+ throw new TypeError(`Invalid integer value: ${parts[0]}`);
+ }
+ } else {
+ const sliceSize = size / total;
+ if (sliceSize !== 32 && sliceSize !== 64 && sliceSize !== 128)
+ throw new TypeError('Invalid number of arguments');
+ // combine parts
+ for (let i = 0; i < total; i++) {
+ let part = BigInt.asUintN(sliceSize, BigInt(parts[i].valueOf()));
+ if (i > 0) {
+ // shift if needed
+ part <<= BigInt(i * sliceSize);
+ }
+ result |= part;
+ }
+ if (!unsigned) {
+ // clamp value to the requested size
+ result = BigInt.asIntN(size, result);
+ }
+ }
+ // check type
+ if (typeof result === 'bigint') {
+ // check boundaries
+ const [min, max] = calculateBigIntBoundaries(size, unsigned);
+ if (result >= min && result <= max) return result;
+ }
+ // failed to encode
+ throw new TypeError(`Invalid ${formatIntName(size, unsigned)} value`);
+}
+
+export function sliceBigInt(value: BigInt, size: number, sliceSize: number) {
+ if (typeof value !== 'bigint') throw new TypeError('Invalid BigInt value');
+ const total = size / sliceSize;
+ if (total === 1) return [value];
+ if (sliceSize < 32 || sliceSize > 128 || (total !== 2 && total !== 4 && total !== 8))
+ throw new TypeError('Invalid slice size');
+ // prepare shift and mask
+ const shift = BigInt(sliceSize);
+ const mask = (BigInt(1) << shift) - BigInt(1);
+ // iterate shift and mask application
+ const result = new Array(total);
+ for (let i = 0; i < total; i++) {
+ if (i > 0) {
+ value >>= shift;
+ }
+ result[i] = BigInt.asIntN(sliceSize, value & mask); // clamp value
+ }
+ return result;
+}
+
+export function formatIntName(precision: number, unsigned: boolean) {
+ return `${unsigned ? 'u' : 'i'}${precision}`;
+}
+
+export function calculateBigIntBoundaries(size: number, unsigned: boolean) {
+ if (unsigned) return [BigInt(0), (BigInt(1) << BigInt(size)) - BigInt(1)];
+ const boundary = BigInt(1) << BigInt(size - 1);
+ return [BigInt(0) - boundary, boundary - BigInt(1)];
+}
diff --git a/src/helpers/xdr/errors.ts b/src/helpers/xdr/errors.ts
new file mode 100644
index 0000000..261b578
--- /dev/null
+++ b/src/helpers/xdr/errors.ts
@@ -0,0 +1,23 @@
+export class XdrWriterError extends TypeError {
+ constructor(message: string) {
+ super(`XDR Write Error: ${message}`);
+ }
+}
+
+export class XdrReaderError extends TypeError {
+ constructor(message: string) {
+ super(`XDR Read Error: ${message}`);
+ }
+}
+
+export class XdrDefinitionError extends TypeError {
+ constructor(message: string) {
+ super(`XDR Type Definition Error: ${message}`);
+ }
+}
+
+export class XdrNotImplementedDefinitionError extends XdrDefinitionError {
+ constructor() {
+ super(`method not implemented, it should be overloaded in the descendant class.`);
+ }
+}
diff --git a/src/helpers/xdr/i128.ts b/src/helpers/xdr/i128.ts
new file mode 100644
index 0000000..35dcd35
--- /dev/null
+++ b/src/helpers/xdr/i128.ts
@@ -0,0 +1,17 @@
+import { LargeInt } from './large-int';
+
+export class I128 extends LargeInt {
+ constructor(...args: any) {
+ super(args);
+ }
+
+ get unsigned(): any {
+ return false;
+ }
+
+ get size(): any {
+ return 128;
+ }
+}
+
+I128.defineIntBoundaries();
diff --git a/src/helpers/xdr/index.ts b/src/helpers/xdr/index.ts
new file mode 100644
index 0000000..ac24fa6
--- /dev/null
+++ b/src/helpers/xdr/index.ts
@@ -0,0 +1 @@
+export * from './i128';
diff --git a/src/helpers/xdr/large-int.ts b/src/helpers/xdr/large-int.ts
new file mode 100644
index 0000000..e993c09
--- /dev/null
+++ b/src/helpers/xdr/large-int.ts
@@ -0,0 +1,116 @@
+// @ts-nocheck
+
+import { XdrPrimitiveType } from './xdr-type';
+import { calculateBigIntBoundaries, encodeBigIntFromBits, sliceBigInt } from './bigint-encoder';
+import { XdrNotImplementedDefinitionError, XdrWriterError } from './errors';
+
+/* eslint-disable */
+
+/* tslint:disable */
+export class LargeInt extends XdrPrimitiveType {
+ constructor(args) {
+ super();
+ this._value = encodeBigIntFromBits(args, this.size, this.unsigned);
+ }
+
+ /**
+ * Signed/unsigned representation
+ * @type {Boolean}
+ * @abstract
+ */
+ get unsigned() {
+ throw new XdrNotImplementedDefinitionError();
+ }
+
+ /**
+ * Size of the integer in bits
+ * @type {Number}
+ * @abstract
+ */
+ get size() {
+ throw new XdrNotImplementedDefinitionError();
+ }
+
+ /**
+ * Slice integer to parts with smaller bit size
+ * @param {32|64|128} sliceSize - Size of each part in bits
+ * @return {BigInt[]}
+ */
+ slice(sliceSize) {
+ return sliceBigInt(this._value, this.size, sliceSize);
+ }
+
+ toString() {
+ return this._value.toString();
+ }
+
+ toJSON() {
+ return { _value: this._value.toString() };
+ }
+
+ /**
+ * @inheritDoc
+ */
+ static read(reader) {
+ const { size } = this.prototype;
+ if (size === 64) return new this(reader.readBigUInt64BE());
+ return new this(...Array.from({ length: size / 64 }, () => reader.readBigUInt64BE()).reverse());
+ }
+
+ /**
+ * @inheritDoc
+ */
+ static write(value, writer) {
+ if (value instanceof this) {
+ value = value._value;
+ } else if (typeof value !== 'bigint' || value > this.MAX_VALUE || value < this.MIN_VALUE)
+ throw new XdrWriterError(`${value} is not a ${this.name}`);
+
+ const { unsigned, size } = this.prototype;
+ if (size === 64) {
+ if (unsigned) {
+ writer.writeBigUInt64BE(value);
+ } else {
+ writer.writeBigInt64BE(value);
+ }
+ } else {
+ for (const part of sliceBigInt(value, size, 64).reverse()) {
+ if (unsigned) {
+ writer.writeBigUInt64BE(part);
+ } else {
+ writer.writeBigInt64BE(part);
+ }
+ }
+ }
+ }
+
+ /**
+ * @inheritDoc
+ */
+ static isValid(value) {
+ return typeof value === 'bigint' || value instanceof this;
+ }
+
+ /**
+ * Create instance from string
+ * @param {String} string - Numeric representation
+ * @return {LargeInt}
+ */
+ static fromString(string) {
+ return new this(string);
+ }
+
+ static MAX_VALUE = 0n;
+
+ static MIN_VALUE = 0n;
+
+ /**
+ * @internal
+ * @return {void}
+ */
+ static defineIntBoundaries() {
+ const [min, max] = calculateBigIntBoundaries(this.prototype.size, this.prototype.unsigned);
+ this.MIN_VALUE = min;
+ this.MAX_VALUE = max;
+ }
+}
diff --git a/src/helpers/xdr/serialization/xdr-reader.ts b/src/helpers/xdr/serialization/xdr-reader.ts
new file mode 100644
index 0000000..dbcc2ef
--- /dev/null
+++ b/src/helpers/xdr/serialization/xdr-reader.ts
@@ -0,0 +1,86 @@
+import { XdrReaderError } from '../errors';
+
+export class XdrReader {
+ private _buffer: any;
+ private _length: number;
+ private _index: number;
+
+ constructor(source: any) {
+ let _source = source;
+ if (!Buffer.isBuffer(_source)) {
+ if (_source instanceof Array) {
+ _source = Buffer.from(source);
+ } else {
+ throw new XdrReaderError('source not specified');
+ }
+ }
+
+ this._buffer = _source;
+ this._length = _source.length;
+ this._index = 0;
+ }
+
+ get eof() {
+ return this._index === this._length;
+ }
+
+ advance(size: number) {
+ const from = this._index;
+ // advance cursor position
+ this._index += size;
+ // check buffer boundaries
+ if (this._length < this._index)
+ throw new XdrReaderError('attempt to read outside the boundary of the buffer');
+ // check that padding is correct for Opaque and String
+ const padding = 4 - (size % 4 || 4);
+ if (padding > 0) {
+ // eslint-disable-next-line no-plusplus
+ for (let i = 0; i < padding; i++)
+ if (this._buffer[this._index + i] !== 0)
+ // all bytes in the padding should be zeros
+ throw new XdrReaderError('invalid padding');
+ this._index += padding;
+ }
+ return from;
+ }
+
+ rewind() {
+ this._index = 0;
+ }
+
+ read(size: number) {
+ const from = this.advance(size);
+ return this._buffer.subarray(from, from + size);
+ }
+
+ readInt32BE() {
+ return this._buffer.readInt32BE(this.advance(4));
+ }
+
+ readUInt32BE() {
+ return this._buffer.readUInt32BE(this.advance(4));
+ }
+
+ readBigInt64BE() {
+ return this._buffer.readBigInt64BE(this.advance(8));
+ }
+
+ readBigUInt64BE() {
+ return this._buffer.readBigUInt64BE(this.advance(8));
+ }
+
+ readFloatBE() {
+ return this._buffer.readFloatBE(this.advance(4));
+ }
+
+ readDoubleBE() {
+ return this._buffer.readDoubleBE(this.advance(8));
+ }
+
+ ensureInputConsumed() {
+ if (this._index !== this._length)
+ throw new XdrReaderError(
+ `invalid XDR contract typecast - source buffer not entirely consumed`,
+ );
+ }
+}
diff --git a/src/helpers/xdr/serialization/xdr-writer.ts b/src/helpers/xdr/serialization/xdr-writer.ts
new file mode 100644
index 0000000..34210e3
--- /dev/null
+++ b/src/helpers/xdr/serialization/xdr-writer.ts
@@ -0,0 +1,105 @@
+const BUFFER_CHUNK = 8192; // 8 KB chunk size increment
+
+export class XdrWriter {
+ private _buffer: any;
+ private _length: any;
+
+ constructor(buffer: any) {
+ let _buffer = buffer;
+ if (typeof _buffer === 'number') {
+ _buffer = Buffer.allocUnsafe(_buffer);
+ } else if (!(buffer instanceof Buffer)) {
+ _buffer = Buffer.allocUnsafe(BUFFER_CHUNK);
+ }
+ this._buffer = _buffer;
+ this._length = _buffer.length;
+ }
+
+ _index = 0;
+
+ alloc(size: number) {
+ const from = this._index;
+ // advance cursor position
+ this._index += size;
+ // ensure sufficient buffer size
+ if (this._length < this._index) {
+ this.resize(this._index);
+ }
+ return from;
+ }
+
+ resize(minRequiredSize: number) {
+ // calculate new length, align new buffer length by chunk size
+ const newLength = Math.ceil(minRequiredSize / BUFFER_CHUNK) * BUFFER_CHUNK;
+ // create new buffer and copy previous data
+ const newBuffer = Buffer.allocUnsafe(newLength);
+ this._buffer.copy(newBuffer, 0, 0, this._length);
+ // update references
+ this._buffer = newBuffer;
+ this._length = newLength;
+ }
+
+ finalize() {
+ // clip underlying buffer to the actually written value
+ return this._buffer.subarray(0, this._index);
+ }
+
+ toArray() {
+ return [...this.finalize()];
+ }
+
+ write(value: any, size: number) {
+ let _value = value;
+ if (typeof value === 'string') {
+ // serialize string directly to the output buffer
+ const offset = this.alloc(size);
+ this._buffer.write(_value, offset, 'utf8');
+ } else {
+ // copy data to the output buffer
+ if (!(_value instanceof Buffer)) {
+ _value = Buffer.from(_value);
+ }
+ const offset = this.alloc(size);
+ _value.copy(this._buffer, offset, 0, size);
+ }
+
+ // add padding for 4-byte XDR alignment
+ const padding = 4 - (size % 4 || 4);
+ if (padding > 0) {
+ const offset = this.alloc(padding);
+ this._buffer.fill(0, offset, this._index);
+ }
+ }
+
+ writeInt32BE(value: string) {
+ const offset = this.alloc(4);
+ this._buffer.writeInt32BE(value, offset);
+ }
+
+ writeUInt32BE(value: string) {
+ const offset = this.alloc(4);
+ this._buffer.writeUInt32BE(value, offset);
+ }
+
+ writeBigInt64BE(value: string) {
+ const offset = this.alloc(8);
+ this._buffer.writeBigInt64BE(value, offset);
+ }
+
+ writeBigUInt64BE(value: string) {
+ const offset = this.alloc(8);
+ this._buffer.writeBigUInt64BE(value, offset);
+ }
+
+ writeFloatBE(value: string) {
+ const offset = this.alloc(4);
+ this._buffer.writeFloatBE(value, offset);
+ }
+
+ writeDoubleBE(value: string) {
+ const offset = this.alloc(8);
+ this._buffer.writeDoubleBE(value, offset);
+ }
+
+ static bufferChunkSize = BUFFER_CHUNK;
+}
diff --git a/src/helpers/xdr/xdr-type.ts b/src/helpers/xdr/xdr-type.ts
new file mode 100644
index 0000000..38fe943
--- /dev/null
+++ b/src/helpers/xdr/xdr-type.ts
@@ -0,0 +1,170 @@
+// @ts-nocheck
+
+import { XdrReader } from './serialization/xdr-reader';
+import { XdrWriter } from './serialization/xdr-writer';
+import { XdrNotImplementedDefinitionError } from './errors';
+
+/* eslint-disable */
+/* tslint:disable */
+class XdrType {
+ write: any;
+
+ toXDR(format = 'raw') {
+ if (!this.write) return this.constructor.toXDR(this, format);
+
+ const writer = new XdrWriter();
+ this.write(this, writer);
+ return encodeResult(writer.finalize(), format);
+ }
+
+ fromXDR(input, format = 'raw') {
+ if (!this.read) return this.constructor.fromXDR(input, format);
+
+ const reader = new XdrReader(decodeInput(input, format));
+ const result = this.read(reader);
+ reader.ensureInputConsumed();
+ return result;
+ }
+
+ /**
+ * Check whether input contains a valid XDR-encoded value
+ * @param {Buffer|String} input - XDR-encoded input data
+ * @param {XdrEncodingFormat} [format] - Encoding format (one of "raw", "hex", "base64")
+ * @return {Boolean}
+ */
+ validateXDR(input, format = 'raw') {
+ try {
+ this.fromXDR(input, format);
+ return true;
+ } catch (e) {
+ return false;
+ }
+ }
+
+ /**
+ * Encode value to XDR format
+ * @param {this} value - Value to serialize
+ * @param {XdrEncodingFormat} [format] - Encoding format (one of "raw", "hex", "base64")
+ * @return {Buffer}
+ */
+ static toXDR(value, format = 'raw') {
+ const writer = new XdrWriter();
+ this.write(value, writer);
+ return encodeResult(writer.finalize(), format);
+ }
+
+ /**
+ * Decode XDR-encoded value
+ * @param {Buffer|String} input - XDR-encoded input data
+ * @param {XdrEncodingFormat} [format] - Encoding format (one of "raw", "hex", "base64")
+ * @return {this}
+ */
+ static fromXDR(input, format = 'raw') {
+ const reader = new XdrReader(decodeInput(input, format));
+ const result = this.read(reader);
+ reader.ensureInputConsumed();
+ return result;
+ }
+
+ /**
+ * Check whether input contains a valid XDR-encoded value
+ * @param {Buffer|String} input - XDR-encoded input data
+ * @param {XdrEncodingFormat} [format] - Encoding format (one of "raw", "hex", "base64")
+ * @return {Boolean}
+ */
+ static validateXDR(input, format = 'raw') {
+ try {
+ this.fromXDR(input, format);
+ return true;
+ } catch (e) {
+ return false;
+ }
+ }
+}
+
+export class XdrPrimitiveType extends XdrType {
+ /**
+ * Read value from the XDR-serialized input
+ * @param {XdrReader} reader - XdrReader instance
+ * @return {this}
+ * @abstract
+ */
+ // eslint-disable-next-line no-unused-vars
+ static read(reader) {
+ throw new XdrNotImplementedDefinitionError();
+ }
+
+ /**
+ * Write XDR value to the buffer
+ * @param {this} value - Value to write
+ * @param {XdrWriter} writer - XdrWriter instance
+ * @return {void}
+ * @abstract
+ */
+ // eslint-disable-next-line no-unused-vars
+ static write(value, writer) {
+ throw new XdrNotImplementedDefinitionError();
+ }
+
+ /**
+ * Check whether XDR primitive value is valid
+ * @param {this} value - Value to check
+ * @return {Boolean}
+ * @abstract
+ */
+ // eslint-disable-next-line no-unused-vars
+ static isValid(value) {
+ return false;
+ }
+}
+
+export class XdrCompositeType extends XdrType {
+ // Every descendant should implement two methods: read(reader) and write(value, writer)
+
+ /**
+ * Check whether XDR primitive value is valid
+ * @param {this} value - Value to check
+ * @return {Boolean}
+ * @abstract
+ */
+ // eslint-disable-next-line no-unused-vars
+ isValid(value) {
+ return false;
+ }
+}
+
+class InvalidXdrEncodingFormatError extends TypeError {
+ constructor(format) {
+ super(`Invalid format ${format}, must be one of "raw", "hex", "base64"`);
+ }
+}
+
+function encodeResult(buffer, format) {
+ switch (format) {
+ case 'raw':
+ return buffer;
+ case 'hex':
+ return buffer.toString('hex');
+ case 'base64':
+ return buffer.toString('base64');
+ default:
+ throw new InvalidXdrEncodingFormatError(format);
+ }
+}
+
+function decodeInput(input, format) {
+ switch (format) {
+ case 'raw':
+ return input;
+ case 'hex':
+ return Buffer.from(input, 'hex');
+ case 'base64':
+ return Buffer.from(input, 'base64');
+ default:
+ throw new InvalidXdrEncodingFormatError(format);
+ }
+}
+
+/**
+ * @typedef {'raw'|'hex'|'base64'} XdrEncodingFormat
+ */
diff --git a/src/hooks/useRouterAddress.tsx b/src/hooks/useRouterAddress.tsx
new file mode 100644
index 0000000..9678497
--- /dev/null
+++ b/src/hooks/useRouterAddress.tsx
@@ -0,0 +1,25 @@
+import { SorobanContextType, useSorobanReact } from '@soroban-react/core';
+import { useEffect, useState } from 'react';
+import useSWRImmutable from 'swr/immutable';
+import { fetchRouter } from '../services/router';
+
+export const useRouterAddress = () => {
+ const sorobanContext: SorobanContextType = useSorobanReact();
+
+ const { activeChain } = sorobanContext;
+
+ const { data, error, isLoading, mutate } = useSWRImmutable(
+ ['router', activeChain],
+ ([key, activeChain]) => fetchRouter(activeChain?.id!)
+ );
+
+ const [router, setRouter] = useState();
+
+ useEffect(() => {
+ if (!data || !sorobanContext) return;
+
+ setRouter(data.address);
+ }, [data, sorobanContext]);
+
+ return { router, isLoading, isError: error, data };
+};
diff --git a/src/hooks/useRouterCallback.tsx b/src/hooks/useRouterCallback.tsx
new file mode 100644
index 0000000..a307847
--- /dev/null
+++ b/src/hooks/useRouterCallback.tsx
@@ -0,0 +1,74 @@
+import { TxResponse, contractInvoke } from '@soroban-react/contracts';
+
+import { useSorobanReact } from '@soroban-react/core';
+import * as StellarSdk from '@stellar/stellar-sdk';
+import { useCallback } from 'react';
+import { useSWRConfig } from 'swr';
+import { useRouterAddress } from './useRouterAddress';
+
+export enum RouterMethod {
+ ADD_LIQUIDITY = 'add_liquidity',
+ REMOVE_LIQUIDITY = 'remove_liquidity',
+ SWAP_EXACT_IN = 'swap_exact_tokens_for_tokens',
+ SWAP_EXACT_OUT = 'swap_tokens_for_exact_tokens',
+ QUOTE = 'router_quote',
+ GET_AMOUNT_OUT = 'router_get_amount_out',
+ GET_AMOUNT_IN = 'router_get_amount_in',
+ GET_AMOUNTS_OUT = 'router_get_amounts_out',
+ GET_AMOUNTS_IN = 'router_get_amounts_in',
+}
+
+// Returns a function that will execute a any method on RouterContract, if the parameters are all valid
+// and the user has approved the slippage adjusted input amount for the trade
+
+const isObject = (val: any) => typeof val === 'object' && val !== null && !Array.isArray(val);
+
+//refetch balance, lptokens and reserves after router tx success
+export const revalidateKeysCondition = (key: any) => {
+ const revalidateKeys = new Set([
+ 'balance',
+ 'lp-tokens',
+ 'reserves',
+ 'trade',
+ 'subscribed-pairs',
+ 'currencyBalance',
+ 'horizon-account',
+ 'swap-network-fees',
+ ]);
+
+ return Array.isArray(key) && key.some((k) => revalidateKeys.has(k));
+};
+
+export function useRouterCallback() {
+ const sorobanContext = useSorobanReact();
+ const { router } = useRouterAddress();
+ const router_address = router!;
+ const { mutate } = useSWRConfig();
+
+ return useCallback(
+ async (method: RouterMethod, args?: StellarSdk.xdr.ScVal[], signAndSend?: boolean) => {
+ let result = (await contractInvoke({
+ contractAddress: router_address as string,
+ method: method,
+ args: args,
+ sorobanContext,
+ signAndSend: signAndSend,
+ reconnectAfterTx: false,
+ })) as TxResponse;
+
+ //If is only a simulation return the result
+ if (!signAndSend) return result;
+
+ if (
+ isObject(result) &&
+ result?.status !== StellarSdk.SorobanRpc.Api.GetTransactionStatus.SUCCESS
+ )
+ throw result;
+
+ mutate((key: any) => revalidateKeysCondition(key), undefined, { revalidate: true });
+
+ return result;
+ },
+ [router_address, sorobanContext, mutate]
+ );
+}
diff --git a/src/hooks/useSwapCallback.tsx b/src/hooks/useSwapCallback.tsx
new file mode 100644
index 0000000..8edc967
--- /dev/null
+++ b/src/hooks/useSwapCallback.tsx
@@ -0,0 +1,111 @@
+import * as StellarSdk from '@stellar/stellar-sdk';
+import BigNumber from 'bignumber.js';
+import { useWallet } from '../contexts/wallet'; // Adjust the import path if necessary
+import { getCurrentTimePlusOneHour } from '../functions/getCurrentTimePlusOneHour';
+import { scValToJs } from '../helpers/convert';
+import { bigNumberToI128, bigNumberToU64 } from '../helpers/utils';
+import { InterfaceTrade, TradeType } from '../state/routing/types';
+import { RouterMethod, useRouterCallback } from './useRouterCallback';
+
+// Returns a function that will execute a swap, if the parameters are all valid
+// and the user has approved the slippage adjusted input amount for the trade
+
+interface GetSwapAmountsProps {
+ tradeType: TradeType;
+ inputAmount: string;
+ outputAmount: string;
+ allowedSlippage: number;
+}
+
+export const getSwapAmounts = ({
+ tradeType,
+ inputAmount,
+ outputAmount,
+ allowedSlippage = 0.5,
+}: GetSwapAmountsProps) => {
+ const routerMethod =
+ tradeType == TradeType.EXACT_INPUT ? RouterMethod.SWAP_EXACT_IN : RouterMethod.SWAP_EXACT_OUT;
+
+ const factorLess = BigNumber(100).minus(allowedSlippage).dividedBy(100);
+ const factorMore = BigNumber(100).plus(allowedSlippage).dividedBy(100);
+
+ //amount_in , amount_out
+ const amount0 =
+ routerMethod === RouterMethod.SWAP_EXACT_IN ? BigNumber(inputAmount) : BigNumber(outputAmount);
+
+ //amount_out_min , amount_in_max
+ const amount1 =
+ routerMethod === RouterMethod.SWAP_EXACT_IN
+ ? BigNumber(outputAmount).multipliedBy(factorLess).decimalPlaces(0)
+ : BigNumber(inputAmount).multipliedBy(factorMore).decimalPlaces(0);
+
+ return { amount0, amount1, routerMethod };
+};
+
+interface SuccessfulSwapResponse
+ extends StellarSdk.SorobanRpc.Api.GetSuccessfulTransactionResponse {
+ switchValues: string[];
+}
+
+export function useSwapCallback(
+ trade: InterfaceTrade | undefined // trade to execute, required
+) {
+ const { connected, walletAddress } = useWallet(); // Use the wallet context
+ const routerCallback = useRouterCallback();
+ const allowedSlippage = 1;
+
+ const doSwap = async (
+ simulation?: boolean
+ ): Promise => {
+ if (!trade) throw new Error('missing trade');
+ if (!connected || !walletAddress) throw new Error('wallet must be connected to swap');
+ if (!trade.tradeType) throw new Error('tradeType must be defined');
+
+ const { amount0, amount1, routerMethod } = getSwapAmounts({
+ tradeType: trade.tradeType,
+ inputAmount: trade.inputAmount?.value as string,
+ outputAmount: trade.outputAmount?.value as string,
+ allowedSlippage: allowedSlippage,
+ });
+
+ const amount0ScVal = bigNumberToI128(amount0);
+ const amount1ScVal = bigNumberToI128(amount1);
+
+ console.log('USING ROUTER');
+ const path = trade.path?.map((address: string) => new StellarSdk.Address(address));
+
+ const pathScVal = StellarSdk.nativeToScVal(path);
+
+ const args = [
+ amount0ScVal,
+ amount1ScVal,
+ pathScVal, // path
+ new StellarSdk.Address(walletAddress).toScVal(),
+ bigNumberToU64(BigNumber(getCurrentTimePlusOneHour())),
+ ];
+
+ try {
+ const result = (await routerCallback(
+ routerMethod,
+ args,
+ !simulation
+ )) as StellarSdk.SorobanRpc.Api.GetTransactionResponse;
+
+ //if it is a simulation should return the result
+ if (simulation) return result;
+
+ if (result.status !== StellarSdk.SorobanRpc.Api.GetTransactionStatus.SUCCESS) throw result;
+
+ const switchValues: string[] = scValToJs(result.returnValue!);
+
+ const currencyA = switchValues?.[0];
+ const currencyB = switchValues?.[switchValues?.length - 1];
+
+ return { ...result, switchValues };
+ } catch (error) {
+ throw error;
+ }
+ };
+
+ return { doSwap, isLoading: trade?.isLoading };
+}
diff --git a/src/interfaces/adminKeys.ts b/src/interfaces/adminKeys.ts
new file mode 100644
index 0000000..01de01a
--- /dev/null
+++ b/src/interfaces/adminKeys.ts
@@ -0,0 +1,10 @@
+export interface AdminKeyResponseType {
+ network: string;
+ admin_public: string;
+ admin_secret: string;
+}
+
+export interface KeysType {
+ admin_public: string;
+ admin_secret: string;
+}
diff --git a/src/interfaces/currency.ts b/src/interfaces/currency.ts
new file mode 100644
index 0000000..c78aff8
--- /dev/null
+++ b/src/interfaces/currency.ts
@@ -0,0 +1,6 @@
+import { TokenType } from 'interfaces';
+
+export type CurrencyAmount = {
+ currency: TokenType;
+ value: string;
+};
diff --git a/src/interfaces/index.ts b/src/interfaces/index.ts
new file mode 100644
index 0000000..c5b4697
--- /dev/null
+++ b/src/interfaces/index.ts
@@ -0,0 +1,3 @@
+export * from './tokens';
+export * from './adminKeys';
+export * from './currency';
diff --git a/src/interfaces/pairs.ts b/src/interfaces/pairs.ts
new file mode 100644
index 0000000..39bb0e1
--- /dev/null
+++ b/src/interfaces/pairs.ts
@@ -0,0 +1,18 @@
+import BigNumber from 'bignumber.js';
+import { TokenType } from './tokens';
+
+interface TokenAmount {
+ currency: TokenType | undefined;
+ balance: BigNumber;
+}
+
+interface LiquidityToken {
+ token: TokenType | undefined;
+ userBalance: number | BigNumber;
+ totalSupply: any;
+}
+
+export interface PairInfo {
+ liquidityToken: LiquidityToken;
+ tokenAmounts: TokenAmount[];
+}
diff --git a/src/interfaces/tokens.ts b/src/interfaces/tokens.ts
new file mode 100644
index 0000000..1e354ac
--- /dev/null
+++ b/src/interfaces/tokens.ts
@@ -0,0 +1,23 @@
+export interface TokenType {
+ code: string;
+ issuer?: string;
+ contract: string;
+ name?: string;
+ org?: string;
+ domain?: string;
+ icon?: string;
+ decimals?: number;
+}
+
+export interface tokensResponse {
+ network: string;
+ tokens: TokenType[];
+}
+
+export type TokenMapType = {
+ [key: string]: TokenType;
+};
+
+export type TokenBalancesMap = {
+ [tokenAddress: string]: { usdValue: number; balance: string };
+};
diff --git a/src/layouts/DefaultLayout.tsx b/src/layouts/DefaultLayout.tsx
index d08dd89..9cd2d06 100644
--- a/src/layouts/DefaultLayout.tsx
+++ b/src/layouts/DefaultLayout.tsx
@@ -21,10 +21,13 @@ export default function DefaultLayout({ children }: { children: ReactNode }) {
typeof poolId == 'string' && /^[0-9A-Z]{56}$/.test(poolId) ? poolId : undefined;
const loadBlendData = useStore((state) => state.loadBlendData);
+ const rewardZone = useStore((state) => state.backstop?.config?.rewardZone ?? []);
+
+ const isTestnet = process.env.NEXT_PUBLIC_PASSPHRASE === Networks.TESTNET;
useEffect(() => {
const update = async () => {
- await loadBlendData(false, "CCG4HM7SML3CUKWO2WOXDR2HCH5EMIIYVNPFB2EMQPWI6KURL46XB54H", connected ? walletAddress : undefined);
+ await loadBlendData(false, undefined, connected ? walletAddress : undefined);
};
update();
const refreshInterval = setInterval(async () => {
@@ -33,6 +36,9 @@ export default function DefaultLayout({ children }: { children: ReactNode }) {
return () => clearInterval(refreshInterval);
}, [loadBlendData, connected, walletAddress]);
+ // get the last (oldest) pool in the reward zone
+ const faucet_pool = rewardZone.length > 0 ? rewardZone[rewardZone.length - 1] : undefined;
+
if (safePoolId && safePoolId !== lastPool) {
setLastPool(safePoolId);
}
@@ -50,6 +56,11 @@ export default function DefaultLayout({ children }: { children: ReactNode }) {
+ {faucet_pool && isTestnet && (
+
+
+
+ )}
{children}
diff --git a/src/pages/borrow.tsx b/src/pages/borrow.tsx
index 62a8ed3..bd35f80 100644
--- a/src/pages/borrow.tsx
+++ b/src/pages/borrow.tsx
@@ -1,18 +1,16 @@
-import OpenInNewIcon from '@mui/icons-material/OpenInNew';
-import { Box, Link, Typography, useTheme } from '@mui/material';
+import { Typography, useTheme } from '@mui/material';
import type { NextPage } from 'next';
import { useRouter } from 'next/router';
-import { BorrowAnvil } from '../components/borrow/BorrowAnvil';
import { FlameIcon } from '../components/common/FlameIcon';
-import { GoBackHeader } from '../components/common/GoBackHeader';
import { ReserveDropdown } from '../components/common/ReserveDropdown';
import { Row } from '../components/common/Row';
import { Section, SectionSize } from '../components/common/Section';
import { StackedText } from '../components/common/StackedText';
+import { LendAnvil } from '../components/lend/LendAnvil';
import { useWallet } from '../contexts/wallet';
import { useStore } from '../store/store';
import { getEmissionTextFromValue, toBalance, toPercentage } from '../utils/formatter';
-import { getEmissionsPerYearPerUnit, getTokenLinkFromReserve } from '../utils/token';
+import { getEmissionsPerYearPerUnit } from '../utils/token';
const Borrow: NextPage = () => {
const theme = useTheme();
@@ -20,9 +18,10 @@ const Borrow: NextPage = () => {
const router = useRouter();
const { poolId, assetId } = router.query;
- const safePoolId = typeof poolId == 'string' && /^[0-9A-Z]{56}$/.test(poolId) ? poolId : '';
- const safeAssetId = typeof assetId == 'string' && /^[0-9A-Z]{56}$/.test(assetId) ? assetId : '';
-
+ const safePoolId = 'CBYCVLEHLOVGH6XYYOMXNXWC3AVSYSRUXK3MHWKVIQSDF7JQ2YNEF2FN';
+ const safeAssetId = 'CBGO6D5Q3SIPG6QHN2MJ5LQQ6XH2SRPKEB6PLRPS3KWDDPLBMDETEZRK';
+ const xlmAssetId = 'CDLZFC3SYJYDZT7K67VZ75HPJVIEUVNIXF47ZG2FB2RMQQVU2HHGCYSC';
+ const usdcAssetId = 'CAQCFVLOBK5GIULPNZRGATJJMIZL5BSP7X5YJVMGCPTUEPFM4AVSRCJU';
const poolData = useStore((state) => state.pools.get(safePoolId));
const reserve = poolData?.reserves.get(safeAssetId);
@@ -31,63 +30,8 @@ const Borrow: NextPage = () => {
const totalSupplied = reserve?.estimates.supplied || 0;
const availableToBorrow = totalSupplied * maxUtilFraction - (reserve?.estimates.borrowed || 0);
- return (
+ return poolData ? (
<>
-
-
-
-
-
-
-
-
-
-
-
- Available
-
-
- {toBalance(availableToBorrow, reserve?.config.decimals)}
-
-
-
-
-
- {reserve?.tokenMetadata?.symbol ?? ''}
-
-
-
-
-
-
-
-
+
+
+
+
+
>
+ ) : (
+
+ {connected ? 'Loading...' : 'Please connect your wallet'}
+
);
};
diff --git a/src/pages/dashboard.tsx b/src/pages/dashboard.tsx
index c120f6d..279555a 100644
--- a/src/pages/dashboard.tsx
+++ b/src/pages/dashboard.tsx
@@ -1,20 +1,13 @@
import { Box, Typography, useTheme } from '@mui/material';
import type { NextPage } from 'next';
import { useRouter } from 'next/router';
-import { BackstopPreviewBar } from '../components/backstop/BackstopPreviewBar';
-import { BorrowMarketList } from '../components/borrow/BorrowMarketList';
import { BorrowPositions } from '../components/borrow/BorrowPositions';
import { Divider } from '../components/common/Divider';
import { Row } from '../components/common/Row';
-import { Section, SectionSize } from '../components/common/Section';
-import { ToggleButton } from '../components/common/ToggleButton';
import { PositionOverview } from '../components/dashboard/PositionOverview';
-import { LendMarketList } from '../components/lend/LendMarketList';
import { LendPositions } from '../components/lend/LendPositions';
-import { PoolExploreBar } from '../components/pool/PoolExploreBar';
import { useSettings } from '../contexts';
import { useStore } from '../store/store';
-import { toBalance } from '../utils/formatter';
const Dashboard: NextPage = () => {
const router = useRouter();
@@ -40,10 +33,6 @@ const Dashboard: NextPage = () => {
return (
<>
-
-
-
-
@@ -55,45 +44,6 @@ const Dashboard: NextPage = () => {
-
-
-
- Supply
-
-
- Borrow
-
-
-
-
- {`Assets to ${showLend ? 'supply' : 'borrow'}`}
-
-
- Market size:
-
- {`$${toBalance(
- poolData?.estimates?.totalSupply ?? 0
- )}`}
-
-
-
- {showLend ? : }
>
);
};
diff --git a/src/pages/index.tsx b/src/pages/index.tsx
index a6e7a24..62a8ed3 100644
--- a/src/pages/index.tsx
+++ b/src/pages/index.tsx
@@ -1,26 +1,140 @@
+import OpenInNewIcon from '@mui/icons-material/OpenInNew';
+import { Box, Link, Typography, useTheme } from '@mui/material';
import type { NextPage } from 'next';
-import { Divider } from '../components/common/Divider';
+import { useRouter } from 'next/router';
+import { BorrowAnvil } from '../components/borrow/BorrowAnvil';
+import { FlameIcon } from '../components/common/FlameIcon';
+import { GoBackHeader } from '../components/common/GoBackHeader';
+import { ReserveDropdown } from '../components/common/ReserveDropdown';
import { Row } from '../components/common/Row';
-import { SectionBase } from '../components/common/SectionBase';
-import { MarketCard } from '../components/markets/MarketCard';
+import { Section, SectionSize } from '../components/common/Section';
+import { StackedText } from '../components/common/StackedText';
+import { useWallet } from '../contexts/wallet';
import { useStore } from '../store/store';
+import { getEmissionTextFromValue, toBalance, toPercentage } from '../utils/formatter';
+import { getEmissionsPerYearPerUnit, getTokenLinkFromReserve } from '../utils/token';
-const Markets: NextPage = () => {
- const pools = useStore((state) => state.pools);
+const Borrow: NextPage = () => {
+ const theme = useTheme();
+ const { connected, walletAddress } = useWallet();
+
+ const router = useRouter();
+ const { poolId, assetId } = router.query;
+ const safePoolId = typeof poolId == 'string' && /^[0-9A-Z]{56}$/.test(poolId) ? poolId : '';
+ const safeAssetId = typeof assetId == 'string' && /^[0-9A-Z]{56}$/.test(assetId) ? assetId : '';
+
+ const poolData = useStore((state) => state.pools.get(safePoolId));
+
+ const reserve = poolData?.reserves.get(safeAssetId);
+ //totalEstLiabilities / totalEstSupply , you you can just do something like canBorrow = totalSupply * max_util - totalLiabilities
+ const maxUtilFraction = (reserve?.config.max_util || 1) / 10 ** (reserve?.config.decimals || 7);
+ const totalSupplied = reserve?.estimates.supplied || 0;
+ const availableToBorrow = totalSupplied * maxUtilFraction - (reserve?.estimates.borrowed || 0);
return (
<>
-
- Markets
-
+
+
+
+
+
+
+
+
+
+
+ Available
+
+
+ {toBalance(availableToBorrow, reserve?.config.decimals)}
+
+
+
+
+
+ {reserve?.tokenMetadata?.symbol ?? ''}
+
+
+
+
+
+
+
+
+
+
+ {toPercentage(reserve?.estimates.apy)}{' '}
+
+
+ }
+ sx={{ padding: '6px' }}
+ >
+
+
+
+
+
+
-
- {Array.from(pools.keys()).map((poolId) => (
-
- ))}
>
);
};
-export default Markets;
+export default Borrow;
diff --git a/src/pages/swap.tsx b/src/pages/swap.tsx
new file mode 100644
index 0000000..b5f2e52
--- /dev/null
+++ b/src/pages/swap.tsx
@@ -0,0 +1,256 @@
+import type { NextPage } from 'next';
+
+// const Swap: NextPage = () => {
+// const router = useRouter();
+// const { viewType } = useSettings();
+// const { connected, walletAddress, backstopClaim } = useWallet();
+// const loadBlendData = useStore((state) => state.loadBlendData);
+// const { poolId } = router.query;
+// const safePoolId = typeof poolId === 'string' && /^[0-9A-Z]{56}$/.test(poolId) ? poolId : '';
+
+// const backstopData = useStore((state) => state.backstop);
+// const userBackstopData = useStore((state) => state.backstopUserData);
+// const userPoolEstimates = userBackstopData?.estimates.get(safePoolId);
+// const userPoolBackstopData = userBackstopData?.balances.get(safePoolId);
+// const [lpTokenEmissions, setLpTokenEmissions] = useState();
+// const [sellCoin, setSellCoin] = useState('XLM');
+// const [receiveCoin, setReceiveCoin] = useState('USDC');
+// const [sellAmount, setSellAmount] = useState('');
+// const [receiveAmount, setReceiveAmount] = useState('');
+// const [showConfirm, setShowConfirm] = useState(false);
+// const [txError, setTxError] = useState(false);
+// const [txErrorMessage, setTxErrorMessage] = useState('');
+// const [swapResult, setSwapResult] = useState();
+// const [isLoading, setIsLoading] = useState(false);
+
+// const conversionRate = 0.0899; // 1 XLM = 0.0899 USDC
+
+// const handleSellAmountChange = (amount: string) => {
+// setSellAmount(amount);
+// setReceiveAmount((parseFloat(amount) * conversionRate).toFixed(2));
+// };
+
+// const handleReceiveAmountChange = (amount: string) => {
+// setReceiveAmount(amount);
+// setSellAmount((parseFloat(amount) / conversionRate).toFixed(2));
+// };
+
+// const handleClaimEmissionsClick = async () => {
+// if (connected && userBackstopData && userPoolEstimates?.emissions) {
+// let claimArgs: BackstopClaimArgs = {
+// from: walletAddress,
+// pool_addresses: [safePoolId],
+// to: walletAddress,
+// };
+// setLpTokenEmissions(BigInt(0));
+// await backstopClaim(claimArgs, false);
+// await loadBlendData(true, safePoolId, walletAddress);
+// }
+// };
+
+// const trade: InterfaceTrade = {
+// tradeType: TradeType.EXACT_INPUT,
+// inputAmount: { value: sellAmount, currency: sellCoin },
+// outputAmount: { value: receiveAmount, currency: receiveCoin },
+// path: [sellCoin, receiveCoin],
+// };
+
+// const { doSwap } = useSwapCallback(trade);
+
+// const handleSwap = async () => {
+// if (!connected) {
+// setTxErrorMessage('Wallet not connected');
+// setTxError(true);
+// return;
+// }
+
+// setIsLoading(true);
+// setTxError(false);
+// setTxErrorMessage('');
+
+// try {
+// const result = await doSwap();
+// setSwapResult(result);
+// setShowConfirm(true);
+// } catch (error: any) {
+// setTxErrorMessage(error.message || 'An unknown error occurred');
+// setTxError(true);
+// } finally {
+// setIsLoading(false);
+// }
+// };
+
+// const handleConfirmDismiss = () => {
+// setShowConfirm(false);
+// setSwapResult(undefined);
+// };
+
+// const handleErrorDismiss = () => {
+// setTxError(false);
+// setTxErrorMessage('');
+// handleConfirmDismiss();
+// };
+
+// return (
+// <>
+//
+//
+//
+// Swap
+//
+//
+//
+
+// {lpTokenEmissions !== undefined && lpTokenEmissions > BigInt(0) && (
+//
+//
+//
+// Emissions to claim
+//
+//
+//
+//
+//
+//
+// )}
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+
+//
+//
+//
+
+//
+//
+//
+// Transaction Error
+//
+//
+// {txErrorMessage}
+//
+//
+//
+//
+
+//
+//
+//
+// Swap Successful
+//
+//
+// {swapResult}
+//
+//
+//
+//
+
+//
+// >
+// );
+// };
+
+// export default Swap;
+
+const Swap: NextPage = () => {
+ return <>>;
+};
+
+export default Swap;
diff --git a/src/pages/termsofservice.tsx b/src/pages/termsofservice.tsx
deleted file mode 100644
index 24a2b61..0000000
--- a/src/pages/termsofservice.tsx
+++ /dev/null
@@ -1,23 +0,0 @@
-import { Box, Typography } from '@mui/material';
-import { NextPage } from 'next';
-import { Divider } from '../components/common/Divider';
-import { Row } from '../components/common/Row';
-import { TOS } from '../components/common/TOS';
-
-const TermsOfService: NextPage = () => {
- return (
- <>
- <>
-
- Blend App Terms of Service
-
-
-
-
-
- >
- >
- );
-};
-
-export default TermsOfService;
diff --git a/src/services/axios.ts b/src/services/axios.ts
new file mode 100644
index 0000000..7a07700
--- /dev/null
+++ b/src/services/axios.ts
@@ -0,0 +1,10 @@
+import axios from 'axios';
+
+const axiosInstance = axios.create({
+ baseURL: process.env.NEXT_PUBLIC_BACKEND_URL,
+ headers: {
+ 'Cache-Control': 'no-cache',
+ },
+});
+
+export default axiosInstance;
diff --git a/src/services/router.ts b/src/services/router.ts
new file mode 100644
index 0000000..92e55d1
--- /dev/null
+++ b/src/services/router.ts
@@ -0,0 +1,10 @@
+import axios from './axios';
+
+export const fetchRouter = async (network: string) => {
+ if (network == 'mainnet')
+ return { address: 'CBHNQTKJD76Q55TINIT3PPP3BKLIKIQEXPTQ32GUUU7I3CHBD5JECZLW' };
+
+ const { data } = await axios.get(`/api/${network}/router`);
+
+ return data;
+};
diff --git a/src/state/routing/types.ts b/src/state/routing/types.ts
new file mode 100644
index 0000000..715735b
--- /dev/null
+++ b/src/state/routing/types.ts
@@ -0,0 +1,301 @@
+import { Percent } from 'soroswap-router-sdk';
+import { DexDistribution } from '../../helpers/aggregator';
+import { CurrencyAmount } from '../../interfaces';
+
+export enum TradeState {
+ LOADING,
+ INVALID,
+ STALE,
+ NO_ROUTE_FOUND,
+ VALID,
+}
+
+export enum QuoteMethod {
+ ROUTING_API = 'ROUTING_API',
+ CLIENT_SIDE = 'CLIENT_SIDE',
+ CLIENT_SIDE_FALLBACK = 'CLIENT_SIDE_FALLBACK', // If client-side was used after the routing-api call failed.
+}
+
+// // from https://github.com/Uniswap/routing-api/blob/main/lib/handlers/schema.ts
+
+// type TokenInRoute = Pick
+
+// export type V3PoolInRoute = {
+// type: 'v3-pool'
+// tokenIn: TokenInRoute
+// tokenOut: TokenInRoute
+// sqrtRatioX96: string
+// liquidity: string
+// tickCurrent: string
+// fee: string
+// amountIn?: string
+// amountOut?: string
+
+// // not used in the interface
+// address?: string
+// }
+
+// type V2Reserve = {
+// token: TokenInRoute
+// quotient: string
+// }
+
+// export type V2PoolInRoute = {
+// type: 'v2-pool'
+// tokenIn: TokenInRoute
+// tokenOut: TokenInRoute
+// reserve0: V2Reserve
+// reserve1: V2Reserve
+// amountIn?: string
+// amountOut?: string
+
+// // not used in the interface
+// // avoid returning it from the client-side smart-order-router
+// address?: string
+// }
+
+// export interface ClassicQuoteData {
+// quoteId?: string
+// requestId?: string
+// blockNumber: string
+// amount: string
+// amountDecimals: string
+// gasPriceWei: string
+// gasUseEstimate: string
+// gasUseEstimateQuote: string
+// gasUseEstimateQuoteDecimals: string
+// gasUseEstimateUSD: string
+// methodParameters?: { calldata: string; value: string }
+// quote: string
+// quoteDecimals: string
+// quoteGasAdjusted: string
+// quoteGasAdjustedDecimals: string
+// route: Array<(V3PoolInRoute | V2PoolInRoute)[]>
+// routeString: string
+// }
+
+// type URADutchOrderQuoteResponse = {
+// routing: URAQuoteType.DUTCH_LIMIT
+// quote: {
+// auctionPeriodSecs: number
+// deadlineBufferSecs: number
+// orderInfo: DutchOrderInfoJSON
+// quoteId?: string
+// requestId?: string
+// slippageTolerance: string
+// }
+// allQuotes: Array
+// }
+// type URAClassicQuoteResponse = {
+// routing: URAQuoteType.CLASSIC
+// quote: ClassicQuoteData
+// allQuotes: Array
+// }
+// export type URAQuoteResponse = URAClassicQuoteResponse | URADutchOrderQuoteResponse
+
+// export function isClassicQuoteResponse(data: URAQuoteResponse): data is URAClassicQuoteResponse {
+// return data.routing === URAQuoteType.CLASSIC
+// }
+
+// export enum TradeFillType {
+// Classic = 'classic', // Uniswap V1, V2, and V3 trades with on-chain routes
+// UniswapX = 'uniswap_x', // off-chain trades, no routes
+// }
+
+// export type ApproveInfo = { needsApprove: true; approveGasEstimateUSD: number } | { needsApprove: false }
+// export type WrapInfo = { needsWrap: true; wrapGasEstimateUSD: number } | { needsWrap: false }
+
+// export class ClassicTrade extends Trade {
+// public readonly fillType = TradeFillType.Classic
+// approveInfo: ApproveInfo
+// gasUseEstimateUSD?: number // gas estimate for swaps
+// blockNumber: string | null | undefined
+// isUniswapXBetter: boolean | undefined
+// fromClientRouter: boolean | undefined
+// requestId: string | undefined
+// quoteMethod: QuoteMethod
+
+// constructor({
+// gasUseEstimateUSD,
+// blockNumber,
+// isUniswapXBetter,
+// requestId,
+// quoteMethod,
+// approveInfo,
+// ...routes
+// }: {
+// gasUseEstimateUSD?: number
+// totalGasUseEstimateUSD?: number
+// blockNumber?: string | null
+// isUniswapXBetter?: boolean
+// requestId?: string
+// quoteMethod: QuoteMethod
+// fromClientRouter?: boolean
+// approveInfo: ApproveInfo
+// v2Routes: {
+// routev2: V2Route
+// inputAmount: CurrencyAmount
+// outputAmount: CurrencyAmount
+// }[]
+// v3Routes: {
+// routev3: V3Route
+// inputAmount: CurrencyAmount
+// outputAmount: CurrencyAmount
+// }[]
+// tradeType: TradeType
+// mixedRoutes?: {
+// mixedRoute: MixedRouteSDK
+// inputAmount: CurrencyAmount
+// outputAmount: CurrencyAmount
+// }[]
+// }) {
+// super(routes)
+// this.blockNumber = blockNumber
+// this.gasUseEstimateUSD = gasUseEstimateUSD
+// this.isUniswapXBetter = isUniswapXBetter
+// this.requestId = requestId
+// this.quoteMethod = quoteMethod
+// this.approveInfo = approveInfo
+// }
+
+// // gas estimate for maybe approve + swap
+// public get totalGasUseEstimateUSD(): number | undefined {
+// if (this.approveInfo.needsApprove && this.gasUseEstimateUSD) {
+// return this.approveInfo.approveGasEstimateUSD + this.gasUseEstimateUSD
+// }
+
+// return this.gasUseEstimateUSD
+// }
+// }
+
+// export class DutchOrderTrade extends IDutchOrderTrade {
+// public readonly fillType = TradeFillType.UniswapX
+// quoteId?: string
+// requestId?: string
+// wrapInfo: WrapInfo
+// approveInfo: ApproveInfo
+// // The gas estimate of the reference classic trade, if there is one.
+// classicGasUseEstimateUSD?: number
+// auctionPeriodSecs: number
+// deadlineBufferSecs: number
+// slippageTolerance: Percent
+
+// constructor({
+// currencyIn,
+// currenciesOut,
+// orderInfo,
+// tradeType,
+// quoteId,
+// requestId,
+// wrapInfo,
+// approveInfo,
+// classicGasUseEstimateUSD,
+// auctionPeriodSecs,
+// deadlineBufferSecs,
+// slippageTolerance,
+// }: {
+// currencyIn: Currency
+// currenciesOut: Currency[]
+// orderInfo: DutchOrderInfo
+// tradeType: TradeType
+// quoteId?: string
+// requestId?: string
+// approveInfo: ApproveInfo
+// wrapInfo: WrapInfo
+// classicGasUseEstimateUSD?: number
+// auctionPeriodSecs: number
+// deadlineBufferSecs: number
+// slippageTolerance: Percent
+// }) {
+// super({ currencyIn, currenciesOut, orderInfo, tradeType })
+// this.quoteId = quoteId
+// this.requestId = requestId
+// this.approveInfo = approveInfo
+// this.wrapInfo = wrapInfo
+// this.classicGasUseEstimateUSD = classicGasUseEstimateUSD
+// this.auctionPeriodSecs = auctionPeriodSecs
+// this.deadlineBufferSecs = deadlineBufferSecs
+// this.slippageTolerance = slippageTolerance
+// }
+
+// public get totalGasUseEstimateUSD(): number {
+// if (this.wrapInfo.needsWrap && this.approveInfo.needsApprove) {
+// return this.wrapInfo.wrapGasEstimateUSD + this.approveInfo.approveGasEstimateUSD
+// }
+
+// if (this.wrapInfo.needsWrap) return this.wrapInfo.wrapGasEstimateUSD
+// if (this.approveInfo.needsApprove) return this.approveInfo.approveGasEstimateUSD
+
+// return 0
+// }
+// }
+export enum TradeType {
+ EXACT_INPUT = 'EXACT_INPUT',
+ EXACT_OUTPUT = 'EXACT_OUTPUT',
+}
+export type InterfaceTrade = {
+ inputAmount: CurrencyAmount | undefined;
+ outputAmount: CurrencyAmount | undefined;
+ tradeType: TradeType | undefined;
+ path: string[] | undefined;
+ distribution?: DexDistribution[] | undefined;
+ priceImpact?: Percent | undefined;
+ [x: string]: any;
+};
+
+export enum QuoteState {
+ SUCCESS = 'Success',
+ NOT_FOUND = 'Not found',
+}
+
+// export type QuoteResult =
+// | {
+// state: QuoteState.NOT_FOUND
+// data?: undefined
+// }
+// | {
+// state: QuoteState.SUCCESS
+// data: URAQuoteResponse
+// }
+
+// export type TradeResult =
+// | {
+// state: QuoteState.NOT_FOUND
+// trade?: undefined
+// }
+// | {
+// state: QuoteState.SUCCESS
+// trade: InterfaceTrade
+// }
+
+// export enum PoolType {
+// V2Pool = 'v2-pool',
+// V3Pool = 'v3-pool',
+// }
+
+// // swap router API special cases these strings to represent native currencies
+// // all chains except for bnb chain and polygon
+// // have "ETH" as native currency symbol
+// export enum SwapRouterNativeAssets {
+// MATIC = 'MATIC',
+// BNB = 'BNB',
+// AVAX = 'AVAX',
+// ETH = 'ETH',
+// }
+
+// export enum URAQuoteType {
+// CLASSIC = 'CLASSIC',
+// DUTCH_LIMIT = 'DUTCH_LIMIT',
+// }
+
+// type ClassicAPIConfig = {
+// protocols: Protocol[]
+// }
+
+// type UniswapXConfig = {
+// swapper?: string
+// exclusivityOverrideBps?: number
+// auctionPeriodSecs?: number
+// }
+
+// export type RoutingConfig = (UniswapXConfig | ClassicAPIConfig)[]
diff --git a/src/store/blendSlice.ts b/src/store/blendSlice.ts
index c767a48..09a53f7 100644
--- a/src/store/blendSlice.ts
+++ b/src/store/blendSlice.ts
@@ -55,7 +55,7 @@ export const createBlendSlice: StateCreator = (se
// all pools in the reward zone + the request pools are loaded on the backstop
let horizonServer = get().horizonServer();
let pools = new Map();
- let pool = "CBYCVLEHLOVGH6XYYOMXNXWC3AVSYSRUXK3MHWKVIQSDF7JQ2YNEF2FN";
+ let pool = 'CBYCVLEHLOVGH6XYYOMXNXWC3AVSYSRUXK3MHWKVIQSDF7JQ2YNEF2FN';
let assetStellarMetadata = new Map();
try {
let pool_data = await Pool.load(network, pool, latest_ledger_close);
@@ -65,8 +65,6 @@ export const createBlendSlice: StateCreator = (se
assetStellarMetadata.set(reserve.assetId, metadata);
}
}
- console.log('Loaded pool data for pool ' + pool);
- console.log(pool_data);
pools.set(pool, pool_data);
} catch (e) {
console.error('Unable to load pool data for pool ' + pool);
diff --git a/src/store/userSlice.ts b/src/store/userSlice.ts
index 6b21e5e..a674e9b 100644
--- a/src/store/userSlice.ts
+++ b/src/store/userSlice.ts
@@ -32,7 +32,7 @@ export const createUserSlice: StateCreator = (set,
const networkPassphrase = network.passphrase;
if (get().latestLedgerTimestamp == 0) {
- await get().loadBlendData(true, "CBYCVLEHLOVGH6XYYOMXNXWC3AVSYSRUXK3MHWKVIQSDF7JQ2YNEF2FN");
+ await get().loadBlendData(true, 'CBYCVLEHLOVGH6XYYOMXNXWC3AVSYSRUXK3MHWKVIQSDF7JQ2YNEF2FN');
}
const backstop = get().backstop;
diff --git a/src/theme.ts b/src/theme.ts
index 7f99519..b712232 100644
--- a/src/theme.ts
+++ b/src/theme.ts
@@ -51,12 +51,12 @@ const theme: Theme = createTheme({
mode: 'dark',
tonalOffset: 0,
background: {
- default: '#191B1F',
- paper: '#212429E5',
+ default: '#F1F3F4',
+ paper: '#ffffff',
},
primary: {
- main: '#36B04A',
- opaque: '#36B04A26',
+ main: '#185180',
+ opaque: '#b3e4ff',
contrastText: 'white',
},
secondary: {
@@ -68,8 +68,8 @@ const theme: Theme = createTheme({
opaque: '#00C4EF26',
},
borrow: {
- main: '#FF8A00',
- opaque: '#FF8A0026',
+ main: '#185180',
+ opaque: '#ffffff',
},
backstop: {
main: '#E16BFF',
@@ -80,7 +80,7 @@ const theme: Theme = createTheme({
opaque: '#2775C930',
},
accent: {
- main: '#191B1F',
+ main: '#ffffff',
opaque: '#191B1F',
},
menu: {
@@ -88,12 +88,12 @@ const theme: Theme = createTheme({
light: '#2E313893',
},
text: {
- primary: '#FFFFFF',
+ primary: '#185180',
secondary: '#979797',
},
warning: {
- main: '#FFCB00',
- opaque: '#FFCB0026',
+ main: '#fc1500',
+ opaque: '#fc150026',
},
error: {
main: '#FF3366',
diff --git a/tsconfig.json b/tsconfig.json
index 99710e8..73e4afb 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -13,7 +13,8 @@
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "preserve",
- "incremental": true
+ "incremental": true,
+ "downlevelIteration": true
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
"exclude": ["node_modules"]