diff --git a/.github/workflows/ci.protocol.yaml b/.github/workflows/ci.protocol.yaml
index 75000ea74f..58cb6fba87 100644
--- a/.github/workflows/ci.protocol.yaml
+++ b/.github/workflows/ci.protocol.yaml
@@ -6,7 +6,27 @@ on:
- "protocol/**"
jobs:
+ format:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v3
+ with:
+ ref: ${{ github.head_ref }}
+ - uses: actions/setup-node@v3
+ with:
+ node-version: "18"
+ - run: yarn add prettier
+ - run: yarn add prettier-plugin-solidity
+ - run: shopt -s globstar; yarn prettier --write --config .prettierrc --plugin=prettier-plugin-solidity protocol/**/*.sol || true
+ - name: Commit changes
+ uses: stefanzweifel/git-auto-commit-action@v4
+ with:
+ commit_message: prettier auto formatting changes
+ branch: ${{ github.head_ref }}
+ - name: check format
+ run: shopt -s globstar; yarn prettier --check --config .prettierrc --plugin=prettier-plugin-solidity protocol/**/*.sol
test:
+ needs: format
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
@@ -25,12 +45,8 @@ jobs:
- name: Install Dependencies
if: steps.node-modules-cache.outputs.cache-hit != 'true'
- run: yarn install --no-immutable
-
- - name: Generate (with cache)
- id: generate-with-cache
- continue-on-error: true
- run: yarn generate
+ run: yarn install --immutable
+ - run: yarn generate
working-directory: protocol
- name: Clear cache and reinstall on generate failure
diff --git a/.gitignore b/.gitignore
index 0ff7f1713b..bcce178b1d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -40,4 +40,6 @@ node_modules
# Local Netlify folder
.netlify
+# forge libraries.
+protocol/lib/
diff --git a/.gitmodules b/.gitmodules
index fd650d3ed0..842b0f598d 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,6 +1,3 @@
[submodule "protocol/lib/forge-std"]
path = protocol/lib/forge-std
url = https://github.com/foundry-rs/forge-std
-[submodule "protocol/lib/solmate"]
- path = protocol/lib/solmate
- url = https://github.com/transmissions11/solmate
diff --git a/.prettierrc b/.prettierrc
index 43834780bb..d80ec5f738 100644
--- a/.prettierrc
+++ b/.prettierrc
@@ -3,7 +3,19 @@
"singleQuote": false,
"semi": true,
"trailingComma": "none",
+ "plugins": ["prettier-plugin-solidity"],
"overrides": [
+ {
+ "files": "*.sol",
+ "options": {
+ "parser": "solidity-parse",
+ "printWidth": 100,
+ "tabWidth": 4,
+ "useTabs": false,
+ "singleQuote": false,
+ "bracketSpacing": false
+ }
+ },
{
"files": "projects/subgraph-*/**",
"options": {
diff --git a/.vscode/extensions.json b/.vscode/extensions.json
new file mode 100644
index 0000000000..6ffa8c983b
--- /dev/null
+++ b/.vscode/extensions.json
@@ -0,0 +1,7 @@
+{
+ "recommendations": [
+ "streetsidesoftware.code-spell-checker",
+ "esbenp.prettier-vscode",
+ "juanblanco.solidity"
+ ]
+}
\ No newline at end of file
diff --git a/.vscode/settings.json b/.vscode/settings.json
new file mode 100644
index 0000000000..ac7aa8d29e
--- /dev/null
+++ b/.vscode/settings.json
@@ -0,0 +1,4 @@
+{
+ "editor.formatOnSave": true,
+ "solidity.formatter": "prettier"
+}
\ No newline at end of file
diff --git a/package.json b/package.json
index b20e9d7273..83b3378217 100644
--- a/package.json
+++ b/package.json
@@ -16,7 +16,7 @@
"jest": "29.2.2",
"jest-serial-runner": "1.2.1",
"lint-staged": "13.3.0",
- "prettier": "3.2.5",
+ "prettier": "3.3.3",
"ts-jest": "29.1.2",
"ts-node": "10.9.2",
"typescript": "5.3.3"
@@ -42,13 +42,22 @@
"sdk:prettier": "yarn prettier projects/sdk -w",
"sdk:publish": "yarn workspace @beanstalk/sdk publish",
"sdk:version": "yarn workspace @beanstalk/sdk version",
+ "dex-ui:dev": "yarn workspace dex-ui dev",
+ "dex-ui:build": "yarn workspace dex-ui build",
+ "dex-ui:generate": "yarn workspace dex-ui generate",
"ui:generate": "yarn workspace ui generate",
+ "ui:dev": "yarn workspace ui dev",
"ui:start": "yarn workspace ui start",
"ui:build": "yarn workspace ui build",
"ui:test": "yarn workspace ui test",
"test:browser": "yarn workspace tests test:browser",
"ex": "yarn workspace @beanstalk/examples x",
+ "anvil-arbitrum": "yarn cli:anvil-arbitrum",
+ "anvil-eth-mainnet": "yarn cli:anvil-eth-mainnet",
"anvil": "anvil --fork-url https://eth-mainnet.g.alchemy.com/v2/5ubn94zT7v7DnB5bNW1VOnoIbX5-AG2N --chain-id 1337",
"anvil4tests": "anvil --fork-url https://eth-mainnet.g.alchemy.com/v2/Kk7ktCQL5wz4v4AG8bR2Gun8TAASQ-qi --chain-id 1337 --fork-block-number 18629000"
+ },
+ "dependencies": {
+ "prettier-plugin-solidity": "1.4.1"
}
}
diff --git a/projects/cli/.env.example b/projects/cli/.env.example
new file mode 100644
index 0000000000..a900f24edb
--- /dev/null
+++ b/projects/cli/.env.example
@@ -0,0 +1,5 @@
+# DEV API key
+DEV_ALCHEMY_API_KEY=""
+
+# Test API key
+DEV_TEST_ALCHEMY_API_KEY=""
diff --git a/projects/cli/.gitignore b/projects/cli/.gitignore
index dd87e2d73f..7f8efdeace 100644
--- a/projects/cli/.gitignore
+++ b/projects/cli/.gitignore
@@ -1,2 +1,4 @@
node_modules
build
+
+.env
\ No newline at end of file
diff --git a/projects/cli/anvil.sh b/projects/cli/anvil.sh
new file mode 100644
index 0000000000..da688875af
--- /dev/null
+++ b/projects/cli/anvil.sh
@@ -0,0 +1,48 @@
+#!/bin/bash
+
+source .env
+
+# Set variables based on arguments
+keyType="$1"
+chainIdType="$2"
+
+# Set chain IDs
+mainnet_local_chain_id=1338
+
+arbitrum_local_chain_id=1337
+
+# Determine which API key to use
+if [ "$keyType" = "test" ]; then
+ apiKey="$DEV_TEST_ALCHEMY_API_KEY"
+else
+ apiKey="$DEV_ALCHEMY_API_KEY"
+fi
+
+# Determine which chain ID to use. Defaults to arbitrum local host
+if [ "$chainIdType" = "eth-mainnet" ]; then
+ chainId=$mainnet_local_chain_id
+ prefix="eth"
+ port=9545
+else
+ chainId=$arbitrum_local_chain_id
+ prefix="arb"
+ port=8545
+fi
+
+# Check if required variables are set
+if [ -z "$prefix" ] || [ -z "$apiKey" ] || [ -z "$chainId" ]; then
+ echo "Error: Missing required variables. Please set keyType and chainIdType."
+ exit 1
+fi
+
+anvil \
+ --fork-url "https://$prefix-mainnet.g.alchemy.com/v2/$apiKey" \
+ --chain-id "$chainId" \
+ --port "$port" \
+ "${@:3}"
+
+# Check if Anvil exited with an error
+if [ $? -ne 0 ]; then
+ echo "Error: Anvil exited with a non-zero status."
+ exit 1
+fi
\ No newline at end of file
diff --git a/projects/cli/package.json b/projects/cli/package.json
index aeeac121f1..f06eaa79e5 100644
--- a/projects/cli/package.json
+++ b/projects/cli/package.json
@@ -1,6 +1,6 @@
{
"name": "@beanstalk/cli",
- "version": "0.0.10",
+ "version": "0.0.20",
"description": "Beanstalk protocol development cli tool",
"license": "MIT",
"repository": {
@@ -16,7 +16,11 @@
"scripts": {
"cli:publish": "yarn cli:build && yarn npm publish --access public",
"cli:build": "rimraf build && tsc && chmod u+x build/cli.js",
- "g:bean": "yarn ts-node-esm src/cli.ts"
+ "g:bean": "yarn ts-node-esm src/cli.ts",
+ "cli:anvil-eth-mainnet": "bash anvil.sh dev eth-mainnet",
+ "cli:anvil-arbitrum": "bash anvil.sh dev arbitrum-mainnet",
+ "cli:anvil4tests-mainnet": "bash anvil.sh test eth-mainnet --fork-block-number 18629000",
+ "cli:anvil4tests-arbitrum": "bash anvil.sh test arbitrum-mainnet --fork-block-number 18629000"
},
"devDependencies": {
"@types/command-line-args": "^5.2.3",
diff --git a/projects/cli/src/commands/balance.ts b/projects/cli/src/commands/balance.ts
index 5f1b665f54..5f258255db 100644
--- a/projects/cli/src/commands/balance.ts
+++ b/projects/cli/src/commands/balance.ts
@@ -14,16 +14,21 @@ export const balance = async (sdk, { account, symbol }) => {
[
"ETH",
"WETH",
+ "WSTETH",
+ "WEETH",
+ "WBTC",
"BEAN",
- "USDT",
- "USDC",
"DAI",
- "CRV3",
- "UNRIPE_BEAN",
- "UNRIPE_BEAN_wstETH",
- "BEAN_CRV3_LP",
- "BEAN_ETH_WELL_LP",
- "ROOT"
+ "USDC",
+ "USDT",
+ "urBEAN",
+ "urBEANWSTETH",
+ "BEANWETH",
+ "BEANWEETH",
+ "BEANWEETH",
+ "BEANWBTC",
+ "BEANUSDC",
+ "BEANUSDT"
].map((s) => getBal(sdk, s, account))
);
res.push(...bals);
@@ -32,7 +37,17 @@ export const balance = async (sdk, { account, symbol }) => {
};
async function getBal(sdk, symbol: string, account: string) {
- const token = sdk.tokens[symbol];
+ let token = sdk.tokens[symbol];
+ if (!token) {
+ if (symbol === "urBEAN") token = sdk.tokens.UNRIPE_BEAN;
+ if (symbol === "urBEANWSTETH") token = sdk.tokens.UNRIPE_BEAN_WSTETH;
+ if (symbol === "BEANWETH") token = sdk.tokens.BEAN_ETH_WELL_LP;
+ if (symbol === "BEANWEETH") token = sdk.tokens.BEAN_WEETH_WELL_LP;
+ if (symbol === "BEANWSTETH") token = sdk.tokens.BEAN_WSTETH_WELL_LP;
+ if (symbol === "BEANWBTC") token = sdk.tokens.BEAN_WBTC_WELL_LP;
+ if (symbol === "BEANUSDC") token = sdk.tokens.BEAN_USDC_WELL_LP;
+ if (symbol === "BEANUSDT") token = sdk.tokens.BEAN_USDT_WELL_LP;
+ }
if (!token) throw new Error(`No token found: ${symbol}`);
try {
diff --git a/projects/cli/src/commands/setbalance.ts b/projects/cli/src/commands/setbalance.ts
index f75d0346e4..a4a38a5554 100644
--- a/projects/cli/src/commands/setbalance.ts
+++ b/projects/cli/src/commands/setbalance.ts
@@ -14,16 +14,21 @@ export const setbalance = async (sdk, chain, { account, symbol, amount }) => {
const symbols = [
"ETH",
"WETH",
+ "WSTETH",
+ "WEETH",
+ "WBTC",
"BEAN",
- "USDT",
- "USDC",
"DAI",
- "CRV3",
- "BEAN3CRV",
- "BEANWETH",
+ "USDC",
+ "USDT",
"urBEAN",
- "urBEANwstETH",
- "ROOT"
+ "urBEANWSTETH",
+ "BEANWETH",
+ "BEANWSTETH",
+ "BEANWEETH",
+ "BEANWBTC",
+ "BEANUSDC",
+ "BEANUSDT"
];
if (!symbols.includes(symbol)) {
console.log(
@@ -33,10 +38,16 @@ export const setbalance = async (sdk, chain, { account, symbol, amount }) => {
process.exit(-1);
}
let t = sdk.tokens[symbol] as Token;
- if (symbol === "urBEAN") t = sdk.tokens.UNRIPE_BEAN;
- if (symbol === "urBEANwstETH") t = sdk.tokens.UNRIPE_BEAN_WSTETH;
- if (symbol === "BEAN3CRV") t = sdk.tokens.BEAN_CRV3_LP;
- if (symbol === "BEANWETH") t = sdk.tokens.BEAN_ETH_WELL_LP;
+ if (!t) {
+ if (symbol === "urBEAN") t = sdk.tokens.UNRIPE_BEAN;
+ if (symbol === "urBEANWSTETH") t = sdk.tokens.UNRIPE_BEAN_WSTETH;
+ if (symbol === "BEANWETH") t = sdk.tokens.BEAN_ETH_WELL_LP;
+ if (symbol === "BEANWEETH") t = sdk.tokens.BEAN_WEETH_WELL_LP;
+ if (symbol === "BEANWSTETH") t = sdk.tokens.BEAN_WSTETH_WELL_LP;
+ if (symbol === "BEANWBTC") t = sdk.tokens.BEAN_WBTC_WELL_LP;
+ if (symbol === "BEANUSDC") t = sdk.tokens.BEAN_USDC_WELL_LP;
+ if (symbol === "BEANUSDT") t = sdk.tokens.BEAN_USDT_WELL_LP;
+ }
if (typeof chain[`set${symbol}Balance`] !== "function")
throw new Error(`${symbol} is not a valid token or the method ${chalk.bold.whiteBright("")}`);
diff --git a/projects/cli/src/commands/setprice.ts b/projects/cli/src/commands/setprice.ts
index 6b9caacd52..66c9254d47 100644
--- a/projects/cli/src/commands/setprice.ts
+++ b/projects/cli/src/commands/setprice.ts
@@ -14,18 +14,18 @@ export const setPrice = async (sdk: BeanstalkSDK, chain: TestUtils.BlockchainUti
console.log(beanInput, crv3Input);
const newBeanAmount = (beanInput ? beanInput : 20) * 1_000_000;
- const newCrv3Amount = (crv3Input ? crv3Input : beanInput ? beanInput : 20) * 1_000_000;
+ // const newCrv3Amount = (crv3Input ? crv3Input : beanInput ? beanInput : 20) * 1_000_000;
- const newBean = sdk.tokens.BEAN.amount(newBeanAmount);
- const newCrv3 = sdk.tokens.CRV3.amount(newCrv3Amount);
+ // const newBean = sdk.tokens.BEAN.amount(newBeanAmount);
+ // const newCrv3 = sdk.tokens.CRV3.amount(newCrv3Amount);
////// Set the new balance
- console.log(`New Balances: ${newBean.toHuman()} ${newCrv3.toHuman()}`);
+ // console.log(`New Balances: ${newBean.toHuman()} ${newCrv3.toHuman()}`);
// update the array tracking balances
- await setBalance(sdk, POOL_ADDRESS, BALANCE_SLOT, newBean, newCrv3);
+ // await setBalance(sdk, POOL_ADDRESS, BALANCE_SLOT, newBean, newCrv3);
// actually give the pool the ERC20's
- await chain.setBEANBalance(POOL_ADDRESS, newBean);
- await chain.setCRV3Balance(POOL_ADDRESS, newCrv3);
+ // await chain.setBEANBalance(POOL_ADDRESS, newBean);
+ // await chain.setCRV3Balance(POOL_ADDRESS, newCrv3);
// Curve also keeps track of the previous balance, so we just copy the existing current to old.
await setBalance(sdk, POOL_ADDRESS, PREV_BALANCE_SLOT, currentBean, currentCrv3);
diff --git a/projects/dex-ui/.env.local.example b/projects/dex-ui/.env.local.example
index c15b585eca..ad84550116 100644
--- a/projects/dex-ui/.env.local.example
+++ b/projects/dex-ui/.env.local.example
@@ -1,5 +1,7 @@
-VITE_AQUIFER_ADDRESS=local/fork deployed address
+VITE_AQUIFER_ADDRESS_ETH="deployed address here"
+VITE_AQUIFER_ADDRESS_ARBITRUM="deployed address here"
VITE_ALCHEMY_API_KEY="your key here"
+VITE_THEGRAPH_API_KEY="your key here"
+VITE_WALLETCONNECT_PROJECT_ID="project key here"
VITE_WELLS_ORIGIN_BLOCK=17138465
-VITE_LOAD_HISTORY_FROM_GRAPH=0
-VITE_WALLET_CONNECT_PROJECT_ID="project key here"
\ No newline at end of file
+VITE_LOAD_HISTORY_FROM_GRAPH=0
\ No newline at end of file
diff --git a/projects/dex-ui/.env.production b/projects/dex-ui/.env.production
index 0df3966e5a..87359512ec 100644
--- a/projects/dex-ui/.env.production
+++ b/projects/dex-ui/.env.production
@@ -1,5 +1,10 @@
// DO NOT ACTUALLY SAVE THINGS HERE
// ONLY USE THIS FILE TO TRACK WHAT ENV VARS NEED TO
// BE ADDED TO NETLIFY CONFIG
+VITE_AQUIFER_ADDRESS_ETH=""
+VITE_AQUIFER_ADDRESS_ARBITRUM=""
VITE_ALCHEMY_API_KEY=""
-VITE_WALLET_CONNECT_PROJECT_ID=""
\ No newline at end of file
+VITE_THEGRAPH_API_KEY=""
+VITE_WALLETCONNECT_PROJECT_ID=""
+VITE_WELLS_ORIGIN_BLOCK=""
+VITE_LOAD_HISTORY_FROM_GRAPH=""
\ No newline at end of file
diff --git a/projects/dex-ui/.eslintrc b/projects/dex-ui/.eslintrc
index 5e526b6a46..f2fa3d80af 100644
--- a/projects/dex-ui/.eslintrc
+++ b/projects/dex-ui/.eslintrc
@@ -2,12 +2,21 @@
"settings": {
"react": {
"version": "detect"
+ },
+ "import/resolver": {
+ "typescript": {},
+ "node": {
+ "paths": ["src"],
+ "extensions": [".js", ".jsx", ".ts", ".tsx"]
+ }
}
},
"extends": [
"plugin:react/recommended",
"plugin:jsx-a11y/recommended",
// "plugin:@typescript-eslint/recommended",
+ // "plugin:import/errors",
+ // "plugin:import/warnings",
"plugin:import/typescript"
],
"parser": "@typescript-eslint/parser",
@@ -18,13 +27,7 @@
"ecmaVersion": "latest",
"sourceType": "module"
},
- "plugins": [
- "react",
- "react-hooks",
- "@typescript-eslint",
- "import",
- "jsx-a11y"
- ],
+ "plugins": ["react", "react-hooks", "@typescript-eslint", "import", "jsx-a11y"],
"rules": {
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/no-non-null-assertion": "off",
@@ -39,6 +42,41 @@
"react-hooks/rules-of-hooks": "error",
"react-hooks/exhaustive-deps": "warn",
"react/prop-types": 0,
- "react/display-name": 0
+ "react/display-name": 0,
+ "import/order": [
+ "warn",
+ {
+ "groups": [
+ "builtin",
+ "external",
+ "internal",
+ ["parent", "sibling", "index"],
+ "object",
+ "type"
+ ],
+ "pathGroups": [
+ {
+ "pattern": "react",
+ "group": "external",
+ "position": "before"
+ },
+ {
+ "pattern": "@beanstalk/sdk*",
+ "group": "external",
+ "position": "after"
+ },
+ {
+ "pattern": "src/**",
+ "group": "internal"
+ }
+ ],
+ "pathGroupsExcludedImportTypes": ["react", "@beanstalk/sdk*"],
+ "alphabetize": {
+ "order": "asc",
+ "caseInsensitive": true
+ },
+ "newlines-between": "always"
+ }
+ ]
}
-}
\ No newline at end of file
+}
diff --git a/projects/dex-ui/codegen.ts b/projects/dex-ui/codegen.ts
index 07d4686e04..526d09bdca 100644
--- a/projects/dex-ui/codegen.ts
+++ b/projects/dex-ui/codegen.ts
@@ -5,7 +5,8 @@ const config: CodegenConfig = {
schema: [
"graphql.schema.json",
// beanstalk subgraph
- "https://graph.node.bean.money/subgraphs/name/beanstalk"
+ "https://graph.bean.money/beanstalk",
+ "https://graph.bean.money/beanstalk_eth"
],
documents: "src/**/*.graphql",
ignoreNoDocuments: true,
diff --git a/projects/dex-ui/package.json b/projects/dex-ui/package.json
index a01c41b755..f63f669919 100644
--- a/projects/dex-ui/package.json
+++ b/projects/dex-ui/package.json
@@ -30,6 +30,7 @@
"connectkit": "1.7.2",
"ethers": "^5.7.2",
"graphql-request": "5.2.0",
+ "jotai": "2.9.3",
"lightweight-charts": "4.1.3",
"prettier": "3.2.5",
"react": "^18.2.0",
diff --git a/projects/dex-ui/src/assets/images/tokens/ARB.svg b/projects/dex-ui/src/assets/images/tokens/ARB.svg
new file mode 100644
index 0000000000..d6b9a7527d
--- /dev/null
+++ b/projects/dex-ui/src/assets/images/tokens/ARB.svg
@@ -0,0 +1,30 @@
+
\ No newline at end of file
diff --git a/projects/dex-ui/src/assets/images/tokens/WBTC.svg b/projects/dex-ui/src/assets/images/tokens/WBTC.svg
new file mode 100644
index 0000000000..2940e9c232
--- /dev/null
+++ b/projects/dex-ui/src/assets/images/tokens/WBTC.svg
@@ -0,0 +1,10 @@
+
\ No newline at end of file
diff --git a/projects/dex-ui/src/assets/images/tokens/index.tsx b/projects/dex-ui/src/assets/images/tokens/index.tsx
index 59963997b8..840c4c8c34 100644
--- a/projects/dex-ui/src/assets/images/tokens/index.tsx
+++ b/projects/dex-ui/src/assets/images/tokens/index.tsx
@@ -1,12 +1,16 @@
-const glob = import.meta.glob("src/assets/images/tokens/*.svg", {
- eager: true,
- as: "url"
- // import: "default"
-});
+const glob = import.meta.glob(
+ ["src/assets/images/tokens/*.svg", "src/assets/images/tokens/*.png"],
+ {
+ eager: true,
+ as: "url"
+ }
+);
export const images: Record = {};
for (const key of Object.keys(glob)) {
- let symbol = key.replace("/src/assets/images/tokens/", "").replace(".svg", "");
+ const parts = key.split("/");
+ const filename = parts[parts.length - 1];
+ const symbol = filename.replace(/\.(svg|png)$/, "");
images[symbol] = glob[key];
}
diff --git a/projects/dex-ui/src/assets/images/tokens/weETH.png b/projects/dex-ui/src/assets/images/tokens/weETH.png
new file mode 100644
index 0000000000..e0ba7d239a
Binary files /dev/null and b/projects/dex-ui/src/assets/images/tokens/weETH.png differ
diff --git a/projects/dex-ui/src/components/App/App.tsx b/projects/dex-ui/src/components/App/App.tsx
index cacac60c7c..c87014302f 100644
--- a/projects/dex-ui/src/components/App/App.tsx
+++ b/projects/dex-ui/src/components/App/App.tsx
@@ -1,33 +1,40 @@
import React from "react";
+
import { Route, Routes } from "react-router-dom";
+
+import { Frame } from "src/components/Frame/Frame";
import { NotFound } from "src/pages/404";
-import { Home } from "src/pages/Home";
+import { Build } from "src/pages/Build";
+import { Create } from "src/pages/Create";
import { Dev } from "src/pages/Dev";
+import { Home } from "src/pages/Home";
+import { Liquidity } from "src/pages/Liquidity";
+import { Swap } from "src/pages/Swap";
import { Well } from "src/pages/Well";
import { Wells } from "src/pages/Wells";
-import { Frame } from "src/components/Frame/Frame";
-import { Build } from "src/pages/Build";
-import { Swap } from "src/pages/Swap";
import { Settings } from "src/settings";
-import { Liquidity } from "src/pages/Liquidity";
-import { Create } from "src/pages/Create";
+
+import { ForceSupportedChainId } from "./ForceSupportedChainId";
export const App = ({}) => {
const isNotProd = !Settings.PRODUCTION;
return (
-
-
- } />
- } />
- } />
- } />
- } />
- } />
- } />
- {isNotProd && } />}
- } />
-
-
+ <>
+
+
+
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ {isNotProd && } />}
+ } />
+
+
+ >
);
};
diff --git a/projects/dex-ui/src/components/App/ForceSupportedChainId.tsx b/projects/dex-ui/src/components/App/ForceSupportedChainId.tsx
new file mode 100644
index 0000000000..d85ea732bd
--- /dev/null
+++ b/projects/dex-ui/src/components/App/ForceSupportedChainId.tsx
@@ -0,0 +1,197 @@
+import React, { useEffect, useState } from "react";
+
+import { ConnectKitButton, useModal } from "connectkit";
+import { useLocation, useNavigate } from "react-router-dom";
+import styled from "styled-components";
+
+import { ChainId, ChainResolver } from "@beanstalk/sdk-core";
+
+import { ChainIdError, useChainErr, useSetChainErr } from "src/state/atoms/chain.atoms";
+import { useSdkChainId } from "src/utils/chain";
+import { theme } from "src/utils/ui/theme";
+
+import { ButtonPrimary } from "../Button";
+import { Logo } from "../Icons";
+import { Flex } from "../Layout";
+import { Modal } from "../Modal";
+import { LinksNav, Text } from "../Typography";
+
+const UNSUPPORTED_CHAIN_ID = -1;
+
+/**
+ *
+ * @returns
+ * - Returns -1 if unsupported chainId (e.g., Not ETH or Arbitrum)
+ * - Returns chainId if supported
+ */
+function parseChainIdFromPath(location: ReturnType) {
+ const segments = location.pathname.split("/");
+ const first = segments?.[1];
+
+ if (first?.toLowerCase() !== "wells") return;
+
+ const chainId = segments?.[2];
+
+ try {
+ const cidNum = parseInt(chainId);
+ if (Object.values(ChainId).includes(cidNum)) {
+ return cidNum;
+ }
+ } catch (_e: any) {
+ // do nothing;
+ }
+
+ return UNSUPPORTED_CHAIN_ID;
+}
+
+function getNavigateUrl(
+ toChainId: ChainId,
+ location: ReturnType,
+ stay: boolean
+) {
+ const segments = location.pathname.split("/");
+ const first = segments?.[1];
+
+ if (first?.toLowerCase() === "wells") {
+ const address = segments?.[3];
+ const addressPortion = address && stay ? `/${address}` : "";
+ return `/wells/${toChainId}${addressPortion}`;
+ }
+ return `/`;
+}
+
+const CHAIN_ID_TO_NAME = {
+ [ChainId.ETH_MAINNET]: "Ethereum Mainnet",
+ [ChainId.ARBITRUM_MAINNET]: "Arbitrum Mainnet"
+};
+
+export const ForceSupportedChainId = () => {
+ const location = useLocation();
+ const navigate = useNavigate();
+ const setChainErr = useSetChainErr();
+ const [navLink, setNavLink] = useState(null);
+
+ const urlChainId = parseChainIdFromPath(location);
+ const chainId = useSdkChainId();
+ const chainIdErr = useChainErr();
+
+ const { openSwitchNetworks, setOpen } = useModal();
+
+ const handleStayOnCurrentNetwork = () => {
+ navigate(getNavigateUrl(chainId, location, false));
+ };
+
+ const handleSetSwitchNetworkUrl = () => {
+ if (urlChainId) {
+ setNavLink(getNavigateUrl(urlChainId, location, true));
+ }
+ };
+
+ useEffect(() => {
+ if (chainId !== urlChainId) return;
+ if (navLink) {
+ const url = navLink;
+ setOpen(false);
+ setNavLink(null);
+ navigate(url);
+ }
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [chainId, urlChainId, navLink]);
+
+ useEffect(() => {
+ if (urlChainId) {
+ if (urlChainId === UNSUPPORTED_CHAIN_ID) {
+ setChainErr(ChainIdError.INVALID);
+ return;
+ } else if (
+ ChainId[urlChainId] &&
+ ChainResolver.resolveToMainnetChainId(urlChainId) !==
+ ChainResolver.resolveToMainnetChainId(chainId)
+ ) {
+ setChainErr(ChainIdError.INCORRECT);
+ return;
+ }
+ }
+
+ if (!!chainIdErr) {
+ setChainErr(null);
+ }
+ }, [chainIdErr, location, urlChainId, chainId, setChainErr]);
+
+ return (
+ <>
+ {}}>
+
+
+
+
+
+ BASIN
+
+
+ {chainIdErr === ChainIdError.INVALID ? (
+ <>
+ This network is not supported
+
+ Basin is currently only available on Ethereum and Arbitrum Mainnet.
+
+ >
+ ) : null}
+ {chainIdErr === ChainIdError.INCORRECT && urlChainId ? (
+ <>
+ Looks like you're connected to the wrong network
+
+ Switch to{" "}
+ {CHAIN_ID_TO_NAME[ChainResolver.resolveToMainnetChainId(urlChainId)]} or stay
+ on this network to continue.
+
+ >
+ ) : null}
+
+
+
+ {() => {
+ return (
+ {
+ e.preventDefault();
+ openSwitchNetworks();
+ handleSetSwitchNetworkUrl();
+ }}
+ >
+ Switch Network
+
+ );
+ }}
+
+ {chainIdErr === ChainIdError.INCORRECT ? (
+
+ Stay on {CHAIN_ID_TO_NAME[ChainResolver.resolveToMainnetChainId(chainId)]}
+
+ ) : null}
+
+
+
+
+
+ >
+ );
+};
+
+const ModalContentWrapper = styled(Flex)`
+ max-width: 290px;
+ min-width: 290px;
+ width: 100%;
+
+ ${theme.media.query.sm.only} {
+ min-width: min(calc(100vw - 96px), 400px);
+ max-width: min(calc(100vw - 96px), 400px);
+ width: 100%;
+ }
+`;
+
+const Brand = styled.div`
+ text-transform: uppercase;
+ ${LinksNav};
+ margin-bottom: -6px;
+`;
diff --git a/projects/dex-ui/src/components/App/OnLoad.tsx b/projects/dex-ui/src/components/App/OnLoad.tsx
index 963a730e45..a15f182327 100644
--- a/projects/dex-ui/src/components/App/OnLoad.tsx
+++ b/projects/dex-ui/src/components/App/OnLoad.tsx
@@ -1,7 +1,9 @@
import React, { useEffect } from "react";
+
+import { useAccount } from "wagmi";
+
import { useAllTokensBalance } from "src/tokens/useAllTokenBalance";
import { FC } from "src/types";
-import { useAccount } from "wagmi";
export const OnLoad: FC<{}> = ({ children }) => {
const { address, chain } = useAccount();
@@ -13,20 +15,20 @@ export const OnLoad: FC<{}> = ({ children }) => {
refetch();
}, [address, chain?.id, refetch]);
- // useEffect(() => {
- // const unwatch = watchAccount(config, {
- // onChange(account, prevAccount) {
- // // if (account.chain?.id !== chain?.id) {
- // // console.log("CHECK ME");
- // // }
- // // if (prevAccount.address !== account.address) {
- // // console.log(`CHANGED! - from(${prevAccount.address}) to => ${account.address}`);
- // // }
- // }
- // });
-
- // return () => unwatch();
- // });
-
return <>{children}>;
};
+
+// useEffect(() => {
+// const unwatch = watchAccount(config, {
+// onChange(account, prevAccount) {
+// // if (account.chain?.id !== chain?.id) {
+// // console.log("CHECK ME");
+// // }
+// // if (prevAccount.address !== account.address) {
+// // console.log(`CHANGED! - from(${prevAccount.address}) to => ${account.address}`);
+// // }
+// }
+// });
+
+// return () => unwatch();
+// });
diff --git a/projects/dex-ui/src/components/App/Wrapper.tsx b/projects/dex-ui/src/components/App/Wrapper.tsx
index ef4c809edf..0d5148f122 100644
--- a/projects/dex-ui/src/components/App/Wrapper.tsx
+++ b/projects/dex-ui/src/components/App/Wrapper.tsx
@@ -1,16 +1,18 @@
import React from "react";
-import { HashRouter } from "react-router-dom";
-import { FC } from "src/types";
-import { ConnectKitProvider } from "connectkit";
-import { WagmiProvider } from "wagmi";
+
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { ReactQueryDevtools } from "@tanstack/react-query-devtools";
+import { ConnectKitProvider } from "connectkit";
+import { HashRouter } from "react-router-dom";
+import { WagmiProvider } from "wagmi";
+
+import JotaiProvider from "src/state";
+import { FC } from "src/types";
import { Avatar } from "src/utils/wagmi/Avatar";
-import { TokenProvider } from "src/tokens/TokenProvider";
-import { OnLoad } from "./OnLoad";
-import { SdkProvider } from "src/utils/sdk/SdkProvider";
import { config } from "src/utils/wagmi/config";
+import { OnLoad } from "./OnLoad";
+
export const Wrapper: FC<{}> = ({ children }) => {
const queryClient = new QueryClient();
return (
@@ -31,11 +33,9 @@ export const Wrapper: FC<{}> = ({ children }) => {
}}
>
-
-
- {children}
-
-
+
+ {children}
+
diff --git a/projects/dex-ui/src/components/BottomDrawer.tsx b/projects/dex-ui/src/components/BottomDrawer.tsx
index 09d4629fcf..9257a81661 100644
--- a/projects/dex-ui/src/components/BottomDrawer.tsx
+++ b/projects/dex-ui/src/components/BottomDrawer.tsx
@@ -1,10 +1,13 @@
import React from "react";
-import { FC } from "src/types";
+
import styled from "styled-components";
-import { BodyXS } from "./Typography";
+
import x from "src/assets/images/x.svg";
-import { ImageButton } from "./ImageButton";
import { size } from "src/breakpoints";
+import { FC } from "src/types";
+
+import { ImageButton } from "./ImageButton";
+import { BodyXS } from "./Typography";
interface Composition {
Header: typeof Header;
@@ -26,7 +29,12 @@ type Props = {
toggleDrawer?: (isDrawerOpen: boolean) => void;
};
-export const BottomDrawer: FC & Composition = ({ children, showDrawer, headerText, toggleDrawer }) => {
+export const BottomDrawer: FC & Composition = ({
+ children,
+ showDrawer,
+ headerText,
+ toggleDrawer
+}) => {
return (
<>
diff --git a/projects/dex-ui/src/components/Button.tsx b/projects/dex-ui/src/components/Button.tsx
index 2a1df8b064..f2b6737050 100644
--- a/projects/dex-ui/src/components/Button.tsx
+++ b/projects/dex-ui/src/components/Button.tsx
@@ -1,4 +1,7 @@
import React, { ButtonHTMLAttributes, CSSProperties, forwardRef } from "react";
+
+import styled from "styled-components";
+
import {
CommonCssProps,
CommonCssStyles,
@@ -7,7 +10,7 @@ import {
makeCssStyle
} from "src/utils/ui/styled";
import { theme } from "src/utils/ui/theme";
-import styled from "styled-components";
+
import { Spinner } from "./Spinner";
export type ButtonVariant = "outlined" | "contained"; // | "text" (Add Text Variant later)
diff --git a/projects/dex-ui/src/components/Checkbox.tsx b/projects/dex-ui/src/components/Checkbox.tsx
index 22b82c7cdf..9447c2309b 100644
--- a/projects/dex-ui/src/components/Checkbox.tsx
+++ b/projects/dex-ui/src/components/Checkbox.tsx
@@ -1,8 +1,11 @@
-import { FC } from "src/types";
import React from "react";
+
import styled from "styled-components";
-import { BodyXS } from "./Typography";
+
import { size } from "src/breakpoints";
+import { FC } from "src/types";
+
+import { BodyXS } from "./Typography";
type Props = {
label?: string;
@@ -12,12 +15,23 @@ type Props = {
onClick?: () => void;
};
-export const Checkbox: FC = ({ label, checked = false, mode, checkboxColor = "black", onClick = () => {} }) => {
+export const Checkbox: FC = ({
+ label,
+ checked = false,
+ mode,
+ checkboxColor = "black",
+ onClick = () => {}
+}) => {
return (
-
+
{checked && (
`
- border: 1px solid ${(props) => (props.checkboxColor && props.checked ? props.checkboxColor : "#000")};
+ border: 1px solid
+ ${(props) => (props.checkboxColor && props.checked ? props.checkboxColor : "#000")};
width: 16px;
height: 16px;
position: ${(props) => (props.mode === "checkOnly" ? "relative" : "absolute")};
diff --git a/projects/dex-ui/src/components/Create/ComponentLibraryTable.tsx b/projects/dex-ui/src/components/Create/ComponentLibraryTable.tsx
index a442972848..87123e69f2 100644
--- a/projects/dex-ui/src/components/Create/ComponentLibraryTable.tsx
+++ b/projects/dex-ui/src/components/Create/ComponentLibraryTable.tsx
@@ -1,10 +1,12 @@
import React from "react";
+
+import { Link } from "react-router-dom";
import styled from "styled-components";
import { Table, Td, THead, ResponsiveTr, Th, TBody, Row } from "src/components//Table";
-import { Link } from "react-router-dom";
-import { theme } from "src/utils/ui/theme";
import { Text } from "src/components/Typography";
+import { theme } from "src/utils/ui/theme";
+
import { useWhitelistedWellComponents } from "./useWhitelistedWellComponents";
export const ComponentLibraryTable = () => {
diff --git a/projects/dex-ui/src/components/Create/CreateWellProvider.tsx b/projects/dex-ui/src/components/Create/CreateWellProvider.tsx
index bc9b2a8a44..f41c68e746 100644
--- a/projects/dex-ui/src/components/Create/CreateWellProvider.tsx
+++ b/projects/dex-ui/src/components/Create/CreateWellProvider.tsx
@@ -1,14 +1,19 @@
import React, { createContext, useCallback, useMemo, useState } from "react";
-import { ERC20Token, TokenValue } from "@beanstalk/sdk-core";
+
import { DeepRequired } from "react-hook-form";
-import useSdk from "src/utils/sdk/useSdk";
-import { Log } from "src/utils/logger";
-import { Pump, WellFunction } from "@beanstalk/sdk-wells";
import { useAccount } from "wagmi";
-import { usePumps } from "src/wells/pump/usePumps";
+
+import { ERC20Token, TokenValue } from "@beanstalk/sdk-core";
+import { Pump, WellFunction } from "@beanstalk/sdk-wells";
+
+import { clearWellsCache } from "src/state/providers/WellsProvider";
+import { Log } from "src/utils/logger";
+import { queryKeys } from "src/utils/query/queryKeys";
+import { useFetchChainScopedQueryData } from "src/utils/query/useChainScopedQuery";
+import useSdk from "src/utils/sdk/useSdk";
+import { useAquifer } from "src/wells/aquifer/aquifer";
import BoreWellUtils from "src/wells/boreWell";
-import { clearWellsCache } from "src/wells/useWells";
-import { useQueryClient } from "@tanstack/react-query";
+import { usePumps } from "src/wells/pump/usePumps";
/**
* Architecture notes: @Space-Bean
@@ -123,7 +128,8 @@ export const CreateWellProvider = ({ children }: { children: React.ReactNode })
const { address: walletAddress } = useAccount();
const sdk = useSdk();
const pumps = usePumps();
- const queryClient = useQueryClient();
+ const aquifer = useAquifer();
+ const fetchScopedQueryData = useFetchChainScopedQueryData();
/// ----- Local State -----
const [deploying, setDeploying] = useState(false);
@@ -242,6 +248,7 @@ export const CreateWellProvider = ({ children }: { children: React.ReactNode })
const { wellAddress } = await BoreWellUtils.boreWell(
sdk,
+ aquifer,
walletAddress,
wellImplementation,
wellFunction,
@@ -255,7 +262,7 @@ export const CreateWellProvider = ({ children }: { children: React.ReactNode })
);
clearWellsCache();
- queryClient.fetchQuery({ queryKey: ["wells", sdk] });
+ fetchScopedQueryData(queryKeys.wells(sdk));
Log.module("wellDeployer").debug("Well deployed at address: ", wellAddress || "");
setDeploying(false);
@@ -268,7 +275,6 @@ export const CreateWellProvider = ({ children }: { children: React.ReactNode })
},
[
pumpAddress,
- queryClient,
walletAddress,
wellImplementation,
wellFunction,
@@ -277,7 +283,9 @@ export const CreateWellProvider = ({ children }: { children: React.ReactNode })
wellTokens.token2,
wellDetails.name,
wellDetails.symbol,
- sdk
+ sdk,
+ aquifer,
+ fetchScopedQueryData
]
);
diff --git a/projects/dex-ui/src/components/Create/CreateWellStep1.tsx b/projects/dex-ui/src/components/Create/CreateWellStep1.tsx
index a7b83dea74..9a600a5692 100644
--- a/projects/dex-ui/src/components/Create/CreateWellStep1.tsx
+++ b/projects/dex-ui/src/components/Create/CreateWellStep1.tsx
@@ -1,13 +1,15 @@
import React from "react";
+
+import { FormProvider, useForm } from "react-hook-form";
+import styled from "styled-components";
+
import { Flex } from "src/components/Layout";
import { Text } from "src/components/Typography";
+import { theme } from "src/utils/ui/theme";
-import { FormProvider, useForm } from "react-hook-form";
import { CreateWellStepProps, useCreateWell } from "./CreateWellProvider";
import { ComponentInputWithCustom } from "./shared/ComponentInputWithCustom";
import { CreateWellButtonRow } from "./shared/CreateWellButtonRow";
-import styled from "styled-components";
-import { theme } from "src/utils/ui/theme";
import { StyledForm } from "../Form";
type FormValues = CreateWellStepProps["step1"];
diff --git a/projects/dex-ui/src/components/Create/CreateWellStep2.tsx b/projects/dex-ui/src/components/Create/CreateWellStep2.tsx
index 8a1aa9ca53..998f0da273 100644
--- a/projects/dex-ui/src/components/Create/CreateWellStep2.tsx
+++ b/projects/dex-ui/src/components/Create/CreateWellStep2.tsx
@@ -1,24 +1,28 @@
import React, { useEffect, useMemo, useState } from "react";
-import styled from "styled-components";
+
import { FormProvider, useForm, useFormContext, useWatch } from "react-hook-form";
-import { getIsValidEthereumAddress } from "src/utils/addresses";
-import { theme } from "src/utils/ui/theme";
-import { Divider, Flex, FlexCard } from "src/components/Layout";
-import { Text } from "src/components/Typography";
-import { CreateWellButtonRow } from "./shared/CreateWellButtonRow";
+import styled from "styled-components";
+
+import { ERC20Token } from "@beanstalk/sdk";
+
+import { images } from "src/assets/images/tokens";
+import { Dropdown } from "src/components/Dropdown";
import { StyledForm, TextInputField } from "src/components/Form";
import { XIcon } from "src/components/Icons";
-import { CreateWellStepProps, useCreateWell } from "./CreateWellProvider";
-import { CreateWellFormProgress } from "./shared/CreateWellFormProgress";
-import { ComponentInputWithCustom } from "./shared/ComponentInputWithCustom";
+import { Divider, Flex, FlexCard } from "src/components/Layout";
+import { Text } from "src/components/Typography";
import { useERC20TokenWithAddress } from "src/tokens/useERC20Token";
-import { ERC20Token } from "@beanstalk/sdk";
+import { getIsValidEthereumAddress } from "src/utils/addresses";
import useSdk from "src/utils/sdk/useSdk";
+import { theme } from "src/utils/ui/theme";
+import { useBoolean } from "src/utils/ui/useBoolean";
import BoreWellUtils from "src/wells/boreWell";
import { useValidateWellFunction } from "src/wells/wellFunction/useValidateWellFunction";
-import { useBoolean } from "src/utils/ui/useBoolean";
-import { Dropdown } from "src/components/Dropdown";
-import { images } from "src/assets/images/tokens";
+
+import { CreateWellStepProps, useCreateWell } from "./CreateWellProvider";
+import { ComponentInputWithCustom } from "./shared/ComponentInputWithCustom";
+import { CreateWellButtonRow } from "./shared/CreateWellButtonRow";
+import { CreateWellFormProgress } from "./shared/CreateWellFormProgress";
const additionalOptions = [
{
diff --git a/projects/dex-ui/src/components/Create/CreateWellStep3.tsx b/projects/dex-ui/src/components/Create/CreateWellStep3.tsx
index c39b09969b..dc3cb06eda 100644
--- a/projects/dex-ui/src/components/Create/CreateWellStep3.tsx
+++ b/projects/dex-ui/src/components/Create/CreateWellStep3.tsx
@@ -1,32 +1,48 @@
import React from "react";
+
+import { FormProvider, useForm } from "react-hook-form";
+import styled from "styled-components";
+
import { Divider, Flex } from "src/components/Layout";
import { Text } from "src/components/Typography";
+import useSdk from "src/utils/sdk/useSdk";
import { theme } from "src/utils/ui/theme";
-import styled from "styled-components";
+import { useWells } from "src/wells/useWells";
+
import { CreateWellStepProps, useCreateWell } from "./CreateWellProvider";
-import { FormProvider, useForm } from "react-hook-form";
+import { CreateWellButtonRow } from "./shared/CreateWellButtonRow";
import { CreateWellFormProgress } from "./shared/CreateWellFormProgress";
import { StyledForm, TextInputField } from "../Form";
-import { useWells } from "src/wells/useWells";
-import { CreateWellButtonRow } from "./shared/CreateWellButtonRow";
export type WellDetailsFormValues = CreateWellStepProps["step3"];
// If the user goes back to step 2 changes the well function & returns to this step,
// the default values will not be updated.
-// TODO: priofity sm.
const useWellDetailsDefaultValues = () => {
- const { wellTokens, wellFunction } = useCreateWell();
+ const { wellImplementation, wellTokens, wellFunction } = useCreateWell();
+ const sdk = useSdk();
+
+ const wellDotSolL2 = sdk.wells.addresses.WELL_DOT_SOL.ARBITRUM_MAINNET;
const wellName = wellFunction?.name;
const wellSymbol = wellFunction?.symbol;
const token1 = wellTokens?.token1?.symbol;
const token2 = wellTokens?.token2?.symbol;
- const defaultName =
- wellName && token1 && token2 ? `${token1}:${token2} ${wellName} Well` : undefined;
+ const upgradeable = wellImplementation?.toLowerCase() === wellDotSolL2.toLowerCase();
+ const upgradeableNameFragment = upgradeable ? " Upgradeable " : "";
+ const upgradeableSymbolFragment = upgradeable ? "U-" : "";
- const defaultSymbol = wellSymbol && token1 && token2 && `${token1}${token2}${wellSymbol}w`;
+ const defaultName =
+ wellName && token1 && token2
+ ? `${token1}:${token2} ${wellName}${upgradeableNameFragment}Well`
+ : undefined;
+
+ const defaultSymbol =
+ wellSymbol &&
+ token1 &&
+ token2 &&
+ `${upgradeableSymbolFragment}${token1}${token2}${wellSymbol}w`;
return {
name: defaultName,
diff --git a/projects/dex-ui/src/components/Create/CreateWellStep4.tsx b/projects/dex-ui/src/components/Create/CreateWellStep4.tsx
index 90bc2568f7..ce5731108e 100644
--- a/projects/dex-ui/src/components/Create/CreateWellStep4.tsx
+++ b/projects/dex-ui/src/components/Create/CreateWellStep4.tsx
@@ -1,5 +1,5 @@
import React, { useEffect, useState } from "react";
-import styled from "styled-components";
+
import {
Control,
Controller,
@@ -8,30 +8,31 @@ import {
useFormContext,
useWatch
} from "react-hook-form";
-import { theme } from "src/utils/ui/theme";
+import { useNavigate } from "react-router-dom";
+import styled from "styled-components";
+import { useAccount } from "wagmi";
+
+import { ERC20Token, TokenValue } from "@beanstalk/sdk";
import { StyledForm, SwitchField, TextInputField } from "src/components/Form";
import { Box, Divider, Flex, FlexCard } from "src/components/Layout";
import { SelectCard } from "src/components/Selectable";
+import { TokenInput } from "src/components/Swap/TokenInput";
import { Text } from "src/components/Typography";
+import { useTokenAllowance } from "src/tokens/useTokenAllowance";
+import { queryKeys } from "src/utils/query/queryKeys";
+import { useInvalidateQueries } from "src/utils/query/useInvalidateQueries";
+import useSdk from "src/utils/sdk/useSdk";
+import { theme } from "src/utils/ui/theme";
+import { useBoolean } from "src/utils/ui/useBoolean";
import { CreateWellContext, CreateWellStepProps, useCreateWell } from "./CreateWellProvider";
-import { WellComponentInfo, useWhitelistedWellComponents } from "./useWhitelistedWellComponents";
-
-import { ERC20Token, TokenValue } from "@beanstalk/sdk";
-import { TokenInput } from "src/components/Swap/TokenInput";
import { CreateWellButtonRow } from "./shared/CreateWellButtonRow";
-import { useTokenAllowance } from "src/tokens/useTokenAllowance";
-import useSdk from "src/utils/sdk/useSdk";
+import { WellComponentInfo, useWhitelistedWellComponents } from "./useWhitelistedWellComponents";
import { ButtonPrimary } from "../Button";
import { ensureAllowance } from "../Liquidity/allowance";
-import { useAccount } from "wagmi";
-import { useQueryClient } from "@tanstack/react-query";
-import { queryKeys } from "src/utils/query/queryKeys";
-import { useBoolean } from "src/utils/ui/useBoolean";
-import { ProgressCircle } from "../ProgressCircle";
-import { useNavigate } from "react-router-dom";
import { Modal } from "../Modal";
+import { ProgressCircle } from "../ProgressCircle";
type FormValues = CreateWellStepProps["step4"] & {
usingSalt: boolean;
@@ -73,11 +74,15 @@ const FormContent = ({
}
});
- const [seeding, _amt1, _amt2] = methods.watch(['seedingLiquidity', 'token1Amount', 'token2Amount']);
+ const [seeding, _amt1, _amt2] = methods.watch([
+ "seedingLiquidity",
+ "token1Amount",
+ "token2Amount"
+ ]);
const amt1 = Number(_amt1 || 0);
const amt2 = Number(_amt2 || 0);
- const bothAmountsNeeded = seeding ? (amt1 > 0 && amt2 <= 0) || (amt1 <= 0 && amt2 > 0) : false;
+ const bothAmountsNeeded = seeding ? (amt1 > 0 && amt2 <= 0) || (amt1 <= 0 && amt2 > 0) : false;
const handleSave = (formValues?: FormValues) => {
const values = formValues || methods.getValues();
@@ -280,7 +285,8 @@ const AllowanceButtons = ({
}) => {
const { address } = useAccount();
const sdk = useSdk();
- const queryClient = useQueryClient();
+
+ const invalidateQueries = useInvalidateQueries();
const { data: token1Allowance } = useTokenAllowance(token1, sdk.contracts.beanstalk.address);
const { data: token2Allowance } = useTokenAllowance(token2, sdk.contracts.beanstalk.address);
@@ -294,9 +300,7 @@ const AllowanceButtons = ({
const approveToken = async (token: ERC20Token, amount: TokenValue) => {
if (!address) return;
await ensureAllowance(address, sdk.contracts.beanstalk.address, token, amount);
- queryClient.invalidateQueries({
- queryKey: queryKeys.tokenAllowance(token.address, sdk.contracts.beanstalk.address)
- });
+ invalidateQueries(queryKeys.tokenAllowance(token.address, sdk.contracts.beanstalk.address));
};
useEffect(() => {
diff --git a/projects/dex-ui/src/components/Create/shared/ComponentAccordionCard.tsx b/projects/dex-ui/src/components/Create/shared/ComponentAccordionCard.tsx
index d8f4432b52..9f948bad6d 100644
--- a/projects/dex-ui/src/components/Create/shared/ComponentAccordionCard.tsx
+++ b/projects/dex-ui/src/components/Create/shared/ComponentAccordionCard.tsx
@@ -1,12 +1,15 @@
import React from "react";
-import styled from "styled-components";
+
import { Link } from "react-router-dom";
-import { theme } from "src/utils/ui/theme";
+import styled from "styled-components";
+
+import { ChainExplorerIcon, Github } from "src/components/Icons";
import { Box, Flex } from "src/components/Layout";
+import { AccordionSelectCard } from "src/components/Selectable";
import { Text } from "src/components/Typography";
+import { theme } from "src/utils/ui/theme";
+
import { WellComponentInfo } from "../useWhitelistedWellComponents";
-import { AccordionSelectCard } from "../../Selectable";
-import { Etherscan, Github } from "../../Icons";
export type WellComponentAccordionCardProps = {
selected: boolean;
@@ -94,9 +97,9 @@ export const WellComponentAccordionCard = ({
- {links.etherscan && (
-
-
+ {links.explorer && (
+
+
)}
{links.github && (
diff --git a/projects/dex-ui/src/components/Create/shared/ComponentInputWithCustom.tsx b/projects/dex-ui/src/components/Create/shared/ComponentInputWithCustom.tsx
index 2f132349e4..9cb90a9498 100644
--- a/projects/dex-ui/src/components/Create/shared/ComponentInputWithCustom.tsx
+++ b/projects/dex-ui/src/components/Create/shared/ComponentInputWithCustom.tsx
@@ -1,16 +1,19 @@
import React, { useCallback } from "react";
+
import { FieldValues, Path, PathValue, useFormContext, useWatch } from "react-hook-form";
-import { useWhitelistedWellComponents } from "../useWhitelistedWellComponents";
-import { useBoolean } from "src/utils/ui/useBoolean";
-import { TextInputField } from "../../Form";
+import styled from "styled-components";
+
import { Flex } from "src/components/Layout";
import { ToggleSwitch } from "src/components/ToggleSwitch";
-import { WellComponentAccordionCard } from "./ComponentAccordionCard";
import { Text } from "src/components/Typography";
+import { getIsValidEthereumAddress } from "src/utils/addresses";
import { theme } from "src/utils/ui/theme";
-import styled from "styled-components";
+import { useBoolean } from "src/utils/ui/useBoolean";
+
+import { WellComponentAccordionCard } from "./ComponentAccordionCard";
+import { TextInputField } from "../../Form";
import { CircleFilledCheckIcon, CircleEmptyIcon } from "../../Icons";
-import { getIsValidEthereumAddress } from "src/utils/addresses";
+import { useWhitelistedWellComponents } from "../useWhitelistedWellComponents";
type AdditionalOptionProps = {
value: string;
diff --git a/projects/dex-ui/src/components/Create/shared/CreateWellButtonRow.tsx b/projects/dex-ui/src/components/Create/shared/CreateWellButtonRow.tsx
index e6c769bfcd..f3d56468cd 100644
--- a/projects/dex-ui/src/components/Create/shared/CreateWellButtonRow.tsx
+++ b/projects/dex-ui/src/components/Create/shared/CreateWellButtonRow.tsx
@@ -1,13 +1,16 @@
import React, { useMemo } from "react";
+
import { useFormContext, useWatch } from "react-hook-form";
import { useNavigate } from "react-router-dom";
-import { theme } from "src/utils/ui/theme";
import styled from "styled-components";
+
+import { ActionWalletButtonWrapper } from "src/components/Wallet";
+import { theme } from "src/utils/ui/theme";
+
import { ButtonPrimary } from "../../Button";
import { LeftArrow, RightArrow } from "../../Icons";
import { Flex } from "../../Layout";
import { useCreateWell } from "../CreateWellProvider";
-import { ActionWalletButtonWrapper } from "src/components/Wallet";
const ButtonLabels = [
{
@@ -72,7 +75,7 @@ export const CreateWellButtonRow = ({
const goNextEnabled = noErrors && hasRequiredValues;
const goBackLabel = ButtonLabels[step].back || "Back";
- const nextLabel = disabled && disabledMessage || ButtonLabels[step].next || "Next";
+ const nextLabel = (disabled && disabledMessage) || ButtonLabels[step].next || "Next";
return (
diff --git a/projects/dex-ui/src/components/Create/shared/CreateWellFormProgress.tsx b/projects/dex-ui/src/components/Create/shared/CreateWellFormProgress.tsx
index 27ceddd0b2..42b22c42f7 100644
--- a/projects/dex-ui/src/components/Create/shared/CreateWellFormProgress.tsx
+++ b/projects/dex-ui/src/components/Create/shared/CreateWellFormProgress.tsx
@@ -1,11 +1,14 @@
import React, { useMemo } from "react";
+
import { useFormContext, useWatch } from "react-hook-form";
-import { theme } from "src/utils/ui/theme";
-import { CheckIcon, CircleEmptyIcon } from "src/components/Icons";
-import { Flex } from "src/components/Layout";
import { Link } from "react-router-dom";
import styled from "styled-components";
+
+import { CheckIcon, CircleEmptyIcon } from "src/components/Icons";
+import { Flex } from "src/components/Layout";
import { Text } from "src/components/Typography";
+import { theme } from "src/utils/ui/theme";
+
import { FunctionTokenPumpFormValues } from "../CreateWellStep2";
import { WellDetailsFormValues } from "../CreateWellStep3";
diff --git a/projects/dex-ui/src/components/Create/useWhitelistedWellComponents.ts b/projects/dex-ui/src/components/Create/useWhitelistedWellComponents.ts
index b2c1eb6df8..89b832f3b0 100644
--- a/projects/dex-ui/src/components/Create/useWhitelistedWellComponents.ts
+++ b/projects/dex-ui/src/components/Create/useWhitelistedWellComponents.ts
@@ -1,21 +1,20 @@
import { useMemo } from "react";
+
+import { ChainId, ChainResolver } from "@beanstalk/sdk-core";
+
import BeanstalkFarmsLogo from "src/assets/images/beanstalk-farms.png";
-import HalbornLogo from "src/assets/images/halborn-logo.png";
-import {
- WELL_DOT_SOL_ADDRESS,
- toAddressMap,
- MULTI_FLOW_PUMP_V_1PT1_ADDRESS,
- CONSTANT_PRODUCT_2_V2_ADDRESS
-} from "src/utils/addresses";
import BrendanTwitterPFP from "src/assets/images/brendan-twitter-pfp.png";
-import CyrfinLogo from "src/assets/images/cyrfin-logo.svg";
-import Code4renaLogo from "src/assets/images/code4rena-logo.png";
import ClockIcon from "src/assets/images/clock-icon.svg";
-import { useWells } from "src/wells/useWells";
+import Code4renaLogo from "src/assets/images/code4rena-logo.png";
+import CyrfinLogo from "src/assets/images/cyrfin-logo.svg";
+import HalbornLogo from "src/assets/images/halborn-logo.png";
+import { AddressMap } from "src/types";
+import { toAddressMap } from "src/utils/addresses";
+import useSdk from "src/utils/sdk/useSdk";
+import { usePumps } from "src/wells/pump/usePumps";
import { useWellImplementations } from "src/wells/useWellImplementations";
+import { useWells } from "src/wells/useWells";
import { useWellFunctions } from "src/wells/wellFunction/useWellFunctions";
-import { usePumps } from "src/wells/pump/usePumps";
-import { AddressMap } from "src/types";
export enum WellComponentType {
WellImplementation = "WellImplementation",
@@ -51,7 +50,9 @@ export type WellComponentInfo = {
};
info: ComponentInfo[];
links: {
- etherscan?: string;
+ explorer?: string;
+ // arbiscan?: string;
+ // etherscan?: string;
github?: string;
learnMore?: string;
};
@@ -82,7 +83,7 @@ const basinAuditInfo = [
];
const WellDotSol: WellComponentInfo = {
- address: WELL_DOT_SOL_ADDRESS,
+ address: "",
component: {
name: "Well.sol",
summary: "A standard Well implementation that prioritizes flexibility and composability.",
@@ -103,14 +104,13 @@ const WellDotSol: WellComponentInfo = {
{ label: "Audited by", value: basinAuditInfo }
],
links: {
- etherscan: `https://etherscan.io/address/${WELL_DOT_SOL_ADDRESS}`,
github: "https://github.com/BeanstalkFarms/Basin/blob/master/src/Well.sol",
learnMore: "https://github.com/BeanstalkFarms/Basin/blob/master/src/Well.sol"
}
};
const MultiFlowPump: WellComponentInfo = {
- address: MULTI_FLOW_PUMP_V_1PT1_ADDRESS,
+ address: "",
component: {
name: "Multi Flow",
fullName: "Multi Flow Pump V1.1",
@@ -136,14 +136,13 @@ const MultiFlowPump: WellComponentInfo = {
{ label: "Audited by", value: basinAuditInfo }
],
links: {
- etherscan: `https://etherscan.io/address/${MULTI_FLOW_PUMP_V_1PT1_ADDRESS}`,
github: "https://github.com/BeanstalkFarms/Basin/blob/master/src/pumps/MultiFlowPump.sol",
learnMore: "https://github.com/BeanstalkFarms/Basin/blob/master/src/pumps/MultiFlowPump.sol"
}
};
const ConstantProduct2: WellComponentInfo = {
- address: CONSTANT_PRODUCT_2_V2_ADDRESS,
+ address: "",
component: {
name: "Constant Product 2",
summary: "A standard x*y = k token pricing function for two tokens.",
@@ -162,7 +161,6 @@ const ConstantProduct2: WellComponentInfo = {
{ label: "Audited by", value: basinAuditInfo }
],
links: {
- etherscan: `https://etherscan.io/address/${CONSTANT_PRODUCT_2_V2_ADDRESS}`,
github:
"https://github.com/BeanstalkFarms/Basin/blob/master/src/functions/ConstantProduct2.sol",
learnMore:
@@ -176,16 +174,21 @@ type WellComponentMap = {
wellFunctions: T;
};
-const ComponentWhiteList: WellComponentMap> = {
- wellImplementations: {
- [WellDotSol.address]: WellDotSol
- },
- pumps: {
- [MultiFlowPump.address]: MultiFlowPump
- },
- wellFunctions: {
- [ConstantProduct2.address]: ConstantProduct2
- }
+const getComponentWithUpdateLinks = (
+ wellComponent: WellComponentInfo,
+ chainId: ChainId,
+ address: string
+) => {
+ const explorer = `https://${ChainResolver.isL2Chain(chainId) ? "arbiscan" : "etherscan"}.io/address/${address}`;
+
+ return {
+ ...wellComponent,
+ address,
+ links: {
+ ...wellComponent.links,
+ explorer
+ }
+ };
};
export const useWhitelistedWellComponents = () => {
@@ -193,10 +196,42 @@ export const useWhitelistedWellComponents = () => {
const { data: implementations } = useWellImplementations();
const wellFunctions = useWellFunctions();
const pumps = usePumps();
+ const sdk = useSdk();
+
+ const whitelist = useMemo(() => {
+ // set Addresses
+ const wellDotSol = getComponentWithUpdateLinks(
+ WellDotSol,
+ sdk.chainId,
+ sdk.wells.addresses.WELL_DOT_SOL.get(sdk.chainId)
+ );
+ const multiFlow = getComponentWithUpdateLinks(
+ MultiFlowPump,
+ sdk.chainId,
+ sdk.wells.addresses.MULTI_FLOW_PUMP_V1_1.get(sdk.chainId)
+ );
+ const cp2 = getComponentWithUpdateLinks(
+ ConstantProduct2,
+ sdk.chainId,
+ sdk.wells.addresses.CONSTANT_PRODUCT_2_V2.get(sdk.chainId)
+ );
+
+ return {
+ wellImplementations: {
+ [wellDotSol.address]: wellDotSol
+ },
+ pumps: {
+ [multiFlow.address]: multiFlow
+ },
+ wellFunctions: {
+ [cp2.address]: cp2
+ }
+ };
+ }, [sdk]);
return useMemo(() => {
// make deep copy of ComponentWhiteList
- const map = JSON.parse(JSON.stringify(ComponentWhiteList)) as WellComponentMap<
+ const map = JSON.parse(JSON.stringify(whitelist)) as WellComponentMap<
AddressMap
>;
@@ -237,5 +272,5 @@ export const useWhitelistedWellComponents = () => {
components,
lookup: map
};
- }, [implementations, pumps, wellFunctions, wells]);
+ }, [whitelist, implementations, pumps, wellFunctions, wells]);
};
diff --git a/projects/dex-ui/src/components/Dropdown.tsx b/projects/dex-ui/src/components/Dropdown.tsx
index c2208c3409..0ac1dadb08 100644
--- a/projects/dex-ui/src/components/Dropdown.tsx
+++ b/projects/dex-ui/src/components/Dropdown.tsx
@@ -1,10 +1,13 @@
import React from "react";
+
import * as DropdownMenu from "@radix-ui/react-dropdown-menu";
import styled from "styled-components";
+
import { theme } from "src/utils/ui/theme";
-import { Flex } from "./Layout";
import useElementDimensions from "src/utils/ui/useDimensions";
+import { Flex } from "./Layout";
+
export type DropdownProps = {
open: boolean;
trigger: React.ReactNode;
@@ -21,8 +24,8 @@ const Dropdown = ({ open, children, trigger, offset, setOpen }: DropdownProps) =
e.preventDefault()}
- onClick={(e) => e.preventDefault()}
+ onMouseDown={(e: any) => e.preventDefault()}
+ onClick={(e: any) => e.preventDefault()}
>
{trigger}
@@ -31,7 +34,7 @@ const Dropdown = ({ open, children, trigger, offset, setOpen }: DropdownProps) =
e.preventDefault()}
+ onFocus={(e: any) => e.preventDefault()}
>
<>{children}>
diff --git a/projects/dex-ui/src/components/Error.tsx b/projects/dex-ui/src/components/Error.tsx
index cc1305d2a7..9be1483db3 100644
--- a/projects/dex-ui/src/components/Error.tsx
+++ b/projects/dex-ui/src/components/Error.tsx
@@ -1,28 +1,24 @@
import React from "react";
+
+import styled from "styled-components";
+
import { Footer } from "src/components/Frame/Footer";
import { Frame } from "src/components/Frame/Frame";
-import styled from "styled-components";
type ErrorProps = {
message: string;
errorOnly?: boolean;
-}
+};
export const Error = ({ message, errorOnly }: ErrorProps) => {
return (
<>
{!errorOnly && }
-
-
- Oops!
-
-
- {"Something went wrong :("}
-
-
- {message}
-
-
+
+ Oops!
+ {"Something went wrong :("}
+ {message}
+
{!errorOnly && }
>
);
@@ -36,19 +32,19 @@ const ErrorContainer = styled.div`
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
-`
+`;
const LargeText = styled.div`
font-size: 100px;
line-height: 90px;
-`
+`;
const SmallText = styled.div`
font-size: 24px;
margin-left: 2px;
-`
+`;
const ErrorBox = styled.div`
width: 95vw;
text-align: center;
-`
\ No newline at end of file
+`;
diff --git a/projects/dex-ui/src/components/ExpandBox.tsx b/projects/dex-ui/src/components/ExpandBox.tsx
index 587c5ede2e..4d5bcd3b7b 100644
--- a/projects/dex-ui/src/components/ExpandBox.tsx
+++ b/projects/dex-ui/src/components/ExpandBox.tsx
@@ -1,11 +1,14 @@
import React, { Children, useCallback, useState, MouseEvent as ReactMouseEvent } from "react";
-import { FC } from "src/types";
+
import styled from "styled-components";
-import { BodyCaps, BodyS, BodyXS } from "./Typography";
-import { ImageButton } from "./ImageButton";
-import { ChevronDown } from "./Icons";
-import { BottomDrawer } from "./BottomDrawer";
+
import { size } from "src/breakpoints";
+import { FC } from "src/types";
+
+import { BottomDrawer } from "./BottomDrawer";
+import { ChevronDown } from "./Icons";
+import { ImageButton } from "./ImageButton";
+import { BodyCaps, BodyS, BodyXS } from "./Typography";
interface Composition {
Header: typeof Header;
@@ -36,7 +39,11 @@ export const ExpandBox: FC & Composition = ({ children, drawerHeaderText
return (
-
+
{body}