mirror of https://github.com/certusone/oyster.git
chore: format
This commit is contained in:
parent
b4a46cfe85
commit
3c2faf5e49
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"name": "@solana/bridge-ethereum",
|
||||
"name": "@solana/bridge-sdk",
|
||||
"version": "0.0.1",
|
||||
"dependencies": {
|
||||
"@oyster/common": "0.0.1",
|
|
@ -296,9 +296,7 @@
|
|||
"ast": {
|
||||
"absolutePath": "contracts/token/ERC20/ERC20.sol",
|
||||
"exportedSymbols": {
|
||||
"ERC20": [
|
||||
9194
|
||||
]
|
||||
"ERC20": [9194]
|
||||
},
|
||||
"id": 9195,
|
||||
"license": "MIT",
|
||||
|
@ -306,12 +304,7 @@
|
|||
"nodes": [
|
||||
{
|
||||
"id": 8689,
|
||||
"literals": [
|
||||
"solidity",
|
||||
"^",
|
||||
"0.6",
|
||||
".0"
|
||||
],
|
||||
"literals": ["solidity", "^", "0.6", ".0"],
|
||||
"nodeType": "PragmaDirective",
|
||||
"src": "33:23:84"
|
||||
},
|
||||
|
@ -399,10 +392,7 @@
|
|||
"src": "1372:6:84"
|
||||
}
|
||||
],
|
||||
"contractDependencies": [
|
||||
22,
|
||||
9773
|
||||
],
|
||||
"contractDependencies": [22, 9773],
|
||||
"contractKind": "contract",
|
||||
"documentation": {
|
||||
"id": 8694,
|
||||
|
@ -412,11 +402,7 @@
|
|||
},
|
||||
"fullyImplemented": true,
|
||||
"id": 9194,
|
||||
"linearizedBaseContracts": [
|
||||
9194,
|
||||
9773,
|
||||
22
|
||||
],
|
||||
"linearizedBaseContracts": [9194, 9773, 22],
|
||||
"name": "ERC20",
|
||||
"nodeType": "ContractDefinition",
|
||||
"nodes": [
|
||||
|
@ -1204,9 +1190,7 @@
|
|||
"visibility": "public"
|
||||
},
|
||||
{
|
||||
"baseFunctions": [
|
||||
9704
|
||||
],
|
||||
"baseFunctions": [9704],
|
||||
"body": {
|
||||
"id": 8779,
|
||||
"nodeType": "Block",
|
||||
|
@ -1300,9 +1284,7 @@
|
|||
"visibility": "public"
|
||||
},
|
||||
{
|
||||
"baseFunctions": [
|
||||
9712
|
||||
],
|
||||
"baseFunctions": [9712],
|
||||
"body": {
|
||||
"id": 8793,
|
||||
"nodeType": "Block",
|
||||
|
@ -1453,9 +1435,7 @@
|
|||
"visibility": "public"
|
||||
},
|
||||
{
|
||||
"baseFunctions": [
|
||||
9722
|
||||
],
|
||||
"baseFunctions": [9722],
|
||||
"body": {
|
||||
"id": 8814,
|
||||
"nodeType": "Block",
|
||||
|
@ -1719,9 +1699,7 @@
|
|||
"visibility": "public"
|
||||
},
|
||||
{
|
||||
"baseFunctions": [
|
||||
9732
|
||||
],
|
||||
"baseFunctions": [9732],
|
||||
"body": {
|
||||
"id": 8832,
|
||||
"nodeType": "Block",
|
||||
|
@ -1928,9 +1906,7 @@
|
|||
"visibility": "public"
|
||||
},
|
||||
{
|
||||
"baseFunctions": [
|
||||
9742
|
||||
],
|
||||
"baseFunctions": [9742],
|
||||
"body": {
|
||||
"id": 8853,
|
||||
"nodeType": "Block",
|
||||
|
@ -2194,9 +2170,7 @@
|
|||
"visibility": "public"
|
||||
},
|
||||
{
|
||||
"baseFunctions": [
|
||||
9754
|
||||
],
|
||||
"baseFunctions": [9754],
|
||||
"body": {
|
||||
"id": 8891,
|
||||
"nodeType": "Block",
|
||||
|
@ -3653,10 +3627,7 @@
|
|||
"id": 8959,
|
||||
"name": "require",
|
||||
"nodeType": "Identifier",
|
||||
"overloadedDeclarations": [
|
||||
-18,
|
||||
-18
|
||||
],
|
||||
"overloadedDeclarations": [-18, -18],
|
||||
"referencedDeclaration": -18,
|
||||
"src": "7132:7:84",
|
||||
"typeDescriptions": {
|
||||
|
@ -3818,10 +3789,7 @@
|
|||
"id": 8969,
|
||||
"name": "require",
|
||||
"nodeType": "Identifier",
|
||||
"overloadedDeclarations": [
|
||||
-18,
|
||||
-18
|
||||
],
|
||||
"overloadedDeclarations": [-18, -18],
|
||||
"referencedDeclaration": -18,
|
||||
"src": "7212:7:84",
|
||||
"typeDescriptions": {
|
||||
|
@ -4615,10 +4583,7 @@
|
|||
"id": 9023,
|
||||
"name": "require",
|
||||
"nodeType": "Identifier",
|
||||
"overloadedDeclarations": [
|
||||
-18,
|
||||
-18
|
||||
],
|
||||
"overloadedDeclarations": [-18, -18],
|
||||
"referencedDeclaration": -18,
|
||||
"src": "7910:7:84",
|
||||
"typeDescriptions": {
|
||||
|
@ -5413,10 +5378,7 @@
|
|||
"id": 9078,
|
||||
"name": "require",
|
||||
"nodeType": "Identifier",
|
||||
"overloadedDeclarations": [
|
||||
-18,
|
||||
-18
|
||||
],
|
||||
"overloadedDeclarations": [-18, -18],
|
||||
"referencedDeclaration": -18,
|
||||
"src": "8599:7:84",
|
||||
"typeDescriptions": {
|
||||
|
@ -6233,10 +6195,7 @@
|
|||
"id": 9136,
|
||||
"name": "require",
|
||||
"nodeType": "Identifier",
|
||||
"overloadedDeclarations": [
|
||||
-18,
|
||||
-18
|
||||
],
|
||||
"overloadedDeclarations": [-18, -18],
|
||||
"referencedDeclaration": -18,
|
||||
"src": "9452:7:84",
|
||||
"typeDescriptions": {
|
||||
|
@ -6398,10 +6357,7 @@
|
|||
"id": 9146,
|
||||
"name": "require",
|
||||
"nodeType": "Identifier",
|
||||
"overloadedDeclarations": [
|
||||
-18,
|
||||
-18
|
||||
],
|
||||
"overloadedDeclarations": [-18, -18],
|
||||
"referencedDeclaration": -18,
|
||||
"src": "9530:7:84",
|
||||
"typeDescriptions": {
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -389,9 +389,7 @@
|
|||
"ast": {
|
||||
"absolutePath": "/home/hhofstadt/Dev/certus/wormhole/ethereum/contracts/WrappedAsset.sol",
|
||||
"exportedSymbols": {
|
||||
"WrappedAsset": [
|
||||
1728
|
||||
]
|
||||
"WrappedAsset": [1728]
|
||||
},
|
||||
"id": 1729,
|
||||
"license": "Apache 2",
|
||||
|
@ -399,12 +397,7 @@
|
|||
"nodes": [
|
||||
{
|
||||
"id": 1186,
|
||||
"literals": [
|
||||
"solidity",
|
||||
"^",
|
||||
"0.6",
|
||||
".0"
|
||||
],
|
||||
"literals": ["solidity", "^", "0.6", ".0"],
|
||||
"nodeType": "PragmaDirective",
|
||||
"src": "67:23:3"
|
||||
},
|
||||
|
@ -492,19 +485,12 @@
|
|||
"src": "337:7:3"
|
||||
}
|
||||
],
|
||||
"contractDependencies": [
|
||||
1751,
|
||||
2025
|
||||
],
|
||||
"contractDependencies": [1751, 2025],
|
||||
"contractKind": "contract",
|
||||
"documentation": null,
|
||||
"fullyImplemented": true,
|
||||
"id": 1728,
|
||||
"linearizedBaseContracts": [
|
||||
1728,
|
||||
1751,
|
||||
2025
|
||||
],
|
||||
"linearizedBaseContracts": [1728, 1751, 2025],
|
||||
"name": "WrappedAsset",
|
||||
"nodeType": "ContractDefinition",
|
||||
"nodes": [
|
||||
|
@ -697,10 +683,7 @@
|
|||
"id": 1209,
|
||||
"name": "require",
|
||||
"nodeType": "Identifier",
|
||||
"overloadedDeclarations": [
|
||||
-18,
|
||||
-18
|
||||
],
|
||||
"overloadedDeclarations": [-18, -18],
|
||||
"referencedDeclaration": -18,
|
||||
"src": "549:7:3",
|
||||
"typeDescriptions": {
|
||||
|
@ -1275,10 +1258,7 @@
|
|||
"id": 1252,
|
||||
"name": "require",
|
||||
"nodeType": "Identifier",
|
||||
"overloadedDeclarations": [
|
||||
-18,
|
||||
-18
|
||||
],
|
||||
"overloadedDeclarations": [-18, -18],
|
||||
"referencedDeclaration": -18,
|
||||
"src": "915:7:3",
|
||||
"typeDescriptions": {
|
||||
|
@ -1568,10 +1548,7 @@
|
|||
"id": 1273,
|
||||
"name": "require",
|
||||
"nodeType": "Identifier",
|
||||
"overloadedDeclarations": [
|
||||
-18,
|
||||
-18
|
||||
],
|
||||
"overloadedDeclarations": [-18, -18],
|
||||
"referencedDeclaration": -18,
|
||||
"src": "1097:7:3",
|
||||
"typeDescriptions": {
|
||||
|
@ -2319,9 +2296,7 @@
|
|||
"visibility": "public"
|
||||
},
|
||||
{
|
||||
"baseFunctions": [
|
||||
1956
|
||||
],
|
||||
"baseFunctions": [1956],
|
||||
"body": {
|
||||
"id": 1348,
|
||||
"nodeType": "Block",
|
||||
|
@ -2415,9 +2390,7 @@
|
|||
"visibility": "public"
|
||||
},
|
||||
{
|
||||
"baseFunctions": [
|
||||
1964
|
||||
],
|
||||
"baseFunctions": [1964],
|
||||
"body": {
|
||||
"id": 1362,
|
||||
"nodeType": "Block",
|
||||
|
@ -2568,9 +2541,7 @@
|
|||
"visibility": "public"
|
||||
},
|
||||
{
|
||||
"baseFunctions": [
|
||||
1974
|
||||
],
|
||||
"baseFunctions": [1974],
|
||||
"body": {
|
||||
"id": 1383,
|
||||
"nodeType": "Block",
|
||||
|
@ -2834,9 +2805,7 @@
|
|||
"visibility": "public"
|
||||
},
|
||||
{
|
||||
"baseFunctions": [
|
||||
1984
|
||||
],
|
||||
"baseFunctions": [1984],
|
||||
"body": {
|
||||
"id": 1401,
|
||||
"nodeType": "Block",
|
||||
|
@ -3043,9 +3012,7 @@
|
|||
"visibility": "public"
|
||||
},
|
||||
{
|
||||
"baseFunctions": [
|
||||
1994
|
||||
],
|
||||
"baseFunctions": [1994],
|
||||
"body": {
|
||||
"id": 1422,
|
||||
"nodeType": "Block",
|
||||
|
@ -3309,9 +3276,7 @@
|
|||
"visibility": "public"
|
||||
},
|
||||
{
|
||||
"baseFunctions": [
|
||||
2006
|
||||
],
|
||||
"baseFunctions": [2006],
|
||||
"body": {
|
||||
"id": 1460,
|
||||
"nodeType": "Block",
|
||||
|
@ -4768,10 +4733,7 @@
|
|||
"id": 1528,
|
||||
"name": "require",
|
||||
"nodeType": "Identifier",
|
||||
"overloadedDeclarations": [
|
||||
-18,
|
||||
-18
|
||||
],
|
||||
"overloadedDeclarations": [-18, -18],
|
||||
"referencedDeclaration": -18,
|
||||
"src": "6587:7:3",
|
||||
"typeDescriptions": {
|
||||
|
@ -4933,10 +4895,7 @@
|
|||
"id": 1538,
|
||||
"name": "require",
|
||||
"nodeType": "Identifier",
|
||||
"overloadedDeclarations": [
|
||||
-18,
|
||||
-18
|
||||
],
|
||||
"overloadedDeclarations": [-18, -18],
|
||||
"referencedDeclaration": -18,
|
||||
"src": "6667:7:3",
|
||||
"typeDescriptions": {
|
||||
|
@ -5641,10 +5600,7 @@
|
|||
"id": 1586,
|
||||
"name": "require",
|
||||
"nodeType": "Identifier",
|
||||
"overloadedDeclarations": [
|
||||
-18,
|
||||
-18
|
||||
],
|
||||
"overloadedDeclarations": [-18, -18],
|
||||
"referencedDeclaration": -18,
|
||||
"src": "7299:7:3",
|
||||
"typeDescriptions": {
|
||||
|
@ -6297,10 +6253,7 @@
|
|||
"id": 1632,
|
||||
"name": "require",
|
||||
"nodeType": "Identifier",
|
||||
"overloadedDeclarations": [
|
||||
-18,
|
||||
-18
|
||||
],
|
||||
"overloadedDeclarations": [-18, -18],
|
||||
"referencedDeclaration": -18,
|
||||
"src": "7920:7:3",
|
||||
"typeDescriptions": {
|
||||
|
@ -6975,10 +6928,7 @@
|
|||
"id": 1681,
|
||||
"name": "require",
|
||||
"nodeType": "Identifier",
|
||||
"overloadedDeclarations": [
|
||||
-18,
|
||||
-18
|
||||
],
|
||||
"overloadedDeclarations": [-18, -18],
|
||||
"referencedDeclaration": -18,
|
||||
"src": "8705:7:3",
|
||||
"typeDescriptions": {
|
||||
|
@ -7140,10 +7090,7 @@
|
|||
"id": 1691,
|
||||
"name": "require",
|
||||
"nodeType": "Identifier",
|
||||
"overloadedDeclarations": [
|
||||
-18,
|
||||
-18
|
||||
],
|
||||
"overloadedDeclarations": [-18, -18],
|
||||
"referencedDeclaration": -18,
|
||||
"src": "8783:7:3",
|
||||
"typeDescriptions": {
|
||||
|
@ -7603,9 +7550,7 @@
|
|||
"legacyAST": {
|
||||
"absolutePath": "/home/hhofstadt/Dev/certus/wormhole/ethereum/contracts/WrappedAsset.sol",
|
||||
"exportedSymbols": {
|
||||
"WrappedAsset": [
|
||||
1728
|
||||
]
|
||||
"WrappedAsset": [1728]
|
||||
},
|
||||
"id": 1729,
|
||||
"license": "Apache 2",
|
||||
|
@ -7613,12 +7558,7 @@
|
|||
"nodes": [
|
||||
{
|
||||
"id": 1186,
|
||||
"literals": [
|
||||
"solidity",
|
||||
"^",
|
||||
"0.6",
|
||||
".0"
|
||||
],
|
||||
"literals": ["solidity", "^", "0.6", ".0"],
|
||||
"nodeType": "PragmaDirective",
|
||||
"src": "67:23:3"
|
||||
},
|
||||
|
@ -7706,19 +7646,12 @@
|
|||
"src": "337:7:3"
|
||||
}
|
||||
],
|
||||
"contractDependencies": [
|
||||
1751,
|
||||
2025
|
||||
],
|
||||
"contractDependencies": [1751, 2025],
|
||||
"contractKind": "contract",
|
||||
"documentation": null,
|
||||
"fullyImplemented": true,
|
||||
"id": 1728,
|
||||
"linearizedBaseContracts": [
|
||||
1728,
|
||||
1751,
|
||||
2025
|
||||
],
|
||||
"linearizedBaseContracts": [1728, 1751, 2025],
|
||||
"name": "WrappedAsset",
|
||||
"nodeType": "ContractDefinition",
|
||||
"nodes": [
|
||||
|
@ -7911,10 +7844,7 @@
|
|||
"id": 1209,
|
||||
"name": "require",
|
||||
"nodeType": "Identifier",
|
||||
"overloadedDeclarations": [
|
||||
-18,
|
||||
-18
|
||||
],
|
||||
"overloadedDeclarations": [-18, -18],
|
||||
"referencedDeclaration": -18,
|
||||
"src": "549:7:3",
|
||||
"typeDescriptions": {
|
||||
|
@ -8489,10 +8419,7 @@
|
|||
"id": 1252,
|
||||
"name": "require",
|
||||
"nodeType": "Identifier",
|
||||
"overloadedDeclarations": [
|
||||
-18,
|
||||
-18
|
||||
],
|
||||
"overloadedDeclarations": [-18, -18],
|
||||
"referencedDeclaration": -18,
|
||||
"src": "915:7:3",
|
||||
"typeDescriptions": {
|
||||
|
@ -8782,10 +8709,7 @@
|
|||
"id": 1273,
|
||||
"name": "require",
|
||||
"nodeType": "Identifier",
|
||||
"overloadedDeclarations": [
|
||||
-18,
|
||||
-18
|
||||
],
|
||||
"overloadedDeclarations": [-18, -18],
|
||||
"referencedDeclaration": -18,
|
||||
"src": "1097:7:3",
|
||||
"typeDescriptions": {
|
||||
|
@ -9533,9 +9457,7 @@
|
|||
"visibility": "public"
|
||||
},
|
||||
{
|
||||
"baseFunctions": [
|
||||
1956
|
||||
],
|
||||
"baseFunctions": [1956],
|
||||
"body": {
|
||||
"id": 1348,
|
||||
"nodeType": "Block",
|
||||
|
@ -9629,9 +9551,7 @@
|
|||
"visibility": "public"
|
||||
},
|
||||
{
|
||||
"baseFunctions": [
|
||||
1964
|
||||
],
|
||||
"baseFunctions": [1964],
|
||||
"body": {
|
||||
"id": 1362,
|
||||
"nodeType": "Block",
|
||||
|
@ -9782,9 +9702,7 @@
|
|||
"visibility": "public"
|
||||
},
|
||||
{
|
||||
"baseFunctions": [
|
||||
1974
|
||||
],
|
||||
"baseFunctions": [1974],
|
||||
"body": {
|
||||
"id": 1383,
|
||||
"nodeType": "Block",
|
||||
|
@ -10048,9 +9966,7 @@
|
|||
"visibility": "public"
|
||||
},
|
||||
{
|
||||
"baseFunctions": [
|
||||
1984
|
||||
],
|
||||
"baseFunctions": [1984],
|
||||
"body": {
|
||||
"id": 1401,
|
||||
"nodeType": "Block",
|
||||
|
@ -10257,9 +10173,7 @@
|
|||
"visibility": "public"
|
||||
},
|
||||
{
|
||||
"baseFunctions": [
|
||||
1994
|
||||
],
|
||||
"baseFunctions": [1994],
|
||||
"body": {
|
||||
"id": 1422,
|
||||
"nodeType": "Block",
|
||||
|
@ -10523,9 +10437,7 @@
|
|||
"visibility": "public"
|
||||
},
|
||||
{
|
||||
"baseFunctions": [
|
||||
2006
|
||||
],
|
||||
"baseFunctions": [2006],
|
||||
"body": {
|
||||
"id": 1460,
|
||||
"nodeType": "Block",
|
||||
|
@ -11982,10 +11894,7 @@
|
|||
"id": 1528,
|
||||
"name": "require",
|
||||
"nodeType": "Identifier",
|
||||
"overloadedDeclarations": [
|
||||
-18,
|
||||
-18
|
||||
],
|
||||
"overloadedDeclarations": [-18, -18],
|
||||
"referencedDeclaration": -18,
|
||||
"src": "6587:7:3",
|
||||
"typeDescriptions": {
|
||||
|
@ -12147,10 +12056,7 @@
|
|||
"id": 1538,
|
||||
"name": "require",
|
||||
"nodeType": "Identifier",
|
||||
"overloadedDeclarations": [
|
||||
-18,
|
||||
-18
|
||||
],
|
||||
"overloadedDeclarations": [-18, -18],
|
||||
"referencedDeclaration": -18,
|
||||
"src": "6667:7:3",
|
||||
"typeDescriptions": {
|
||||
|
@ -12855,10 +12761,7 @@
|
|||
"id": 1586,
|
||||
"name": "require",
|
||||
"nodeType": "Identifier",
|
||||
"overloadedDeclarations": [
|
||||
-18,
|
||||
-18
|
||||
],
|
||||
"overloadedDeclarations": [-18, -18],
|
||||
"referencedDeclaration": -18,
|
||||
"src": "7299:7:3",
|
||||
"typeDescriptions": {
|
||||
|
@ -13511,10 +13414,7 @@
|
|||
"id": 1632,
|
||||
"name": "require",
|
||||
"nodeType": "Identifier",
|
||||
"overloadedDeclarations": [
|
||||
-18,
|
||||
-18
|
||||
],
|
||||
"overloadedDeclarations": [-18, -18],
|
||||
"referencedDeclaration": -18,
|
||||
"src": "7920:7:3",
|
||||
"typeDescriptions": {
|
||||
|
@ -14189,10 +14089,7 @@
|
|||
"id": 1681,
|
||||
"name": "require",
|
||||
"nodeType": "Identifier",
|
||||
"overloadedDeclarations": [
|
||||
-18,
|
||||
-18
|
||||
],
|
||||
"overloadedDeclarations": [-18, -18],
|
||||
"referencedDeclaration": -18,
|
||||
"src": "8705:7:3",
|
||||
"typeDescriptions": {
|
||||
|
@ -14354,10 +14251,7 @@
|
|||
"id": 1691,
|
||||
"name": "require",
|
||||
"nodeType": "Identifier",
|
||||
"overloadedDeclarations": [
|
||||
-18,
|
||||
-18
|
||||
],
|
||||
"overloadedDeclarations": [-18, -18],
|
||||
"referencedDeclaration": -18,
|
||||
"src": "8783:7:3",
|
||||
"typeDescriptions": {
|
||||
|
|
|
@ -13,7 +13,9 @@ const resolvePackage = relativePath => path.resolve(appDirectory, relativePath);
|
|||
module.exports = {
|
||||
webpack: {
|
||||
configure: (webpackConfig, { env, paths }) => {
|
||||
paths.appBuild = webpackConfig.output.path = path.resolve('./../../build/bridge');
|
||||
paths.appBuild = webpackConfig.output.path = path.resolve(
|
||||
'./../../build/bridge',
|
||||
);
|
||||
return webpackConfig;
|
||||
},
|
||||
},
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import React from "react";
|
||||
import "./App.less";
|
||||
import { Routes } from "./routes";
|
||||
import React from 'react';
|
||||
import './App.less';
|
||||
import { Routes } from './routes';
|
||||
|
||||
function App() {
|
||||
return <Routes />;
|
||||
|
|
|
@ -1,2 +1 @@
|
|||
export * from './solana';
|
||||
export * from './ethereum';
|
||||
export * from './input';
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
import React, {useState} from 'react';
|
||||
import {NumericInput, programIds} from '@oyster/common';
|
||||
import {Card, Select} from 'antd';
|
||||
import React, { useState } from 'react';
|
||||
import { NumericInput, programIds } from '@oyster/common';
|
||||
import { Card, Select } from 'antd';
|
||||
import './style.less';
|
||||
import {useEthereum} from '../../contexts';
|
||||
import {WrappedAssetFactory} from '../../contracts/WrappedAssetFactory';
|
||||
import {WormholeFactory} from '../../contracts/WormholeFactory';
|
||||
import {TransferRequestInfo} from '../../models/bridge';
|
||||
import {TokenDisplay} from '../TokenDisplay'
|
||||
import { useEthereum } from '../../contexts';
|
||||
import { WrappedAssetFactory } from '../../contracts/WrappedAssetFactory';
|
||||
import { WormholeFactory } from '../../contracts/WormholeFactory';
|
||||
import { TransferRequestInfo } from '../../models/bridge';
|
||||
import { TokenDisplay } from '../TokenDisplay';
|
||||
import BN from 'bn.js';
|
||||
import {ASSET_CHAIN} from "../../models/bridge/constants";
|
||||
import { ASSET_CHAIN } from '../../models/bridge/constants';
|
||||
|
||||
const { Option } = Select;
|
||||
|
||||
|
@ -17,6 +17,7 @@ export function EthereumInput(props: {
|
|||
hideBalance?: boolean;
|
||||
|
||||
asset?: string;
|
||||
chain?: ASSET_CHAIN;
|
||||
setAsset: (asset: string) => void;
|
||||
|
||||
setInfo: (info: TransferRequestInfo) => void;
|
||||
|
@ -27,28 +28,40 @@ export function EthereumInput(props: {
|
|||
const [lastAmount, setLastAmount] = useState<string>('');
|
||||
const { tokens, provider } = useEthereum();
|
||||
|
||||
const renderReserveAccounts = tokens.filter(t => (t.tags?.indexOf('longList') || -1) < 0).map((token) => {
|
||||
const mint = token.address;
|
||||
return (
|
||||
<Option key={mint} className="multichain-option" value={mint} name={token.symbol} title={token.name}>
|
||||
<div className="multichain-option-content">
|
||||
<TokenDisplay asset={props.asset} token={token} chain={ASSET_CHAIN.Ethereum}/>
|
||||
<div className="multichain-option-name">
|
||||
<span className={"token-name"}>{token.symbol}</span>
|
||||
const renderReserveAccounts = tokens
|
||||
.filter(t => (t.tags?.indexOf('longList') || -1) < 0)
|
||||
.map(token => {
|
||||
const mint = token.address;
|
||||
return (
|
||||
<Option
|
||||
key={mint}
|
||||
className="multichain-option"
|
||||
value={mint}
|
||||
name={token.symbol}
|
||||
title={token.name}
|
||||
>
|
||||
<div className="multichain-option-content">
|
||||
<TokenDisplay
|
||||
asset={props.asset}
|
||||
token={token}
|
||||
chain={props.chain}
|
||||
/>
|
||||
<div className="multichain-option-name">
|
||||
<span className={'token-name'}>{token.symbol}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Option>
|
||||
);
|
||||
});
|
||||
</Option>
|
||||
);
|
||||
});
|
||||
|
||||
const updateBalance = async (fromAddress: string) => {
|
||||
props.setAsset(fromAddress);
|
||||
|
||||
if(!provider) {
|
||||
if (!provider) {
|
||||
return;
|
||||
}
|
||||
|
||||
const bridgeAddress = programIds().wormhole.bridge;
|
||||
const bridgeAddress = programIds().wormhole.bridge;
|
||||
|
||||
let signer = provider.getSigner();
|
||||
let e = WrappedAssetFactory.connect(fromAddress, provider);
|
||||
|
@ -60,26 +73,30 @@ export function EthereumInput(props: {
|
|||
let allowance = await e.allowance(addr, bridgeAddress);
|
||||
|
||||
let info = {
|
||||
address: fromAddress,
|
||||
name: symbol,
|
||||
balance: balance,
|
||||
allowance: allowance,
|
||||
decimals: decimals,
|
||||
isWrapped: false,
|
||||
chainID: ASSET_CHAIN.Ethereum,
|
||||
assetAddress: Buffer.from(fromAddress.slice(2), "hex"),
|
||||
mint: "",
|
||||
}
|
||||
address: fromAddress,
|
||||
name: symbol,
|
||||
balance: balance,
|
||||
allowance: allowance,
|
||||
decimals: decimals,
|
||||
isWrapped: false,
|
||||
chainID: ASSET_CHAIN.Ethereum,
|
||||
assetAddress: Buffer.from(fromAddress.slice(2), 'hex'),
|
||||
mint: '',
|
||||
};
|
||||
|
||||
setBalance(new BN(info.balance.toString()).div(new BN(10).pow(new BN(info.decimals))).toNumber());
|
||||
setBalance(
|
||||
new BN(info.balance.toString())
|
||||
.div(new BN(10).pow(new BN(info.decimals)))
|
||||
.toNumber(),
|
||||
);
|
||||
|
||||
let b = WormholeFactory.connect(bridgeAddress, provider);
|
||||
|
||||
let isWrapped = await b.isWrappedAsset(fromAddress)
|
||||
let isWrapped = await b.isWrappedAsset(fromAddress);
|
||||
if (isWrapped) {
|
||||
info.chainID = await e.assetChain()
|
||||
info.assetAddress = Buffer.from((await e.assetAddress()).slice(2), "hex")
|
||||
info.isWrapped = true
|
||||
info.chainID = await e.assetChain();
|
||||
info.assetAddress = Buffer.from((await e.assetAddress()).slice(2), 'hex');
|
||||
info.isWrapped = true;
|
||||
}
|
||||
|
||||
props.setInfo(info);
|
||||
|
@ -103,10 +120,13 @@ export function EthereumInput(props: {
|
|||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div className="ccy-input-header" style={{ padding: '0px 10px 5px 7px', height: 80 }}>
|
||||
<div
|
||||
className="ccy-input-header"
|
||||
style={{ padding: '0px 10px 5px 7px', height: 80 }}
|
||||
>
|
||||
<NumericInput
|
||||
value={
|
||||
parseFloat(lastAmount || '0.00') === props.amount
|
||||
parseFloat(lastAmount || '0.00') === props.amount
|
||||
? lastAmount
|
||||
: props.amount?.toFixed(6)?.toString()
|
||||
}
|
|
@ -1,136 +0,0 @@
|
|||
import React, {useEffect, useState} from 'react';
|
||||
import {NumericInput, useConnectionConfig, useMint, useUserAccounts, utils} from '@oyster/common';
|
||||
import {Card, Select} from 'antd';
|
||||
import { TokenInfo } from '@uniswap/token-lists';
|
||||
import './style.less';
|
||||
import {TokenDisplay} from '../TokenDisplay'
|
||||
import {ASSET_CHAIN} from "../../models/bridge/constants";
|
||||
|
||||
const { Option } = Select;
|
||||
|
||||
// TODO: add way to add new token account
|
||||
|
||||
export function SolanaInput(props: {
|
||||
title: string;
|
||||
toToken?: TokenInfo;
|
||||
disabled?: boolean;
|
||||
amount?: number | null;
|
||||
onInputChange: (value: number | null) => void;
|
||||
hideBalance?: boolean;
|
||||
useFirstToken?: boolean;
|
||||
onMintChange?: (value: string) => void;
|
||||
}) {
|
||||
const { tokens, tokenMap } = useConnectionConfig();
|
||||
const { userAccounts } = useUserAccounts();
|
||||
const [balance, setBalance] = useState<number>(0);
|
||||
const [lastAmount, setLastAmount] = useState<string>('');
|
||||
const [currentMint, setCurrentMint] = useState<string>('')
|
||||
|
||||
const mint = useMint(currentMint);
|
||||
|
||||
const renderPopularTokens = tokens.map((item) => {
|
||||
const address = item.address;
|
||||
return (
|
||||
<Option key={address} value={address} name={item.symbol} title={address}>
|
||||
<TokenDisplay
|
||||
key={address}
|
||||
asset={address}
|
||||
token={item}
|
||||
chain={ASSET_CHAIN.Solana}
|
||||
/>
|
||||
</Option>
|
||||
);
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if(!currentMint && tokens.length > 0) {
|
||||
setCurrentMint(tokens[0].address)
|
||||
}
|
||||
}, [tokens, currentMint])
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
const currentAccount = userAccounts?.find(
|
||||
(a) => a.info.mint.toBase58() === currentMint
|
||||
);
|
||||
if (currentAccount && mint) {
|
||||
setBalance(
|
||||
currentAccount.info.amount.toNumber() / Math.pow(10, mint.decimals)
|
||||
);
|
||||
} else {
|
||||
setBalance(0);
|
||||
}
|
||||
}, [currentMint, mint, userAccounts])
|
||||
|
||||
return (
|
||||
<Card
|
||||
className="ccy-input to-input"
|
||||
style={{ borderRadius: 20 }}
|
||||
bodyStyle={{ padding: 0 }}
|
||||
>
|
||||
<div className="ccy-input-header">
|
||||
<div className="ccy-input-header-left">{props.title}</div>
|
||||
|
||||
{!props.hideBalance && (
|
||||
<div
|
||||
className="ccy-input-header-right"
|
||||
onClick={e => props.onInputChange && props.onInputChange(balance)}
|
||||
>
|
||||
Balance: {balance.toFixed(6)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div className="ccy-input-header" style={{ padding: '0px 10px 10px 7px' }}>
|
||||
<NumericInput
|
||||
value={
|
||||
parseFloat(lastAmount || '0.00') === props.amount
|
||||
? lastAmount
|
||||
: props.amount?.toFixed(6)?.toString()
|
||||
}
|
||||
onChange={(val: string) => {
|
||||
if (props.onInputChange && parseFloat(val) !== props.amount) {
|
||||
if (!val || !parseFloat(val)) props.onInputChange(null);
|
||||
else props.onInputChange(parseFloat(val));
|
||||
}
|
||||
setLastAmount(val);
|
||||
}}
|
||||
style={{
|
||||
fontSize: 20,
|
||||
boxShadow: 'none',
|
||||
borderColor: 'transparent',
|
||||
outline: 'transparent',
|
||||
}}
|
||||
placeholder="0.00"
|
||||
/>
|
||||
<div className="ccy-input-header-right" style={{ display: 'flex' }}>
|
||||
{!props.disabled ? (
|
||||
<Select
|
||||
size="large"
|
||||
showSearch
|
||||
style={{ minWidth: 150 }}
|
||||
placeholder="CCY"
|
||||
value={currentMint}
|
||||
onChange={item => {
|
||||
if (props.onMintChange) props.onMintChange(item);
|
||||
setCurrentMint(item);
|
||||
}}
|
||||
filterOption={(input, option) =>
|
||||
option?.name?.toLowerCase().indexOf(input.toLowerCase()) >= 0
|
||||
}
|
||||
>
|
||||
{renderPopularTokens}
|
||||
</Select>
|
||||
) : ( props.toToken &&
|
||||
<TokenDisplay
|
||||
|
||||
key={props.toToken.address}
|
||||
asset={props.toToken.address}
|
||||
token={props.toToken}
|
||||
chain={ASSET_CHAIN.Solana}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
);
|
||||
}
|
|
@ -26,6 +26,10 @@
|
|||
box-shadow: none !important;
|
||||
align-items: center;
|
||||
}
|
||||
.ant-select-selection-search {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
}
|
||||
.ant-select-selection-item {
|
||||
display: flex;
|
||||
height: 60px;
|
||||
|
|
|
@ -3,7 +3,7 @@ import './../../App.less';
|
|||
import './index.less';
|
||||
import { Layout } from 'antd';
|
||||
import { Link, useLocation } from 'react-router-dom';
|
||||
import metamaskIcon from "../../assets/metamask.svg"
|
||||
import metamaskIcon from '../../assets/metamask.svg';
|
||||
|
||||
import { LABELS } from '../../constants';
|
||||
import { contexts, AppBar, shortenAddress } from '@oyster/common';
|
||||
|
@ -30,31 +30,38 @@ export const AppLayout = React.memo((props: any) => {
|
|||
'';
|
||||
return (
|
||||
<div className={`App`}>
|
||||
<Wormhole onCreated={() => setWormholeReady(true)} show={true} rotate={isRoot}>
|
||||
<Wormhole
|
||||
onCreated={() => setWormholeReady(true)}
|
||||
show={true}
|
||||
rotate={isRoot}
|
||||
>
|
||||
<Layout title={LABELS.APP_TITLE}>
|
||||
{isRoot && (
|
||||
<Header className="App-Bar">
|
||||
<div className="app-title">
|
||||
<Link to="/"><h2>WORMHOLE</h2></Link>
|
||||
<Link to="/">
|
||||
<h2>WORMHOLE</h2>
|
||||
</Link>
|
||||
</div>
|
||||
<AppBar
|
||||
useWalletBadge={true}
|
||||
left={
|
||||
<>
|
||||
{accounts[0] && (
|
||||
<div>
|
||||
<img
|
||||
alt={"metamask-icon"}
|
||||
width={20}
|
||||
height={20}
|
||||
src={metamaskIcon}
|
||||
style={{ marginRight: 8 }}
|
||||
/>
|
||||
{shortenAddress(accounts[0], 4)}
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
} />
|
||||
<>
|
||||
{accounts[0] && (
|
||||
<div>
|
||||
<img
|
||||
alt={'metamask-icon'}
|
||||
width={20}
|
||||
height={20}
|
||||
src={metamaskIcon}
|
||||
style={{ marginRight: 8 }}
|
||||
/>
|
||||
{shortenAddress(accounts[0], 4)}
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
}
|
||||
/>
|
||||
</Header>
|
||||
)}
|
||||
<Content style={{ padding: '0 50px' }}>{props.children}</Content>
|
||||
|
|
|
@ -11,8 +11,8 @@ export const Settings = () => {
|
|||
|
||||
return (
|
||||
<>
|
||||
<div style={{ display: "grid" }}>
|
||||
Network:{" "}
|
||||
<div style={{ display: 'grid' }}>
|
||||
Network:{' '}
|
||||
<Select
|
||||
onSelect={setEndpoint}
|
||||
value={endpoint}
|
||||
|
@ -24,7 +24,11 @@ export const Settings = () => {
|
|||
</Select.Option>
|
||||
))}
|
||||
</Select>
|
||||
{connected && <Button type="primary" onClick={disconnect}>Disconnect</Button>}
|
||||
{connected && (
|
||||
<Button type="primary" onClick={disconnect}>
|
||||
Disconnect
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
|
|
|
@ -3,12 +3,32 @@ import { TokenInfo } from '@solana/spl-token-registry';
|
|||
import { debug } from 'console';
|
||||
import React from 'react';
|
||||
import { useEthereum } from '../../contexts';
|
||||
import { ASSET_CHAIN } from "../../models/bridge/constants";
|
||||
import { ASSET_CHAIN } from '../../models/bridge/constants';
|
||||
import './style.less';
|
||||
|
||||
export const TokenDisplay = ({ asset, chain, token, logo }: { asset?: string, chain?: ASSET_CHAIN, token?: TokenInfo, logo?: string }) => {
|
||||
return <div className="token-chain-logo">
|
||||
export const TokenDisplay = ({
|
||||
asset,
|
||||
chain,
|
||||
token,
|
||||
logo,
|
||||
}: {
|
||||
asset?: string;
|
||||
chain?: ASSET_CHAIN;
|
||||
token?: TokenInfo;
|
||||
logo?: string;
|
||||
}) => {
|
||||
return (
|
||||
<div className="token-chain-logo">
|
||||
<img className="token-logo" alt="" src={logo || token?.logoURI} />
|
||||
<img className="chain-logo" alt="" src={chain === ASSET_CHAIN.Ethereum ? '/blockchains/ETH.svg' : '/blockchains/solana.webp'} />
|
||||
</div>;
|
||||
}
|
||||
<img
|
||||
className="chain-logo"
|
||||
alt=""
|
||||
src={
|
||||
chain === ASSET_CHAIN.Ethereum
|
||||
? '/blockchains/ETH.svg'
|
||||
: '/blockchains/solana.webp'
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -3,13 +3,19 @@ import { Card, notification, Spin, Button } from 'antd';
|
|||
import { TokenInfo } from '@uniswap/token-lists';
|
||||
import { LAMPORTS_PER_SOL } from '@solana/web3.js';
|
||||
import { LABELS } from '../../constants';
|
||||
import { contexts, utils, ConnectButton, programIds, formatAmount } from '@oyster/common';
|
||||
import { useHistory, useLocation } from "react-router-dom";
|
||||
import { SolanaInput, EthereumInput } from "./../Input";
|
||||
import {
|
||||
contexts,
|
||||
utils,
|
||||
ConnectButton,
|
||||
programIds,
|
||||
formatAmount,
|
||||
} from '@oyster/common';
|
||||
import { useHistory, useLocation } from 'react-router-dom';
|
||||
import { EthereumInput } from './../Input';
|
||||
|
||||
import './style.less';
|
||||
import { ethers } from 'ethers';
|
||||
import { ASSET_CHAIN } from '../../utils/assets';
|
||||
import { ASSET_CHAIN, chainToName } from '../../utils/assets';
|
||||
import { BigNumber } from 'ethers/utils';
|
||||
import { Erc20Factory } from '../../contracts/Erc20Factory';
|
||||
import { ProgressUpdate, transfer, TransferRequest } from '../../models/bridge';
|
||||
|
@ -18,132 +24,208 @@ import { TokenDisplay } from './../TokenDisplay';
|
|||
|
||||
const { useConnection } = contexts.Connection;
|
||||
const { useWallet } = contexts.Wallet;
|
||||
const { notify } = utils;
|
||||
|
||||
export const typeToIcon = (type: string, isLast: boolean) => {
|
||||
const style: React.CSSProperties = { marginRight: 5 }
|
||||
switch(type) {
|
||||
case "user": return <span style={style}>🪓 </span>;
|
||||
case "done": return <span style={style}>✅ </span>;
|
||||
case "error": return <span style={style}>❌ </span>;
|
||||
case "wait": return isLast ? <Spin /> : <span style={style}> ✅ </span>;
|
||||
default: return null;
|
||||
const style: React.CSSProperties = { marginRight: 5 };
|
||||
switch (type) {
|
||||
case 'user':
|
||||
return <span style={style}>🪓 </span>;
|
||||
case 'done':
|
||||
return <span style={style}>✅ </span>;
|
||||
case 'error':
|
||||
return <span style={style}>❌ </span>;
|
||||
case 'wait':
|
||||
return isLast ? <Spin /> : <span style={style}> ✅ </span>;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export const Transfer = () => {
|
||||
const connection = useConnection();
|
||||
const { wallet } = useWallet();
|
||||
const { provider, tokenMap } = useEthereum();
|
||||
const { provider, tokenMap, tokens } = useEthereum();
|
||||
const [request, setRequest] = useState<TransferRequest>({
|
||||
// TODO: update based on selected asset
|
||||
asset: tokens?.[0]?.address,
|
||||
from: ASSET_CHAIN.Ethereum,
|
||||
toChain: ASSET_CHAIN.Solana,
|
||||
});
|
||||
const [toToken, setToToken] = useState<TokenInfo | undefined>()
|
||||
|
||||
const setAssetInformation = (asset:string) => {
|
||||
request.asset = asset;
|
||||
setRequest(request)
|
||||
|
||||
setToToken(tokenMap.get(request?.asset || ""))
|
||||
}
|
||||
const setAssetInformation = (asset: string) => {
|
||||
setRequest({
|
||||
...request,
|
||||
asset,
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="exchange-card">
|
||||
<EthereumInput
|
||||
<div className="exchange-card">
|
||||
<EthereumInput
|
||||
title="From Ethereum"
|
||||
setInfo={(info) => { request.info = info }}
|
||||
asset={request.asset}
|
||||
setAsset={(asset) => setAssetInformation(asset)}
|
||||
amount={request.amount}
|
||||
onInputChange={(amount) => {
|
||||
request.amount = amount || 0;
|
||||
setInfo={info => {
|
||||
request.info = info;
|
||||
}}
|
||||
asset={request.asset}
|
||||
chain={request.from}
|
||||
setAsset={asset => setAssetInformation(asset)}
|
||||
amount={request.amount}
|
||||
onInputChange={amount => {
|
||||
setRequest({
|
||||
...request,
|
||||
amount: amount || 0,
|
||||
});
|
||||
}}
|
||||
/>
|
||||
<Button type="primary" className="swap-button">
|
||||
⇅
|
||||
</Button>
|
||||
<SolanaInput
|
||||
title="To Solana"
|
||||
disabled={true}
|
||||
toToken={toToken}
|
||||
onInputChange={() => {}}
|
||||
/>
|
||||
</div>
|
||||
<ConnectButton type="primary" onClick={async () => {
|
||||
if(!wallet || !provider) {
|
||||
return;
|
||||
}
|
||||
<Button
|
||||
type="primary"
|
||||
className="swap-button"
|
||||
disabled={true}
|
||||
onClick={() => {
|
||||
const from = request.toChain;
|
||||
const toChain = request.from;
|
||||
setRequest({
|
||||
...request,
|
||||
from,
|
||||
toChain,
|
||||
});
|
||||
}}
|
||||
>
|
||||
⇅
|
||||
</Button>
|
||||
<EthereumInput
|
||||
title="To Solana"
|
||||
setInfo={info => {
|
||||
request.info = info;
|
||||
}}
|
||||
asset={request.asset}
|
||||
chain={request.toChain}
|
||||
hideBalance={true}
|
||||
setAsset={asset => setAssetInformation(asset)}
|
||||
amount={request.amount}
|
||||
onInputChange={amount => {
|
||||
setRequest({
|
||||
...request,
|
||||
amount: amount || 0,
|
||||
});
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<ConnectButton
|
||||
type="primary"
|
||||
onClick={async () => {
|
||||
if (!wallet || !provider) {
|
||||
return;
|
||||
}
|
||||
|
||||
const NotificationContent = () => {
|
||||
const [activeSteps, setActiveSteps] = useState<ProgressUpdate[]>([]);
|
||||
useEffect(() => {
|
||||
(async () => {
|
||||
let steps: ProgressUpdate[] = [];
|
||||
try {
|
||||
await transfer(connection, wallet, request, provider, (update) => {
|
||||
if(update.replace) {
|
||||
steps.pop();
|
||||
steps = [...steps, update];
|
||||
} else {
|
||||
steps = [...steps, update];
|
||||
}
|
||||
const NotificationContent = () => {
|
||||
const [activeSteps, setActiveSteps] = useState<ProgressUpdate[]>(
|
||||
[],
|
||||
);
|
||||
useEffect(() => {
|
||||
(async () => {
|
||||
let steps: ProgressUpdate[] = [];
|
||||
try {
|
||||
await transfer(
|
||||
connection,
|
||||
wallet,
|
||||
request,
|
||||
provider,
|
||||
update => {
|
||||
if (update.replace) {
|
||||
steps.pop();
|
||||
steps = [...steps, update];
|
||||
} else {
|
||||
steps = [...steps, update];
|
||||
}
|
||||
|
||||
setActiveSteps(steps);
|
||||
});
|
||||
} catch {
|
||||
// TODO...
|
||||
}
|
||||
})();
|
||||
}, [setActiveSteps]);
|
||||
setActiveSteps(steps);
|
||||
},
|
||||
);
|
||||
} catch {
|
||||
// TODO...
|
||||
}
|
||||
})();
|
||||
}, [setActiveSteps]);
|
||||
|
||||
return <div>
|
||||
<div style={{ display: 'flex' }}>
|
||||
<div>
|
||||
<h5>{`ETH Mainnet -> Solana Mainnet`}</h5>
|
||||
<h2>{formatAmount(request.amount || 0, 2)} {request.info?.name}</h2>
|
||||
return (
|
||||
<div>
|
||||
<div style={{ display: 'flex' }}>
|
||||
<div>
|
||||
<h5>{`${chainToName(request.from)} Mainnet -> ${chainToName(
|
||||
request.from,
|
||||
)} Mainnet`}</h5>
|
||||
<h2>
|
||||
{formatAmount(request.amount || 0, 2)}{' '}
|
||||
{request.info?.name}
|
||||
</h2>
|
||||
</div>
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
marginLeft: 'auto',
|
||||
marginRight: 10,
|
||||
}}
|
||||
>
|
||||
<TokenDisplay
|
||||
asset={request.asset}
|
||||
chain={request.from}
|
||||
token={tokenMap.get(request.asset || '')}
|
||||
/>
|
||||
<span style={{ margin: 15 }}>{'➔'}</span>
|
||||
<TokenDisplay
|
||||
asset={request.asset}
|
||||
chain={request.toChain}
|
||||
token={tokenMap.get(request.asset || '')}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div style={{ display: 'flex', marginLeft: 'auto', marginRight: 10 }}>
|
||||
<TokenDisplay asset={request.asset} chain={request.from} token={tokenMap.get(request.asset || '')} />
|
||||
<span style={{ margin: 15 }}>{'➔'}</span>
|
||||
<TokenDisplay asset={request.asset} chain={request.toChain} token={tokenMap.get(request.asset || '')} />
|
||||
<div
|
||||
style={{
|
||||
textAlign: 'left',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
}}
|
||||
>
|
||||
{(() => {
|
||||
let group = '';
|
||||
return activeSteps.map((step, i) => {
|
||||
let prevGroup = group;
|
||||
group = step.group;
|
||||
let newGroup = prevGroup !== group;
|
||||
return (
|
||||
<>
|
||||
{newGroup && <span>{group}</span>}
|
||||
<span style={{ marginLeft: 15 }}>
|
||||
{typeToIcon(
|
||||
step.type,
|
||||
activeSteps.length - 1 === i,
|
||||
)}{' '}
|
||||
{step.message}
|
||||
</span>
|
||||
</>
|
||||
);
|
||||
});
|
||||
})()}
|
||||
</div>
|
||||
</div>
|
||||
<div style={{ textAlign: 'left', display: 'flex', flexDirection: 'column' }}>
|
||||
{(() => {
|
||||
let group = '';
|
||||
return activeSteps.map((step, i) => {
|
||||
let prevGroup = group;
|
||||
group = step.group;
|
||||
let newGroup = prevGroup !== group;
|
||||
return (
|
||||
<>
|
||||
{newGroup && <span>{group}</span>}
|
||||
<span style={{ marginLeft: 15 }}>{typeToIcon(step.type, (activeSteps.length - 1) === i)} {step.message}</span>
|
||||
</>);
|
||||
});
|
||||
})()}
|
||||
</div>
|
||||
</div>;
|
||||
};
|
||||
);
|
||||
};
|
||||
|
||||
notification.open({
|
||||
message: '',
|
||||
duration: 0,
|
||||
placement: 'bottomLeft',
|
||||
description: <NotificationContent />,
|
||||
className: 'custom-class',
|
||||
style: {
|
||||
width: 500,
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
}}>
|
||||
Transfer
|
||||
</ConnectButton>
|
||||
</>
|
||||
notification.open({
|
||||
message: '',
|
||||
duration: 0,
|
||||
placement: 'bottomLeft',
|
||||
description: <NotificationContent />,
|
||||
className: 'custom-class',
|
||||
style: {
|
||||
width: 500,
|
||||
},
|
||||
});
|
||||
}}
|
||||
>
|
||||
Transfer
|
||||
</ConnectButton>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -7,6 +7,9 @@
|
|||
|
||||
.swap-button {
|
||||
border-radius: 2em;
|
||||
width: 32px;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
font-size: 20px;
|
||||
font-weight: bold;
|
||||
padding-left: 8px;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import * as React from "react";
|
||||
import { PerspectiveCamera } from "@react-three/drei";
|
||||
import { hasWindow } from "./Utils";
|
||||
import * as React from 'react';
|
||||
import { PerspectiveCamera } from '@react-three/drei';
|
||||
import { hasWindow } from './Utils';
|
||||
|
||||
/**
|
||||
* Creates the perspective Camera for our WormholeCanvas.
|
||||
|
|
|
@ -9,7 +9,13 @@ import WormholeGeometry from './WormholeGeometry';
|
|||
* @returns {JSX.Element}
|
||||
* @constructor
|
||||
*/
|
||||
const WormholeCanvas = ({ onCreated, rotate }: { onCreated: any, rotate?: boolean }) => {
|
||||
const WormholeCanvas = ({
|
||||
onCreated,
|
||||
rotate,
|
||||
}: {
|
||||
onCreated: any;
|
||||
rotate?: boolean;
|
||||
}) => {
|
||||
return (
|
||||
<Canvas onCreated={onCreated}>
|
||||
<Camera />
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
import * as React from "react";
|
||||
import { Color, Float32BufferAttribute } from "three";
|
||||
import type { Mesh, BufferGeometry } from "three";
|
||||
import { useTexture } from "@react-three/drei";
|
||||
import { useFrame, useUpdate } from "react-three-fiber";
|
||||
import * as React from 'react';
|
||||
import { Color, Float32BufferAttribute } from 'three';
|
||||
import type { Mesh, BufferGeometry } from 'three';
|
||||
import { useTexture } from '@react-three/drei';
|
||||
import { useFrame, useUpdate } from 'react-three-fiber';
|
||||
|
||||
import {
|
||||
calculateTorusProperties,
|
||||
fragmentShader,
|
||||
vertexShader,
|
||||
} from "./Utils";
|
||||
import disc from "./disc.png";
|
||||
} from './Utils';
|
||||
import disc from './disc.png';
|
||||
|
||||
// The individual "particle size".
|
||||
const PARTICLE_SIZE = 10;
|
||||
|
@ -28,18 +28,18 @@ const WormholeGeometry = ({ rotate }: { rotate?: boolean }) => {
|
|||
const uniforms = React.useMemo(
|
||||
() => ({
|
||||
// Adapt the color of the WormholeCanvas here.
|
||||
color: { value: new Color("dimgrey") },
|
||||
color: { value: new Color('dimgrey') },
|
||||
pointTexture: {
|
||||
value: pointTexture,
|
||||
},
|
||||
}),
|
||||
[pointTexture]
|
||||
[pointTexture],
|
||||
);
|
||||
|
||||
// The calculated torus properties.
|
||||
const [positionAttribute, colors, sizes] = React.useMemo(
|
||||
() => calculateTorusProperties(PARTICLE_SIZE),
|
||||
[]
|
||||
[],
|
||||
);
|
||||
|
||||
// Rotate mesh around the y axis every frame.
|
||||
|
@ -47,7 +47,7 @@ const WormholeGeometry = ({ rotate }: { rotate?: boolean }) => {
|
|||
if (mesh.current) {
|
||||
// x-Axis defines the "top" we're looking at, try e.g. 30.5
|
||||
mesh.current.rotation.x = 30;
|
||||
if(!rotate) {
|
||||
if (!rotate) {
|
||||
mesh.current.rotation.z += 0.0005;
|
||||
}
|
||||
}
|
||||
|
@ -55,9 +55,9 @@ const WormholeGeometry = ({ rotate }: { rotate?: boolean }) => {
|
|||
|
||||
// Calculate the geometry.
|
||||
const geometry = useUpdate((geo: BufferGeometry) => {
|
||||
geo.setAttribute("position", positionAttribute);
|
||||
geo.setAttribute("customColor", new Float32BufferAttribute(colors, 3));
|
||||
geo.setAttribute("size", new Float32BufferAttribute(sizes, 1));
|
||||
geo.setAttribute('position', positionAttribute);
|
||||
geo.setAttribute('customColor', new Float32BufferAttribute(colors, 3));
|
||||
geo.setAttribute('size', new Float32BufferAttribute(sizes, 1));
|
||||
}, []);
|
||||
|
||||
return (
|
||||
|
|
|
@ -19,12 +19,14 @@ const Wormhole = ({
|
|||
show: boolean;
|
||||
rotate?: boolean;
|
||||
children: React.ReactNode;
|
||||
}) => (
|
||||
!show ? <>{children}</> :
|
||||
<>
|
||||
<WormholeCanvas onCreated={onCreated} rotate={rotate} />
|
||||
<div className="wormhole-overlay">{children}</div>
|
||||
</>
|
||||
);
|
||||
}) =>
|
||||
!show ? (
|
||||
<>{children}</>
|
||||
) : (
|
||||
<>
|
||||
<WormholeCanvas onCreated={onCreated} rotate={rotate} />
|
||||
<div className="wormhole-overlay">{children}</div>
|
||||
</>
|
||||
);
|
||||
|
||||
export default Wormhole;
|
||||
|
|
|
@ -1,32 +1,36 @@
|
|||
import React, {createContext, FunctionComponent, useContext, useEffect} from "react"
|
||||
import {Connection, PublicKey} from "@solana/web3.js";
|
||||
import { SolanaBridge} from "../core";
|
||||
import { useConnection, useConnectionConfig } from "@oyster/common/dist/lib/contexts/connection";
|
||||
import React, {
|
||||
createContext,
|
||||
FunctionComponent,
|
||||
useContext,
|
||||
useEffect,
|
||||
} from 'react';
|
||||
import { Connection, PublicKey } from '@solana/web3.js';
|
||||
import { SolanaBridge } from '../core';
|
||||
import {
|
||||
useConnection,
|
||||
useConnectionConfig,
|
||||
} from '@oyster/common/dist/lib/contexts/connection';
|
||||
import { utils } from '@oyster/common';
|
||||
import { MintLayout, TOKEN_PROGRAM_ID } from "@solana/spl-token";
|
||||
import { WORMHOLE_PROGRAM_ID } from "../utils/ids";
|
||||
|
||||
|
||||
import { MintLayout, TOKEN_PROGRAM_ID } from '@solana/spl-token';
|
||||
import { WORMHOLE_PROGRAM_ID } from '../utils/ids';
|
||||
|
||||
export const BridgeContext = createContext<SolanaBridge | undefined>(undefined);
|
||||
|
||||
export const BridgeProvider: FunctionComponent = ({children}) => {
|
||||
export const BridgeProvider: FunctionComponent = ({ children }) => {
|
||||
const { endpoint } = useConnectionConfig();
|
||||
const connection = useConnection();
|
||||
const programs = utils.programIds();
|
||||
|
||||
|
||||
|
||||
/// let bridge = new SolanaBridge(endpoint, connection, programs.wormhole.pubkey, programs.token);
|
||||
/// let bridge = new SolanaBridge(endpoint, connection, programs.wormhole.pubkey, programs.token);
|
||||
|
||||
return (
|
||||
<BridgeContext.Provider value={undefined}>
|
||||
{children}
|
||||
</BridgeContext.Provider>
|
||||
)
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
export const useBridge = () => {
|
||||
const bridge = useContext(BridgeContext);
|
||||
return bridge;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
import {EventEmitter} from "@oyster/common";
|
||||
import React, {useContext, useEffect, useState} from "react";
|
||||
import {MarketsContextState} from "./market";
|
||||
import { EventEmitter } from '@oyster/common';
|
||||
import React, { useContext, useEffect, useState } from 'react';
|
||||
import { MarketsContextState } from './market';
|
||||
|
||||
export const COINGECKO_POOL_INTERVAL = 10000; // 2 min
|
||||
export const COINGECKO_API = "https://api.coingecko.com/api/v3/"
|
||||
export const COINGECKO_COIN_LIST_API = `${COINGECKO_API}coins/list`
|
||||
export const COINGECKO_COIN_PRICE_API = `${COINGECKO_API}simple/price`
|
||||
export const COINGECKO_API = 'https://api.coingecko.com/api/v3/';
|
||||
export const COINGECKO_COIN_LIST_API = `${COINGECKO_API}coins/list`;
|
||||
export const COINGECKO_COIN_PRICE_API = `${COINGECKO_API}simple/price`;
|
||||
|
||||
interface CoinInfo {
|
||||
id: string;
|
||||
|
@ -17,28 +17,30 @@ export interface CoingeckoContextState {
|
|||
coinList: Map<string, CoinInfo>;
|
||||
}
|
||||
|
||||
const CoingeckoContext = React.createContext<CoingeckoContextState | null>(null);
|
||||
const CoingeckoContext = React.createContext<CoingeckoContextState | null>(
|
||||
null,
|
||||
);
|
||||
export function CoingeckoProvider({ children = null as any }) {
|
||||
const [coinList, setCoinList] = useState<Map<string, CoinInfo>>(new Map())
|
||||
const [coinList, setCoinList] = useState<Map<string, CoinInfo>>(new Map());
|
||||
|
||||
useEffect(() => {
|
||||
(async () => {
|
||||
const listResponse = await fetch(COINGECKO_COIN_LIST_API);
|
||||
const coinList: CoinInfo[] = await listResponse.json();
|
||||
setCoinList(
|
||||
coinList.reduce((coins, val) => {
|
||||
coins.set(val.symbol, val);
|
||||
return coins;
|
||||
}, new Map<string, CoinInfo>())
|
||||
)
|
||||
})();
|
||||
}, [setCoinList]);
|
||||
(async () => {
|
||||
const listResponse = await fetch(COINGECKO_COIN_LIST_API);
|
||||
const coinList: CoinInfo[] = await listResponse.json();
|
||||
setCoinList(
|
||||
coinList.reduce((coins, val) => {
|
||||
coins.set(val.symbol, val);
|
||||
return coins;
|
||||
}, new Map<string, CoinInfo>()),
|
||||
);
|
||||
})();
|
||||
}, [setCoinList]);
|
||||
|
||||
return (
|
||||
<CoingeckoContext.Provider value={{coinList: coinList}}>
|
||||
<CoingeckoContext.Provider value={{ coinList: coinList }}>
|
||||
{children}
|
||||
</CoingeckoContext.Provider>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
export const useCoingecko = () => {
|
||||
|
|
|
@ -1,15 +1,22 @@
|
|||
import React, { createContext, FunctionComponent, useCallback, useContext, useEffect, useState } from "react";
|
||||
import React, {
|
||||
createContext,
|
||||
FunctionComponent,
|
||||
useCallback,
|
||||
useContext,
|
||||
useEffect,
|
||||
useState,
|
||||
} from 'react';
|
||||
// @ts-ignore
|
||||
import { useWallet as useEthereumWallet } from "use-wallet";
|
||||
import { useWallet as useEthereumWallet } from 'use-wallet';
|
||||
|
||||
// @ts-ignore
|
||||
import WalletConnectProvider from "@walletconnect/web3-provider";
|
||||
import WalletConnectProvider from '@walletconnect/web3-provider';
|
||||
// @ts-ignore
|
||||
import Fortmatic from "fortmatic";
|
||||
import Torus from "@toruslabs/torus-embed";
|
||||
import { useConnectionConfig, useWallet, ENV } from "@oyster/common";
|
||||
import Fortmatic from 'fortmatic';
|
||||
import Torus from '@toruslabs/torus-embed';
|
||||
import { useConnectionConfig, useWallet, ENV } from '@oyster/common';
|
||||
import { TokenList, TokenInfo } from '@uniswap/token-lists';
|
||||
import { ethers } from "ethers";
|
||||
import { ethers } from 'ethers';
|
||||
|
||||
export interface EthereumContextState {
|
||||
provider?: ethers.providers.Web3Provider;
|
||||
|
@ -25,15 +32,15 @@ export const EthereumContext = createContext<EthereumContextState>({
|
|||
accounts: [''],
|
||||
});
|
||||
|
||||
export const EthereumProvider: FunctionComponent = ({children}) => {
|
||||
export const EthereumProvider: FunctionComponent = ({ children }) => {
|
||||
const [accounts, setAccounts] = useState<string[]>(['']);
|
||||
const [provider, setProvider] = useState<ethers.providers.Web3Provider>();
|
||||
const { env } = useConnectionConfig();
|
||||
const { connected } = useWallet();
|
||||
const wallet = useEthereumWallet();
|
||||
const [tokens, setTokens] = useState<{
|
||||
map: Map<string, TokenInfo>,
|
||||
list: TokenInfo[],
|
||||
map: Map<string, TokenInfo>;
|
||||
list: TokenInfo[];
|
||||
}>({
|
||||
map: new Map<string, TokenInfo>(),
|
||||
list: [],
|
||||
|
@ -42,26 +49,36 @@ export const EthereumProvider: FunctionComponent = ({children}) => {
|
|||
useEffect(() => {
|
||||
(async () => {
|
||||
const map = new Map<string, TokenInfo>();
|
||||
const listResponse: TokenList[] = (await Promise.all([
|
||||
fetch('https://gateway.ipfs.io/ipns/tokens.uniswap.org').then(_ => _.json()),
|
||||
const listResponse: TokenList[] = await Promise.all([
|
||||
fetch('https://gateway.ipfs.io/ipns/tokens.uniswap.org').then(_ =>
|
||||
_.json(),
|
||||
),
|
||||
fetch('https://tokenlist.aave.eth.link/').then(_ => _.json()),
|
||||
fetch('https://tokens.coingecko.com/uniswap/all.json').then(_ => _.json()),
|
||||
]));
|
||||
fetch('https://tokens.coingecko.com/uniswap/all.json').then(_ =>
|
||||
_.json(),
|
||||
),
|
||||
]);
|
||||
|
||||
listResponse.forEach((list, i) =>
|
||||
list.tokens.reduce((acc, val) => {
|
||||
const address = val.address.toLowerCase();
|
||||
const extraTag = i === 2 && !acc.has(address) ? 'longList' : '';
|
||||
|
||||
listResponse.forEach((list, i) => list.tokens.reduce((acc, val) => {
|
||||
const address = val.address.toLowerCase();
|
||||
const extraTag = i === 2 && !acc.has(address) ? 'longList' : '';
|
||||
const item = {
|
||||
...val,
|
||||
logoURI: val.logoURI
|
||||
? val.logoURI?.replace(
|
||||
'ipfs://',
|
||||
'https://cloudflare-ipfs.com/ipfs/',
|
||||
)
|
||||
: ` https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/ethereum/assets/${val.address}/logo.png `,
|
||||
tags: val.tags ? [...val.tags, extraTag] : [extraTag],
|
||||
};
|
||||
|
||||
const item = {
|
||||
...val,
|
||||
logoURI: val.logoURI ? val.logoURI?.replace('ipfs://', 'https://cloudflare-ipfs.com/ipfs/') : ` https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/ethereum/assets/${val.address}/logo.png `,
|
||||
tags: val.tags ? [...val.tags, extraTag] : [extraTag]
|
||||
};
|
||||
|
||||
acc.set(address, item);
|
||||
return acc;
|
||||
}, map));
|
||||
acc.set(address, item);
|
||||
return acc;
|
||||
}, map),
|
||||
);
|
||||
|
||||
setTokens({
|
||||
map,
|
||||
|
@ -71,26 +88,30 @@ export const EthereumProvider: FunctionComponent = ({children}) => {
|
|||
}, [setTokens]);
|
||||
|
||||
useEffect(() => {
|
||||
if(connected) {
|
||||
// @ts-ignore
|
||||
window.ethereum.enable();
|
||||
// @ts-ignore
|
||||
const provider = new ethers.providers.Web3Provider(window.ethereum as any);
|
||||
const signer = provider.getSigner();
|
||||
signer.getAddress().then(account => setAccounts([account]));
|
||||
if (connected) {
|
||||
// @ts-ignore
|
||||
window.ethereum.enable();
|
||||
// @ts-ignore
|
||||
const provider = new ethers.providers.Web3Provider(
|
||||
(window as any).ethereum ,
|
||||
);
|
||||
const signer = provider.getSigner();
|
||||
signer.getAddress().then(account => setAccounts([account]));
|
||||
|
||||
setProvider(provider);
|
||||
setProvider(provider);
|
||||
}
|
||||
}, [connected])
|
||||
}, [connected]);
|
||||
|
||||
return (
|
||||
<EthereumContext.Provider value={{ tokens: tokens.list, tokenMap: tokens.map, accounts, provider }}>
|
||||
<EthereumContext.Provider
|
||||
value={{ tokens: tokens.list, tokenMap: tokens.map, accounts, provider }}
|
||||
>
|
||||
{children}
|
||||
</EthereumContext.Provider>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
export const useEthereum = () => {
|
||||
const context = useContext(EthereumContext);
|
||||
return context;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
export * from "./market";
|
||||
export * from "./tokenPair";
|
||||
export * from "./ethereum";
|
||||
export * from './market';
|
||||
export * from './tokenPair';
|
||||
export * from './ethereum';
|
||||
|
|
|
@ -4,13 +4,21 @@ import React, {
|
|||
useEffect,
|
||||
useMemo,
|
||||
useState,
|
||||
} from "react";
|
||||
import { MintInfo } from "@solana/spl-token";
|
||||
import { useHistory, useLocation } from "react-router-dom";
|
||||
import bs58 from "bs58";
|
||||
import { TokenAccount } from "@oyster/common";
|
||||
} from 'react';
|
||||
import { MintInfo } from '@solana/spl-token';
|
||||
import { useHistory, useLocation } from 'react-router-dom';
|
||||
import bs58 from 'bs58';
|
||||
import { TokenAccount } from '@oyster/common';
|
||||
import { TokenInfo } from '@solana/spl-token-registry';
|
||||
import { useConnection, useConnectionConfig, useAccountByMint, useMint, getTokenName, getTokenIcon, convert } from "@oyster/common";
|
||||
import {
|
||||
useConnection,
|
||||
useConnectionConfig,
|
||||
useAccountByMint,
|
||||
useMint,
|
||||
getTokenName,
|
||||
getTokenIcon,
|
||||
convert,
|
||||
} from '@oyster/common';
|
||||
|
||||
export interface TokenContextState {
|
||||
mintAddress: string;
|
||||
|
@ -33,7 +41,7 @@ export interface TokenPairContextState {
|
|||
}
|
||||
|
||||
const TokenPairContext = React.createContext<TokenPairContextState | null>(
|
||||
null
|
||||
null,
|
||||
);
|
||||
|
||||
const convertAmount = (amount: string, mint?: MintInfo) => {
|
||||
|
@ -42,8 +50,8 @@ const convertAmount = (amount: string, mint?: MintInfo) => {
|
|||
|
||||
export const useCurrencyLeg = (defaultMint?: string) => {
|
||||
const { tokenMap } = useConnectionConfig();
|
||||
const [amount, setAmount] = useState("");
|
||||
const [mintAddress, setMintAddress] = useState(defaultMint || "");
|
||||
const [amount, setAmount] = useState('');
|
||||
const [mintAddress, setMintAddress] = useState(defaultMint || '');
|
||||
const account = useAccountByMint(mintAddress);
|
||||
const mint = useMint(mintAddress);
|
||||
|
||||
|
@ -59,18 +67,9 @@ export const useCurrencyLeg = (defaultMint?: string) => {
|
|||
setMint: setMintAddress,
|
||||
convertAmount: () => convertAmount(amount, mint),
|
||||
sufficientBalance: () =>
|
||||
account !== undefined &&
|
||||
(convert(account, mint) >= parseFloat(amount))
|
||||
account !== undefined && convert(account, mint) >= parseFloat(amount),
|
||||
}),
|
||||
[
|
||||
mintAddress,
|
||||
account,
|
||||
mint,
|
||||
amount,
|
||||
tokenMap,
|
||||
setAmount,
|
||||
setMintAddress,
|
||||
]
|
||||
[mintAddress, account, mint, amount, tokenMap, setAmount, setMintAddress],
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -80,7 +79,7 @@ export function TokenPairProvider({ children = null as any }) {
|
|||
|
||||
const history = useHistory();
|
||||
const location = useLocation();
|
||||
const [lastTypedAccount, setLastTypedAccount] = useState("");
|
||||
const [lastTypedAccount, setLastTypedAccount] = useState('');
|
||||
|
||||
const base = useCurrencyLeg();
|
||||
const mintAddressA = base.mintAddress;
|
||||
|
@ -96,11 +95,9 @@ export function TokenPairProvider({ children = null as any }) {
|
|||
|
||||
useEffect(() => {
|
||||
const base =
|
||||
tokens.find((t) => t.address === mintAddressA)?.symbol ||
|
||||
mintAddressA;
|
||||
tokens.find(t => t.address === mintAddressA)?.symbol || mintAddressA;
|
||||
const quote =
|
||||
tokens.find((t) => t.address === mintAddressB)?.symbol ||
|
||||
mintAddressB;
|
||||
tokens.find(t => t.address === mintAddressB)?.symbol || mintAddressB;
|
||||
|
||||
document.title = `Swap | Serum (${base}/${quote})`;
|
||||
}, [mintAddressA, mintAddressB, tokens, location]);
|
||||
|
@ -109,13 +106,11 @@ export function TokenPairProvider({ children = null as any }) {
|
|||
useEffect(() => {
|
||||
// set history
|
||||
const base =
|
||||
tokens.find((t) => t.address === mintAddressA)?.symbol ||
|
||||
mintAddressA;
|
||||
tokens.find(t => t.address === mintAddressA)?.symbol || mintAddressA;
|
||||
const quote =
|
||||
tokens.find((t) => t.address === mintAddressB)?.symbol ||
|
||||
mintAddressB;
|
||||
tokens.find(t => t.address === mintAddressB)?.symbol || mintAddressB;
|
||||
|
||||
if (base && quote && location.pathname.indexOf("info") < 0) {
|
||||
if (base && quote && location.pathname.indexOf('info') < 0) {
|
||||
history.push({
|
||||
search: `?pair=${base}-${quote}`,
|
||||
});
|
||||
|
@ -138,21 +133,21 @@ export function TokenPairProvider({ children = null as any }) {
|
|||
|
||||
let { defaultBase, defaultQuote } = getDefaultTokens(
|
||||
tokens,
|
||||
location.search
|
||||
location.search,
|
||||
);
|
||||
if (!defaultBase || !defaultQuote) {
|
||||
return;
|
||||
}
|
||||
|
||||
setMintAddressA(
|
||||
tokens.find((t) => t.symbol === defaultBase)?.address ||
|
||||
(isValidAddress(defaultBase) ? defaultBase : "") ||
|
||||
""
|
||||
tokens.find(t => t.symbol === defaultBase)?.address ||
|
||||
(isValidAddress(defaultBase) ? defaultBase : '') ||
|
||||
'',
|
||||
);
|
||||
setMintAddressB(
|
||||
tokens.find((t) => t.symbol === defaultQuote)?.address ||
|
||||
(isValidAddress(defaultQuote) ? defaultQuote : "") ||
|
||||
""
|
||||
tokens.find(t => t.symbol === defaultQuote)?.address ||
|
||||
(isValidAddress(defaultQuote) ? defaultQuote : '') ||
|
||||
'',
|
||||
);
|
||||
// mintAddressA and mintAddressB are not included here to prevent infinite loop
|
||||
// eslint-disable-next-line
|
||||
|
@ -175,12 +170,12 @@ export function TokenPairProvider({ children = null as any }) {
|
|||
|
||||
// TODO: calculate
|
||||
const result: number | string = 0;
|
||||
if (typeof result === "string") {
|
||||
if (typeof result === 'string') {
|
||||
setDependent(result);
|
||||
} else if (result !== undefined && Number.isFinite(result)) {
|
||||
setDependent(result.toFixed(6));
|
||||
} else {
|
||||
setDependent("");
|
||||
setDependent('');
|
||||
}
|
||||
}
|
||||
}, [
|
||||
|
@ -228,8 +223,8 @@ const isValidAddress = (address: string) => {
|
|||
};
|
||||
|
||||
function getDefaultTokens(tokens: TokenInfo[], search: string) {
|
||||
let defaultBase = "SOL";
|
||||
let defaultQuote = "USDC";
|
||||
let defaultBase = 'SOL';
|
||||
let defaultQuote = 'USDC';
|
||||
|
||||
const nameToToken = tokens.reduce((map, item) => {
|
||||
map.set(item.symbol, item);
|
||||
|
@ -238,9 +233,9 @@ function getDefaultTokens(tokens: TokenInfo[], search: string) {
|
|||
|
||||
if (search) {
|
||||
const urlParams = new URLSearchParams(search);
|
||||
const pair = urlParams.get("pair");
|
||||
const pair = urlParams.get('pair');
|
||||
if (pair) {
|
||||
let items = pair.split("-");
|
||||
let items = pair.split('-');
|
||||
|
||||
if (items.length > 1) {
|
||||
if (nameToToken.has(items[0]) || isValidAddress(items[0])) {
|
||||
|
|
|
@ -1,21 +1,30 @@
|
|||
import {useCallback, useEffect, useRef, useState} from "react";
|
||||
import { useConnection, useConnectionConfig, MintParser, cache, getMultipleAccounts, ParsedAccount, TokenAccountParser} from "@oyster/common";
|
||||
import {WORMHOLE_PROGRAM_ID} from "../utils/ids";
|
||||
import {ASSET_CHAIN} from "../utils/assets";
|
||||
import { useEthereum } from "../contexts";
|
||||
import { Connection, PublicKey } from "@solana/web3.js";
|
||||
import { models } from "@oyster/common";
|
||||
import { AccountInfo, MintInfo, TOKEN_PROGRAM_ID } from "@solana/spl-token";
|
||||
import { useCallback, useEffect, useRef, useState } from 'react';
|
||||
import {
|
||||
useConnection,
|
||||
useConnectionConfig,
|
||||
MintParser,
|
||||
cache,
|
||||
getMultipleAccounts,
|
||||
ParsedAccount,
|
||||
TokenAccountParser,
|
||||
} from '@oyster/common';
|
||||
import { WORMHOLE_PROGRAM_ID } from '../utils/ids';
|
||||
import { ASSET_CHAIN } from '../utils/assets';
|
||||
import { useEthereum } from '../contexts';
|
||||
import { Connection, PublicKey } from '@solana/web3.js';
|
||||
import { models } from '@oyster/common';
|
||||
import { AccountInfo, MintInfo, TOKEN_PROGRAM_ID } from '@solana/spl-token';
|
||||
import { WrappedMetaLayout } from './../models/bridge';
|
||||
import bs58 from "bs58";
|
||||
import { COINGECKO_COIN_PRICE_API, COINGECKO_POOL_INTERVAL, useCoingecko } from "../contexts/coingecko";
|
||||
import bs58 from 'bs58';
|
||||
import {
|
||||
COINGECKO_COIN_PRICE_API,
|
||||
COINGECKO_POOL_INTERVAL,
|
||||
useCoingecko,
|
||||
} from '../contexts/coingecko';
|
||||
|
||||
export const useEthUserAccount = () => {
|
||||
const [address, setAddress] = useState('');
|
||||
// const { web3 } = useEthereum();
|
||||
|
||||
|
||||
|
||||
|
||||
return address;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -1,41 +1,56 @@
|
|||
import {useCallback, useEffect, useRef, useState} from "react";
|
||||
import { useConnection, useConnectionConfig, MintParser, cache, getMultipleAccounts, ParsedAccount, TokenAccountParser, programIds, formatTokenAmount, fromLamports} from "@oyster/common";
|
||||
import {WORMHOLE_PROGRAM_ID} from "../utils/ids";
|
||||
import {ASSET_CHAIN} from "../utils/assets";
|
||||
import { useEthereum } from "../contexts";
|
||||
import { Connection, PublicKey } from "@solana/web3.js";
|
||||
import { models } from "@oyster/common";
|
||||
import { AccountInfo, MintInfo } from "@solana/spl-token";
|
||||
import { bridgeAuthorityKey, wrappedAssetMintKey, WrappedMetaLayout } from './../models/bridge';
|
||||
|
||||
import bs58 from "bs58";
|
||||
import { COINGECKO_COIN_PRICE_API, COINGECKO_POOL_INTERVAL, useCoingecko } from "../contexts/coingecko";
|
||||
import { useCallback, useEffect, useRef, useState } from 'react';
|
||||
import {
|
||||
useConnection,
|
||||
useConnectionConfig,
|
||||
MintParser,
|
||||
cache,
|
||||
getMultipleAccounts,
|
||||
ParsedAccount,
|
||||
TokenAccountParser,
|
||||
programIds,
|
||||
formatTokenAmount,
|
||||
fromLamports,
|
||||
} from '@oyster/common';
|
||||
import { WORMHOLE_PROGRAM_ID } from '../utils/ids';
|
||||
import { ASSET_CHAIN } from '../utils/assets';
|
||||
import { useEthereum } from '../contexts';
|
||||
import { Connection, PublicKey } from '@solana/web3.js';
|
||||
import { models } from '@oyster/common';
|
||||
import { AccountInfo, MintInfo } from '@solana/spl-token';
|
||||
import {
|
||||
bridgeAuthorityKey,
|
||||
wrappedAssetMintKey,
|
||||
WrappedMetaLayout,
|
||||
} from './../models/bridge';
|
||||
|
||||
import bs58 from 'bs58';
|
||||
import {
|
||||
COINGECKO_COIN_PRICE_API,
|
||||
COINGECKO_POOL_INTERVAL,
|
||||
useCoingecko,
|
||||
} from '../contexts/coingecko';
|
||||
|
||||
type WrappedAssetMeta = {
|
||||
chain: number,
|
||||
decimals: number,
|
||||
address: string,
|
||||
mintKey: string,
|
||||
mint?: ParsedAccount<MintInfo>,
|
||||
amount: number,
|
||||
amountInUSD: number,
|
||||
logo?: string,
|
||||
symbol?: string,
|
||||
name?: string,
|
||||
price?: number,
|
||||
explorer?: string,
|
||||
wrappedExplorer?: string,
|
||||
chain: number;
|
||||
decimals: number;
|
||||
address: string;
|
||||
mintKey: string;
|
||||
mint?: ParsedAccount<MintInfo>;
|
||||
amount: number;
|
||||
amountInUSD: number;
|
||||
logo?: string;
|
||||
symbol?: string;
|
||||
name?: string;
|
||||
price?: number;
|
||||
explorer?: string;
|
||||
wrappedExplorer?: string;
|
||||
};
|
||||
|
||||
|
||||
const queryWrappedMetaAccounts = async (
|
||||
authorityKey: PublicKey,
|
||||
connection: Connection,
|
||||
setExternalAssets: (arr: WrappedAssetMeta[]) => void
|
||||
) => {
|
||||
|
||||
|
||||
setExternalAssets: (arr: WrappedAssetMeta[]) => void,
|
||||
) => {
|
||||
const filters = [
|
||||
{
|
||||
dataSize: WrappedMetaLayout.span,
|
||||
|
@ -60,63 +75,75 @@ const queryWrappedMetaAccounts = async (
|
|||
const assetsByMint = new Map<string, WrappedAssetMeta>();
|
||||
|
||||
// aggregate all assets that are not from Solana
|
||||
resp.result.map((acc: any) => ({
|
||||
publicKey: new PublicKey(acc.pubkey),
|
||||
account: {
|
||||
data: bs58.decode(acc.account.data),
|
||||
executable: acc.account.executable,
|
||||
owner: new PublicKey(acc.account.owner),
|
||||
lamports: acc.account.lamports,
|
||||
},
|
||||
})).map((acc: any) => {
|
||||
if(acc.account.data.length === WrappedMetaLayout.span) {
|
||||
const metaAccount = WrappedMetaLayout.decode(acc.account.data);
|
||||
if (metaAccount.chain !== ASSET_CHAIN.Solana) {
|
||||
const assetAddress: string = new Buffer(metaAccount.address.slice(12)).toString("hex");
|
||||
resp.result
|
||||
.map((acc: any) => ({
|
||||
publicKey: new PublicKey(acc.pubkey),
|
||||
account: {
|
||||
data: bs58.decode(acc.account.data),
|
||||
executable: acc.account.executable,
|
||||
owner: new PublicKey(acc.account.owner),
|
||||
lamports: acc.account.lamports,
|
||||
},
|
||||
}))
|
||||
.map((acc: any) => {
|
||||
if (acc.account.data.length === WrappedMetaLayout.span) {
|
||||
const metaAccount = WrappedMetaLayout.decode(acc.account.data);
|
||||
if (metaAccount.chain !== ASSET_CHAIN.Solana) {
|
||||
const assetAddress: string = new Buffer(
|
||||
metaAccount.address.slice(12),
|
||||
).toString('hex');
|
||||
|
||||
assets.set(assetAddress, {
|
||||
chain: metaAccount.chain,
|
||||
address: assetAddress,
|
||||
decimals: 9,
|
||||
mintKey: '',
|
||||
amount: 0,
|
||||
amountInUSD: 0,
|
||||
// TODO: customize per chain
|
||||
explorer: `https://etherscan.io/address/0x${assetAddress}`
|
||||
});
|
||||
assets.set(assetAddress, {
|
||||
chain: metaAccount.chain,
|
||||
address: assetAddress,
|
||||
decimals: 9,
|
||||
mintKey: '',
|
||||
amount: 0,
|
||||
amountInUSD: 0,
|
||||
// TODO: customize per chain
|
||||
explorer: `https://etherscan.io/address/0x${assetAddress}`,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// build PDAs for mints
|
||||
await Promise.all([...assets.keys()].map(async key => {
|
||||
const meta = assets.get(key);
|
||||
if(!meta) {
|
||||
throw new Error('missing key');
|
||||
}
|
||||
await Promise.all(
|
||||
[...assets.keys()].map(async key => {
|
||||
const meta = assets.get(key);
|
||||
if (!meta) {
|
||||
throw new Error('missing key');
|
||||
}
|
||||
|
||||
meta.mintKey = (await wrappedAssetMintKey(programIds().wormhole.pubkey, authorityKey, {
|
||||
chain: meta.chain,
|
||||
address: Buffer.from(meta.address, "hex"),
|
||||
decimals: Math.min(meta.decimals, 9)
|
||||
})).toBase58();
|
||||
meta.mintKey = (
|
||||
await wrappedAssetMintKey(programIds().wormhole.pubkey, authorityKey, {
|
||||
chain: meta.chain,
|
||||
address: Buffer.from(meta.address, 'hex'),
|
||||
decimals: Math.min(meta.decimals, 9),
|
||||
})
|
||||
).toBase58();
|
||||
|
||||
assetsByMint.set(meta.mintKey, meta);
|
||||
assetsByMint.set(meta.mintKey, meta);
|
||||
|
||||
return meta;
|
||||
}));
|
||||
return meta;
|
||||
}),
|
||||
);
|
||||
|
||||
// query for all mints
|
||||
const mints = await getMultipleAccounts(connection, [...assetsByMint.keys()], 'singleGossip');
|
||||
const mints = await getMultipleAccounts(
|
||||
connection,
|
||||
[...assetsByMint.keys()],
|
||||
'singleGossip',
|
||||
);
|
||||
|
||||
// cache mints and listen for changes
|
||||
mints.keys.forEach((key, index) => {
|
||||
if(!mints.array[index]) {
|
||||
if (!mints.array[index]) {
|
||||
return;
|
||||
}
|
||||
|
||||
const asset = assetsByMint.get(key);
|
||||
if(!asset) {
|
||||
if (!asset) {
|
||||
throw new Error('missing mint');
|
||||
}
|
||||
|
||||
|
@ -128,50 +155,67 @@ const queryWrappedMetaAccounts = async (
|
|||
asset.mint = cache.get(key);
|
||||
asset.wrappedExplorer = `https://explorer.solana.com/address/${asset.mintKey}`;
|
||||
|
||||
if(asset.mint) {
|
||||
if (asset.mint) {
|
||||
asset.amount =
|
||||
asset.mint?.info.supply.toNumber() /
|
||||
Math.pow(10, asset.mint?.info.decimals) || 0;
|
||||
|
||||
asset.amount = asset.mint?.info.supply.toNumber() / Math.pow(10, asset.mint?.info.decimals) || 0;
|
||||
if (!asset.mint) {
|
||||
throw new Error('missing mint');
|
||||
}
|
||||
|
||||
if(!asset.mint) {
|
||||
throw new Error('missing mint')
|
||||
// monitor updates for mints
|
||||
connection.onAccountChange(asset.mint?.pubkey, acc => {
|
||||
cache.add(key, acc);
|
||||
asset.mint = cache.get(key);
|
||||
asset.amount = asset.mint?.info.supply.toNumber() || 0;
|
||||
|
||||
setExternalAssets([...assets.values()]);
|
||||
});
|
||||
}
|
||||
|
||||
// monitor updates for mints
|
||||
connection.onAccountChange(asset.mint?.pubkey, (acc) => {
|
||||
cache.add(key, acc);
|
||||
asset.mint = cache.get(key);
|
||||
asset.amount = asset.mint?.info.supply.toNumber() || 0;
|
||||
|
||||
setExternalAssets([...assets.values()]);
|
||||
});
|
||||
}
|
||||
|
||||
setExternalAssets([...assets.values()]);
|
||||
});
|
||||
};
|
||||
|
||||
const queryCustodyAccounts = async (authorityKey: PublicKey, connection: Connection) => {
|
||||
const queryCustodyAccounts = async (
|
||||
authorityKey: PublicKey,
|
||||
connection: Connection,
|
||||
) => {
|
||||
debugger;
|
||||
const tokenAccounts = await connection.getTokenAccountsByOwner(
|
||||
authorityKey,
|
||||
{
|
||||
const tokenAccounts = await connection
|
||||
.getTokenAccountsByOwner(authorityKey, {
|
||||
programId: programIds().token,
|
||||
}).then(acc => acc.value.map(a => cache.add(a.pubkey, a.account, TokenAccountParser) as ParsedAccount<AccountInfo>));
|
||||
})
|
||||
.then(acc =>
|
||||
acc.value.map(
|
||||
a =>
|
||||
cache.add(
|
||||
a.pubkey,
|
||||
a.account,
|
||||
TokenAccountParser,
|
||||
) as ParsedAccount<AccountInfo>,
|
||||
),
|
||||
);
|
||||
|
||||
// query for mints
|
||||
await getMultipleAccounts(connection, tokenAccounts.map(a => a.info.mint.toBase58()), 'single').then(({ keys, array }) => {
|
||||
await getMultipleAccounts(
|
||||
connection,
|
||||
tokenAccounts.map(a => a.info.mint.toBase58()),
|
||||
'single',
|
||||
).then(({ keys, array }) => {
|
||||
keys.forEach((key, index) => {
|
||||
if(!array[index]) {
|
||||
if (!array[index]) {
|
||||
return;
|
||||
}
|
||||
|
||||
return cache.add(key, array[index], MintParser);
|
||||
})
|
||||
});
|
||||
});
|
||||
|
||||
return tokenAccounts.map(token => {
|
||||
const mint = cache.get(token.info.mint) as ParsedAccount<MintInfo>;
|
||||
const asset = mint.pubkey.toBase58()
|
||||
const asset = mint.pubkey.toBase58();
|
||||
return {
|
||||
address: asset,
|
||||
chain: ASSET_CHAIN.Solana,
|
||||
|
@ -182,7 +226,7 @@ const queryCustodyAccounts = async (authorityKey: PublicKey, connection: Connec
|
|||
amountInUSD: 0,
|
||||
explorer: `https://explorer.solana.com/address/${asset}`,
|
||||
} as WrappedAssetMeta;
|
||||
})
|
||||
});
|
||||
};
|
||||
|
||||
export const useWormholeAccounts = () => {
|
||||
|
@ -206,22 +250,30 @@ export const useWormholeAccounts = () => {
|
|||
let authorityKey = await bridgeAuthorityKey(programIds().wormhole.pubkey);
|
||||
|
||||
// get all accounts that moved assets from solana to other chains
|
||||
const custodyAccounts = await queryCustodyAccounts(authorityKey, connection);
|
||||
const custodyAccounts = await queryCustodyAccounts(
|
||||
authorityKey,
|
||||
connection,
|
||||
);
|
||||
|
||||
// query wrapped assets that were imported to solana from other chains
|
||||
queryWrappedMetaAccounts(authorityKey, connection, (assets) => {
|
||||
setExternalAssets([...custodyAccounts, ...assets]
|
||||
.sort((a, b) => a?.symbol?.localeCompare(b.symbol || '') || 0))
|
||||
queryWrappedMetaAccounts(authorityKey, connection, assets => {
|
||||
setExternalAssets(
|
||||
[...custodyAccounts, ...assets].sort(
|
||||
(a, b) => a?.symbol?.localeCompare(b.symbol || '') || 0,
|
||||
),
|
||||
);
|
||||
}).then(() => setLoading(false));
|
||||
|
||||
// TODO: listen to solana accounts for updates
|
||||
|
||||
wormholeSubId = connection.onProgramAccountChange(WORMHOLE_PROGRAM_ID, (info) => {
|
||||
if (info.accountInfo.data.length === WrappedMetaLayout.span) {
|
||||
// TODO: check if new account and update external assets
|
||||
}
|
||||
});
|
||||
|
||||
wormholeSubId = connection.onProgramAccountChange(
|
||||
WORMHOLE_PROGRAM_ID,
|
||||
info => {
|
||||
if (info.accountInfo.data.length === WrappedMetaLayout.span) {
|
||||
// TODO: check if new account and update external assets
|
||||
}
|
||||
},
|
||||
);
|
||||
})();
|
||||
|
||||
return () => {
|
||||
|
@ -231,7 +283,7 @@ export const useWormholeAccounts = () => {
|
|||
|
||||
const coingeckoTimer = useRef<number>(0);
|
||||
const dataSourcePriceQuery = useCallback(async () => {
|
||||
if(externalAssets.length === 0) {
|
||||
if (externalAssets.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -240,58 +292,63 @@ export const useWormholeAccounts = () => {
|
|||
|
||||
const assetsToQueryNames: WrappedAssetMeta[] = [];
|
||||
|
||||
const ids = externalAssets.map(asset => {
|
||||
// TODO: add different nets/clusters
|
||||
const ids = externalAssets
|
||||
.map(asset => {
|
||||
// TODO: add different nets/clusters
|
||||
|
||||
|
||||
let knownToken = tokenMap.get(asset.mintKey);
|
||||
if (knownToken) {
|
||||
asset.logo = knownToken.logoURI;
|
||||
asset.symbol = knownToken.symbol;
|
||||
asset.name = knownToken.name;
|
||||
}
|
||||
|
||||
let token = ethTokens.get(`0x${asset.address || ''}`);
|
||||
if (token) {
|
||||
asset.logo = token.logoURI;
|
||||
asset.symbol = token.symbol;
|
||||
asset.name = token.name;
|
||||
}
|
||||
|
||||
if (asset.symbol) {
|
||||
let coinInfo = coinList.get(asset.symbol.toLowerCase());
|
||||
|
||||
if(coinInfo) {
|
||||
idToAsset.set(coinInfo.id, [...(idToAsset.get(coinInfo.id) || []), asset]);
|
||||
addressToId.set(asset.address, coinInfo.id);
|
||||
return coinInfo.id;
|
||||
let knownToken = tokenMap.get(asset.mintKey);
|
||||
if (knownToken) {
|
||||
asset.logo = knownToken.logoURI;
|
||||
asset.symbol = knownToken.symbol;
|
||||
asset.name = knownToken.name;
|
||||
}
|
||||
}
|
||||
}).filter(_ => _);
|
||||
|
||||
let token = ethTokens.get(`0x${asset.address || ''}`);
|
||||
if (token) {
|
||||
asset.logo = token.logoURI;
|
||||
asset.symbol = token.symbol;
|
||||
asset.name = token.name;
|
||||
}
|
||||
|
||||
if (asset.symbol) {
|
||||
let coinInfo = coinList.get(asset.symbol.toLowerCase());
|
||||
|
||||
if (coinInfo) {
|
||||
idToAsset.set(coinInfo.id, [
|
||||
...(idToAsset.get(coinInfo.id) || []),
|
||||
asset,
|
||||
]);
|
||||
addressToId.set(asset.address, coinInfo.id);
|
||||
return coinInfo.id;
|
||||
}
|
||||
}
|
||||
})
|
||||
.filter(_ => _);
|
||||
|
||||
assetsToQueryNames.map(() => {
|
||||
// TODO: query names using ERC-20?
|
||||
});
|
||||
|
||||
if(ids.length === 0) {
|
||||
if (ids.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const parameters = `?ids=${ids.join(',')}&vs_currencies=usd`;
|
||||
const resp = await window.fetch(COINGECKO_COIN_PRICE_API+parameters);
|
||||
const resp = await window.fetch(COINGECKO_COIN_PRICE_API + parameters);
|
||||
const data = await resp.json();
|
||||
let totalInUSD = 0;
|
||||
|
||||
Object.keys(data).forEach(key => {
|
||||
let assets = idToAsset.get(key);
|
||||
|
||||
if(!assets) {
|
||||
if (!assets) {
|
||||
return;
|
||||
}
|
||||
|
||||
assets.forEach(asset => {
|
||||
asset.price = data[key]?.usd || 1;
|
||||
asset.amountInUSD = Math.round(asset.amount * (asset.price || 1) * 100) / 100;
|
||||
asset.amountInUSD =
|
||||
Math.round(asset.amount * (asset.price || 1) * 100) / 100;
|
||||
totalInUSD += asset.amountInUSD;
|
||||
});
|
||||
});
|
||||
|
@ -300,9 +357,9 @@ export const useWormholeAccounts = () => {
|
|||
|
||||
coingeckoTimer.current = window.setTimeout(
|
||||
() => dataSourcePriceQuery(),
|
||||
COINGECKO_POOL_INTERVAL
|
||||
COINGECKO_POOL_INTERVAL,
|
||||
);
|
||||
}, [externalAssets, setAmountInUSD])
|
||||
}, [externalAssets, setAmountInUSD]);
|
||||
|
||||
useEffect(() => {
|
||||
if (externalAssets && coinList) {
|
||||
|
@ -319,4 +376,4 @@ export const useWormholeAccounts = () => {
|
|||
externalAssets,
|
||||
totalInUSD: amountInUSD,
|
||||
};
|
||||
}
|
||||
};
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
import { HashRouter, Route, Switch } from 'react-router-dom';
|
||||
import React from 'react';
|
||||
import { contexts } from '@oyster/common';
|
||||
import { MarketProvider, TokenPairProvider, EthereumProvider } from './contexts';
|
||||
import {
|
||||
MarketProvider,
|
||||
TokenPairProvider,
|
||||
EthereumProvider,
|
||||
} from './contexts';
|
||||
import { AppLayout } from './components/Layout';
|
||||
|
||||
import {
|
||||
FaucetView,
|
||||
HomeView,
|
||||
TransferView,
|
||||
} from './views';
|
||||
import {CoingeckoProvider} from "./contexts/coingecko";
|
||||
import { FaucetView, HomeView, TransferView } from './views';
|
||||
import { CoingeckoProvider } from './contexts/coingecko';
|
||||
import { BridgeProvider } from './contexts/bridge';
|
||||
import { UseWalletProvider } from 'use-wallet';
|
||||
const { WalletProvider } = contexts.Wallet;
|
||||
|
@ -30,9 +30,17 @@ export function Routes() {
|
|||
<CoingeckoProvider>
|
||||
<AppLayout>
|
||||
<Switch>
|
||||
<Route exact path="/" component={() => <HomeView />} />
|
||||
<Route
|
||||
exact
|
||||
path="/"
|
||||
component={() => <HomeView />}
|
||||
/>
|
||||
<Route path="/move" children={<TransferView />} />
|
||||
<Route exact path="/faucet" children={<FaucetView />} />
|
||||
<Route
|
||||
exact
|
||||
path="/faucet"
|
||||
children={<FaucetView />}
|
||||
/>
|
||||
</Switch>
|
||||
</AppLayout>
|
||||
</CoingeckoProvider>
|
||||
|
|
|
@ -38,3 +38,12 @@ export enum ASSET_CHAIN {
|
|||
Solana = 1,
|
||||
Ethereum = 2,
|
||||
}
|
||||
|
||||
const CHAIN_NAME = {
|
||||
[ASSET_CHAIN.Solana]: 'Solana',
|
||||
[ASSET_CHAIN.Ethereum]: 'Ethereum',
|
||||
};
|
||||
|
||||
export const chainToName = (chain?: ASSET_CHAIN) => {
|
||||
return CHAIN_NAME[chain || ASSET_CHAIN.Ethereum];
|
||||
};
|
||||
|
|
|
@ -13,7 +13,7 @@ export const FaucetView = () => {
|
|||
|
||||
const airdrop = useCallback(() => {
|
||||
if (!wallet?.publicKey) {
|
||||
return;
|
||||
return;
|
||||
}
|
||||
|
||||
connection
|
||||
|
@ -21,28 +21,28 @@ export const FaucetView = () => {
|
|||
.then(() => {
|
||||
notify({
|
||||
message: LABELS.ACCOUNT_FUNDED,
|
||||
type: "success",
|
||||
type: 'success',
|
||||
});
|
||||
});
|
||||
}, [wallet, wallet?.publicKey, connection]);
|
||||
|
||||
const bodyStyle: React.CSSProperties = {
|
||||
display: "flex",
|
||||
display: 'flex',
|
||||
flex: 1,
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
height: "100%",
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
height: '100%',
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="flexColumn" style={{ flex: 1 }}>
|
||||
<Card title={"Faucet"} bodyStyle={bodyStyle} style={{ flex: 1 }}>
|
||||
<Card title={'Faucet'} bodyStyle={bodyStyle} style={{ flex: 1 }}>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
justifyContent: "space-around",
|
||||
alignItems: "center",
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
justifyContent: 'space-around',
|
||||
alignItems: 'center',
|
||||
}}
|
||||
>
|
||||
<div className="deposit-input-title" style={{ margin: 10 }}>
|
||||
|
|
|
@ -1,18 +1,17 @@
|
|||
|
||||
import { Table, Col, Row, Statistic, Button } from 'antd';
|
||||
import React from 'react';
|
||||
import { GUTTER } from '../../constants';
|
||||
import { formatNumber, formatUSD, shortenAddress} from '@oyster/common';
|
||||
import { formatNumber, formatUSD, shortenAddress } from '@oyster/common';
|
||||
import './itemStyle.less';
|
||||
import { Link } from 'react-router-dom';
|
||||
import {useWormholeAccounts} from "../../hooks/useWormholeAccounts";
|
||||
import { useWormholeAccounts } from '../../hooks/useWormholeAccounts';
|
||||
import { TokenDisplay } from '../../components/TokenDisplay';
|
||||
|
||||
export const HomeView = () => {
|
||||
const {
|
||||
loading: loadingLockedAccounts,
|
||||
externalAssets,
|
||||
totalInUSD
|
||||
totalInUSD,
|
||||
} = useWormholeAccounts();
|
||||
|
||||
const columns = [
|
||||
|
@ -26,7 +25,12 @@ export const HomeView = () => {
|
|||
style: {},
|
||||
},
|
||||
children: (
|
||||
<span style={{ display: 'inline-flex', alignItems: 'center' }}>{record.logo && <TokenDisplay logo={record.logo} chain={record.chain} />} {record.symbol}</span>
|
||||
<span style={{ display: 'inline-flex', alignItems: 'center' }}>
|
||||
{record.logo && (
|
||||
<TokenDisplay logo={record.logo} chain={record.chain} />
|
||||
)}{' '}
|
||||
{record.symbol}
|
||||
</span>
|
||||
),
|
||||
};
|
||||
},
|
||||
|
@ -56,9 +60,7 @@ export const HomeView = () => {
|
|||
props: {
|
||||
style: { textAlign: 'right' },
|
||||
},
|
||||
children: (
|
||||
record.price ? formatUSD.format(record.price) : '--'
|
||||
),
|
||||
children: record.price ? formatUSD.format(record.price) : '--',
|
||||
};
|
||||
},
|
||||
},
|
||||
|
@ -72,7 +74,9 @@ export const HomeView = () => {
|
|||
style: {},
|
||||
},
|
||||
children: (
|
||||
<a href={record.explorer} target="_blank">{shortenAddress(text, 6)}</a>
|
||||
<a href={record.explorer} target="_blank">
|
||||
{shortenAddress(text, 6)}
|
||||
</a>
|
||||
),
|
||||
};
|
||||
},
|
||||
|
@ -87,11 +91,13 @@ export const HomeView = () => {
|
|||
style: {},
|
||||
},
|
||||
children: (
|
||||
<a href={record.wrappedExplorer} target="_blank">{shortenAddress(text, 6)}</a>
|
||||
<a href={record.wrappedExplorer} target="_blank">
|
||||
{shortenAddress(text, 6)}
|
||||
</a>
|
||||
),
|
||||
};
|
||||
},
|
||||
}
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
|
@ -104,7 +110,9 @@ export const HomeView = () => {
|
|||
>
|
||||
<Col xs={24} xl={12} className="app-title">
|
||||
<h1>Wormhole</h1>
|
||||
<h2><span>Ethereum + Solana Bridge</span></h2>
|
||||
<h2>
|
||||
<span>Ethereum + Solana Bridge</span>
|
||||
</h2>
|
||||
<Link to="/move">
|
||||
<Button className="app-action">Get Started</Button>
|
||||
</Link>
|
||||
|
@ -117,7 +125,11 @@ export const HomeView = () => {
|
|||
/>
|
||||
</Col>
|
||||
</Row>
|
||||
<Table dataSource={externalAssets.filter(a => a.name)} columns={columns} loading={loadingLockedAccounts} />
|
||||
<Table
|
||||
dataSource={externalAssets.filter(a => a.name)}
|
||||
columns={columns}
|
||||
loading={loadingLockedAccounts}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
export { HomeView } from "./home";
|
||||
export { FaucetView } from "./faucet";
|
||||
export { TransferView } from "./transfer";
|
||||
export { HomeView } from './home';
|
||||
export { FaucetView } from './faucet';
|
||||
export { TransferView } from './transfer';
|
||||
|
|
|
@ -8,9 +8,9 @@ export const TransferView = () => {
|
|||
<Card
|
||||
className="bridge-card"
|
||||
headStyle={{ padding: 0 }}
|
||||
bodyStyle={{ position: "relative" }}
|
||||
>
|
||||
<Transfer />
|
||||
bodyStyle={{ position: 'relative' }}
|
||||
>
|
||||
<Transfer />
|
||||
</Card>
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
declare module "buffer-layout" {
|
||||
declare module 'buffer-layout' {
|
||||
const bl: any;
|
||||
export = bl;
|
||||
}
|
||||
|
||||
declare module "jazzicon" {
|
||||
declare module 'jazzicon' {
|
||||
const jazzicon: any;
|
||||
export = jazzicon;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue