Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Wormhole logic #439

Draft
wants to merge 24 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
8d9a18f
chore(ui): Add tmp dir to .gitignore
wormat Oct 13, 2022
9bd7ba9
chore(ui): Add ts-node and csv-parse dev dependencies
wormat Oct 13, 2022
1cfb445
feat(ui): Add Wormhole token data scraper
wormat Oct 13, 2022
e04cce9
feat(ui): Add scraped Wormhole token data
wormat Oct 13, 2022
e771efc
refactor(core): Adjust InitiateWormholeTransferParams to take sourceA…
wormat Oct 13, 2022
49c02b9
refactor(evm): Update for new InitiateWormholeTransferParams
wormat Oct 13, 2022
8b9eebb
refactor(solana): Update for new InitiateWormholeTransferParams
wormat Oct 13, 2022
470ab43
WIP: revert
wormat Oct 13, 2022
023c809
refactor(ui): Update for new InitiateWormholeTransferParams
wormat Oct 13, 2022
55ba5d0
feat(ui): Add Wormhole transfer models
wormat Oct 13, 2022
72d94f4
feat(ui): Add Wormhole transfer hooks
wormat Oct 13, 2022
be1352c
feat(ui): Add basic Wormhole form
wormat Oct 13, 2022
d7a3e4a
feat(ui): Add Wormhole page
wormat Oct 13, 2022
b27d22e
chore(ui): Add npm script for Wormhole token scraper
wormat Oct 14, 2022
b7e126d
feat(ui): Restrict Wormhole tokens to min 2 Solana/EVM chains
wormat Oct 14, 2022
60d4c4c
chore(ui): Update Wormhole token list
wormat Oct 14, 2022
da09132
chore(ui): Update TS/ESLint configs for scripts
wormat Oct 14, 2022
c892fb5
style(ui): Fix lint issues
wormat Oct 14, 2022
ab61bd2
fix(ui): Catch errors properly in scraper script
wormat Oct 14, 2022
fd2751c
refactor(ui): Update wormhole hooks for SDK client changes
wormat Oct 20, 2022
9e00f27
feat(ui): Add balance queries to basic Wormhole form
wormat Oct 20, 2022
e9ea326
refactor(ui): Update Wormhole form/hooks for SDK client changes
wormat Oct 20, 2022
a8e1641
fix(ui): Fix basic Wormhole form bugs
wormat Oct 21, 2022
5e78fce
chore(ui): Add Wormhole tokens list to .prettierignore
wormat Oct 21, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion apps/ui/.eslintrc.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ module.exports = {
extends: ["@swim-io/eslint-config"],
},
{
files: ["**/*.{cts,mts,ts,tsx}"],
files: ["src/**/*.{cts,mts,ts,tsx}"],
extends: ["@swim-io/eslint-config/react"],
parserOptions: {
// Make sure correct `tsconfig.json` is found in monorepo
Expand Down Expand Up @@ -85,5 +85,13 @@ module.exports = {
},
],
},
{
files: ["scripts/*.{cts,mts,ts,tsx}"],
extends: ["@swim-io/eslint-config"],
parserOptions: {
// Make sure correct `tsconfig.json` is found in monorepo
tsconfigRootDir: `${__dirname}/scripts`,
},
},
],
};
1 change: 1 addition & 0 deletions apps/ui/.gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
build/
tmp/
1 change: 1 addition & 0 deletions apps/ui/.prettierignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# ignore auto-generated files
build/
storybook-static/
src/config/wormholeTokens.json
src/keys/**/*.json
23 changes: 13 additions & 10 deletions apps/ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"private": true,
"version": "0.1.0",
"scripts": {
"scrape-wormhole-tokens": "./scripts/scrapeWormholeTokenData.sh",
"start": "NODE_ENV=development SKIP_PREFLIGHT_CHECK=true DISABLE_ESLINT_PLUGIN=true craco start",
"build": "SKIP_PREFLIGHT_CHECK=true DISABLE_ESLINT_PLUGIN=true craco build",
"release": "SENTRY_RELEASE=$(git rev-parse --short HEAD) yarn workspaces foreach --topological-dev --parallel --recursive --from @swim-io/ui run build",
Expand Down Expand Up @@ -50,16 +51,16 @@
"@sentry/types": "^7.9.0",
"@solana/spl-token": "^0.3.5",
"@solana/web3.js": "^1.62.0",
"@swim-io/aptos": "^0.40.0",
"@swim-io/core": "^0.40.0",
"@swim-io/evm": "^0.40.0",
"@swim-io/evm-contracts": "^0.40.0",
"@swim-io/pool-math": "^0.40.0",
"@swim-io/solana": "^0.40.0",
"@swim-io/solana-contracts": "^0.40.0",
"@swim-io/token-projects": "^0.40.0",
"@swim-io/utils": "^0.40.0",
"@swim-io/wormhole": "^0.40.0",
"@swim-io/aptos": "workspace:^",
"@swim-io/core": "workspace:^",
"@swim-io/evm": "workspace:^",
"@swim-io/evm-contracts": "workspace:^",
"@swim-io/pool-math": "workspace:^",
"@swim-io/solana": "workspace:^",
"@swim-io/solana-contracts": "workspace:^",
"@swim-io/token-projects": "workspace:^",
"@swim-io/utils": "workspace:^",
"@swim-io/wormhole": "workspace:^",
"bn.js": "^5.2.1",
"classnames": "^2.3.1",
"decimal.js": "^10.3.1",
Expand Down Expand Up @@ -113,6 +114,7 @@
"@types/react-dom": "^17.0.0",
"@typescript-eslint/eslint-plugin": "^5.38.1",
"@typescript-eslint/parser": "^5.38.1",
"csv-parse": "^5.3.1",
"eslint": "^8.18.0",
"eslint-config-prettier": "^8.5.0",
"eslint-config-react-app": "^7.0.1",
Expand All @@ -129,6 +131,7 @@
"jsonc-eslint-parser": "^2.1.0",
"prettier": "^2.7.1",
"storybook-preset-craco": "^0.0.6",
"ts-node": "^10.9.1",
"typescript": "~4.8.4",
"webpack": "4.44.2"
}
Expand Down
206 changes: 206 additions & 0 deletions apps/ui/scripts/processWormholeTokenData.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,206 @@
import fs from "fs";

import type { ChainId } from "@certusone/wormhole-sdk";
import { CHAINS, isEVMChain } from "@certusone/wormhole-sdk";
import { parse } from "csv-parse";

type Source =
| "sol"
| "eth"
| "bsc"
| "terra"
| "matic"
| "avax"
| "oasis"
| "algorand"
| "ftm"
| "aurora"
| "karura"
| "acala"
| "klaytn"
| "celo"
| "near"
| "moonbeam"
| "terra2";

interface WrappedDetails {
readonly solAddress: string;
readonly solDecimals: string;
readonly ethAddress: string;
readonly ethDecimals: string;
readonly bscAddress: string;
readonly bscDecimals: string;
readonly terraAddress: string;
readonly terraDecimals: string;
readonly maticAddress: string;
readonly maticDecimals: string;
readonly avaxAddress: string;
readonly avaxDecimals: string;
readonly oasisAddress: string;
readonly oasisDecimals: string;
readonly algorandAddress: string;
readonly algorandDecimals: string;
readonly ftmAddress: string;
readonly ftmDecimals: string;
readonly auroraAddress: string;
readonly auroraDecimals: string;
readonly karuraAddress: string;
readonly karuraDecimals: string;
readonly acalaAddress: string;
readonly acalaDecimals: string;
readonly klaytnAddress: string;
readonly klaytnDecimals: string;
readonly celoAddress: string;
readonly celoDecimals: string;
readonly nearAddress: string;
readonly nearDecimals: string;
readonly moonbeamAddress: string;
readonly moonbeamDecimals: string;
readonly terra2Address: string;
readonly terra2Decimals: string;
}

interface CsvRecord extends WrappedDetails {
readonly source: Source;
readonly symbol: string;
readonly name: string;
readonly sourceAddress: string;
readonly sourceDecimals: string;
readonly coingeckoId: string;
readonly logo: string;
}

interface WormholeTokenDetails {
readonly chainId: ChainId;
readonly address: string;
readonly decimals: number;
}

interface WormholeToken {
readonly symbol: string;
readonly displayName: string;
readonly logo: string;
readonly coinGeckoId: string;
readonly nativeDetails: WormholeTokenDetails;
readonly wrappedDetails: readonly WormholeTokenDetails[];
}

const sourceToChainId: Record<Source, ChainId> = {
sol: CHAINS.solana,
eth: CHAINS.ethereum,
bsc: CHAINS.bsc,
terra: CHAINS.terra,
matic: CHAINS.polygon,
avax: CHAINS.avalanche,
oasis: CHAINS.oasis,
algorand: CHAINS.algorand,
ftm: CHAINS.fantom,
aurora: CHAINS.aurora,
karura: CHAINS.karura,
acala: CHAINS.acala,
klaytn: CHAINS.klaytn,
celo: CHAINS.celo,
near: CHAINS.near,
moonbeam: CHAINS.moonbeam,
terra2: CHAINS.terra2,
};

const isChainSupported = (chainId: ChainId): boolean =>
chainId === CHAINS.solana || isEVMChain(chainId);

const supportedSourceToChainId = Object.entries(sourceToChainId).reduce<
Partial<Record<Source, ChainId>>
>(
(accumulator, [source, chainId]) =>
isChainSupported(chainId)
? {
...accumulator,
[source]: chainId,
}
: accumulator,
{},
);

const processWrappedDetails = (
wrappedDetails: WrappedDetails,
): readonly WormholeTokenDetails[] =>
Object.entries(supportedSourceToChainId).reduce(
(accumulator: readonly WormholeTokenDetails[], [source, chainId]) => {
const address: string =
wrappedDetails[`${source}Address` as keyof WrappedDetails];
const decimals: string =
wrappedDetails[`${source}Decimals` as keyof WrappedDetails];
if (!address || !decimals) {
return accumulator;
}
return [
...accumulator,
{
chainId,
address,
decimals: parseInt(decimals, 10),
},
];
},
[],
);

const processRecord = ({
source,
symbol,
name,
logo,
coingeckoId,
sourceAddress,
sourceDecimals,
...wrappedDetails
}: CsvRecord): WormholeToken => ({
symbol,
displayName: name,
logo,
coinGeckoId: coingeckoId,
nativeDetails: {
chainId: sourceToChainId[source],
address: sourceAddress,
decimals: parseInt(sourceDecimals, 10),
},
wrappedDetails: processWrappedDetails(wrappedDetails),
});

const main = async () => {
const parser = fs
.createReadStream(`${__dirname}/../tmp/wormholeTokenData.csv`)
.pipe(
parse({
bom: true,
columns: true,
}),
);

// eslint-disable-next-line functional/prefer-readonly-type
const processedRecords: WormholeToken[] = [];
for await (const record of parser) {
const processedRecord = processRecord(record as CsvRecord);
const supportedChains = [
processedRecord.nativeDetails,
...processedRecord.wrappedDetails,
].filter((details) => isChainSupported(details.chainId));
if (supportedChains.length >= 2) {
// eslint-disable-next-line functional/immutable-data
processedRecords.push(processedRecord);
}
}

return new Promise<void>((resolve, reject) => {
fs.writeFile(
`${__dirname}/../src/config/wormholeTokens.json`,
JSON.stringify(processedRecords),
(err) => (err ? reject(err) : resolve()),
);
});
};

main().catch((error) => {
console.error(error);
process.exit(1);
});
12 changes: 12 additions & 0 deletions apps/ui/scripts/scrapeWormholeTokenData.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#!/bin/bash
set -o errexit -o nounset -o pipefail
command -v shellcheck >/dev/null && shellcheck "$0"

TMP_FILE="./tmp/wormholeTokenData.csv"

mkdir -p tmp
wget -O "$TMP_FILE" "https://raw.githubusercontent.com/certusone/wormhole-token-list/main/content/by_source.csv"

yarn ts-node --esm ./scripts/processWormholeTokenData.ts

rm "$TMP_FILE"
16 changes: 16 additions & 0 deletions apps/ui/scripts/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"$schema": "https://json.schemastore.org/tsconfig",
"extends": "@swim-io/tsconfig/tsconfig-base.json",
"compilerOptions": {
"allowJs": true,
"allowSyntheticDefaultImports": true,
"baseUrl": "./",
"noEmit": true
},
"include": ["./"],
"ts-node": {
"compilerOptions": {
"module": "commonjs"
}
}
}
2 changes: 2 additions & 0 deletions apps/ui/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import StakePage from "./pages/StakePage";
import SwapPage from "./pages/SwapPage";
import SwapPageV2 from "./pages/SwapPageV2";
import TosPage from "./pages/TosPage";
import WormholePage from "./pages/WormholePage";

function App(): ReactElement {
return (
Expand Down Expand Up @@ -64,6 +65,7 @@ function App(): ReactElement {
{process.env.REACT_APP_ENABLE_POOL_RESTRUCTURE && (
<Route path="swapV2" element={<SwapPageV2 />} />
)}
<Route path="wormhole" element={<WormholePage />} />
<Route path="collectibles" element={<CollectiblesPage />} />
<Route path="tos" element={<TosPage />} />
<Route path="media" element={<MediaPage />} />
Expand Down
Loading