bridge_ui: set target address in state
Change-Id: Ie2f87582ffdc8da53ccc0f34721c3985d7807933
This commit is contained in:
parent
1f214029f5
commit
c33f3c0cb9
|
@ -29,6 +29,7 @@
|
||||||
"@solana/wallet-base": "^0.0.1",
|
"@solana/wallet-base": "^0.0.1",
|
||||||
"@solana/web3.js": "^1.22.0",
|
"@solana/web3.js": "^1.22.0",
|
||||||
"@terra-money/wallet-provider": "^1.4.0-alpha.1",
|
"@terra-money/wallet-provider": "^1.4.0-alpha.1",
|
||||||
|
"bech32": "^1.1.4",
|
||||||
"ethers": "^5.4.1",
|
"ethers": "^5.4.1",
|
||||||
"js-base64": "^3.6.1",
|
"js-base64": "^3.6.1",
|
||||||
"notistack": "^1.0.10",
|
"notistack": "^1.0.10",
|
||||||
|
@ -57,6 +58,9 @@
|
||||||
"@improbable-eng/grpc-web": "^0.14.0",
|
"@improbable-eng/grpc-web": "^0.14.0",
|
||||||
"@solana/spl-token": "^0.1.8",
|
"@solana/spl-token": "^0.1.8",
|
||||||
"@solana/web3.js": "^1.24.0",
|
"@solana/web3.js": "^1.24.0",
|
||||||
|
"@terra-money/terra.js": "^1.8.10",
|
||||||
|
"@terra-money/wallet-provider": "^1.2.4",
|
||||||
|
"js-base64": "^3.6.1",
|
||||||
"protobufjs": "^6.11.2",
|
"protobufjs": "^6.11.2",
|
||||||
"rxjs": "^7.3.0"
|
"rxjs": "^7.3.0"
|
||||||
},
|
},
|
||||||
|
@ -65,6 +69,7 @@
|
||||||
"@typechain/ethers-v5": "^7.0.1",
|
"@typechain/ethers-v5": "^7.0.1",
|
||||||
"@types/long": "^4.0.1",
|
"@types/long": "^4.0.1",
|
||||||
"@types/node": "^16.6.1",
|
"@types/node": "^16.6.1",
|
||||||
|
"@types/react": "^17.0.19",
|
||||||
"copy-dir": "^1.3.0",
|
"copy-dir": "^1.3.0",
|
||||||
"ethers": "^5.4.4",
|
"ethers": "^5.4.4",
|
||||||
"prettier": "^2.3.2",
|
"prettier": "^2.3.2",
|
||||||
|
@ -36739,6 +36744,7 @@
|
||||||
"resolved": "https://registry.npmjs.org/wasm-dce/-/wasm-dce-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/wasm-dce/-/wasm-dce-1.0.2.tgz",
|
||||||
"integrity": "sha512-Fq1+nu43ybsjSnBquLrW/cULmKs61qbv9k8ep13QUe0nABBezMoNAA+j6QY66MW0/eoDVDp1rjXDqQ2VKyS/Xg==",
|
"integrity": "sha512-Fq1+nu43ybsjSnBquLrW/cULmKs61qbv9k8ep13QUe0nABBezMoNAA+j6QY66MW0/eoDVDp1rjXDqQ2VKyS/Xg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/core": "^7.0.0-beta.39",
|
"@babel/core": "^7.0.0-beta.39",
|
||||||
"@babel/traverse": "^7.0.0-beta.39",
|
"@babel/traverse": "^7.0.0-beta.39",
|
||||||
|
@ -36752,6 +36758,7 @@
|
||||||
"resolved": "https://registry.npmjs.org/babylon/-/babylon-7.0.0-beta.47.tgz",
|
"resolved": "https://registry.npmjs.org/babylon/-/babylon-7.0.0-beta.47.tgz",
|
||||||
"integrity": "sha512-+rq2cr4GDhtToEzKFD6KZZMDBXhjFAr9JjPw9pAppZACeEWqNM294j+NdBzkSHYXwzzBmVjZ3nEVJlOhbR2gOQ==",
|
"integrity": "sha512-+rq2cr4GDhtToEzKFD6KZZMDBXhjFAr9JjPw9pAppZACeEWqNM294j+NdBzkSHYXwzzBmVjZ3nEVJlOhbR2gOQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"peer": true,
|
||||||
"bin": {
|
"bin": {
|
||||||
"babylon": "bin/babylon.js"
|
"babylon": "bin/babylon.js"
|
||||||
},
|
},
|
||||||
|
@ -37587,6 +37594,7 @@
|
||||||
"resolved": "https://registry.npmjs.org/webassembly-floating-point-hex-parser/-/webassembly-floating-point-hex-parser-0.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/webassembly-floating-point-hex-parser/-/webassembly-floating-point-hex-parser-0.1.2.tgz",
|
||||||
"integrity": "sha512-TUf1H++8U10+stJbFydnvrpG5Sznz5Rilez/oZlV5zI0C/e4cSxd8rALAJ8VpTvjVWxLmL3SVSJUK6Ap9AoiNg==",
|
"integrity": "sha512-TUf1H++8U10+stJbFydnvrpG5Sznz5Rilez/oZlV5zI0C/e4cSxd8rALAJ8VpTvjVWxLmL3SVSJUK6Ap9AoiNg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"peer": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "*"
|
"node": "*"
|
||||||
}
|
}
|
||||||
|
@ -37596,6 +37604,7 @@
|
||||||
"resolved": "https://registry.npmjs.org/webassembly-interpreter/-/webassembly-interpreter-0.0.30.tgz",
|
"resolved": "https://registry.npmjs.org/webassembly-interpreter/-/webassembly-interpreter-0.0.30.tgz",
|
||||||
"integrity": "sha512-+Jdy2piEvz9T5j751mOE8+rBO12p+nNW6Fg4kJZ+zP1oUfsm+151sbAbM8AFxWTURmWCGP+r8Lxwfv3pzN1bCQ==",
|
"integrity": "sha512-+Jdy2piEvz9T5j751mOE8+rBO12p+nNW6Fg4kJZ+zP1oUfsm+151sbAbM8AFxWTURmWCGP+r8Lxwfv3pzN1bCQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/code-frame": "^7.0.0-beta.36",
|
"@babel/code-frame": "^7.0.0-beta.36",
|
||||||
"long": "^3.2.0",
|
"long": "^3.2.0",
|
||||||
|
@ -37615,6 +37624,7 @@
|
||||||
"resolved": "https://registry.npmjs.org/long/-/long-3.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/long/-/long-3.2.0.tgz",
|
||||||
"integrity": "sha1-2CG3E4yhy1gcFymQ7xTbIAtcR0s=",
|
"integrity": "sha1-2CG3E4yhy1gcFymQ7xTbIAtcR0s=",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"peer": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.6"
|
"node": ">=0.6"
|
||||||
}
|
}
|
||||||
|
@ -41022,11 +41032,15 @@
|
||||||
"@openzeppelin/contracts": "^4.2.0",
|
"@openzeppelin/contracts": "^4.2.0",
|
||||||
"@solana/spl-token": "^0.1.8",
|
"@solana/spl-token": "^0.1.8",
|
||||||
"@solana/web3.js": "^1.24.0",
|
"@solana/web3.js": "^1.24.0",
|
||||||
|
"@terra-money/terra.js": "^1.8.10",
|
||||||
|
"@terra-money/wallet-provider": "^1.2.4",
|
||||||
"@typechain/ethers-v5": "^7.0.1",
|
"@typechain/ethers-v5": "^7.0.1",
|
||||||
"@types/long": "^4.0.1",
|
"@types/long": "^4.0.1",
|
||||||
"@types/node": "^16.6.1",
|
"@types/node": "^16.6.1",
|
||||||
|
"@types/react": "^17.0.19",
|
||||||
"copy-dir": "^1.3.0",
|
"copy-dir": "^1.3.0",
|
||||||
"ethers": "^5.4.4",
|
"ethers": "^5.4.4",
|
||||||
|
"js-base64": "^3.6.1",
|
||||||
"prettier": "^2.3.2",
|
"prettier": "^2.3.2",
|
||||||
"protobufjs": "^6.11.2",
|
"protobufjs": "^6.11.2",
|
||||||
"rxjs": "^7.3.0",
|
"rxjs": "^7.3.0",
|
||||||
|
@ -48382,7 +48396,6 @@
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"bitcore-lib": "^8.25.10",
|
|
||||||
"unorm": "^1.4.1"
|
"unorm": "^1.4.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -69246,6 +69259,7 @@
|
||||||
"resolved": "https://registry.npmjs.org/wasm-dce/-/wasm-dce-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/wasm-dce/-/wasm-dce-1.0.2.tgz",
|
||||||
"integrity": "sha512-Fq1+nu43ybsjSnBquLrW/cULmKs61qbv9k8ep13QUe0nABBezMoNAA+j6QY66MW0/eoDVDp1rjXDqQ2VKyS/Xg==",
|
"integrity": "sha512-Fq1+nu43ybsjSnBquLrW/cULmKs61qbv9k8ep13QUe0nABBezMoNAA+j6QY66MW0/eoDVDp1rjXDqQ2VKyS/Xg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"peer": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"@babel/core": "^7.0.0-beta.39",
|
"@babel/core": "^7.0.0-beta.39",
|
||||||
"@babel/traverse": "^7.0.0-beta.39",
|
"@babel/traverse": "^7.0.0-beta.39",
|
||||||
|
@ -69258,7 +69272,8 @@
|
||||||
"version": "7.0.0-beta.47",
|
"version": "7.0.0-beta.47",
|
||||||
"resolved": "https://registry.npmjs.org/babylon/-/babylon-7.0.0-beta.47.tgz",
|
"resolved": "https://registry.npmjs.org/babylon/-/babylon-7.0.0-beta.47.tgz",
|
||||||
"integrity": "sha512-+rq2cr4GDhtToEzKFD6KZZMDBXhjFAr9JjPw9pAppZACeEWqNM294j+NdBzkSHYXwzzBmVjZ3nEVJlOhbR2gOQ==",
|
"integrity": "sha512-+rq2cr4GDhtToEzKFD6KZZMDBXhjFAr9JjPw9pAppZACeEWqNM294j+NdBzkSHYXwzzBmVjZ3nEVJlOhbR2gOQ==",
|
||||||
"dev": true
|
"dev": true,
|
||||||
|
"peer": true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -69268,8 +69283,7 @@
|
||||||
"integrity": "sha512-R4s75XH+o8qM+WaRrAU9S2rbAMDzob18/S3V8R9ZoFpZkPWLAohWWlzWAp1ybeTkOuuku/X1zJtxiV0pBYxZww==",
|
"integrity": "sha512-R4s75XH+o8qM+WaRrAU9S2rbAMDzob18/S3V8R9ZoFpZkPWLAohWWlzWAp1ybeTkOuuku/X1zJtxiV0pBYxZww==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"loader-utils": "^1.1.0",
|
"loader-utils": "^1.1.0"
|
||||||
"wasm-dce": "^1.0.0"
|
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"json5": {
|
"json5": {
|
||||||
|
@ -69991,13 +70005,15 @@
|
||||||
"version": "0.1.2",
|
"version": "0.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/webassembly-floating-point-hex-parser/-/webassembly-floating-point-hex-parser-0.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/webassembly-floating-point-hex-parser/-/webassembly-floating-point-hex-parser-0.1.2.tgz",
|
||||||
"integrity": "sha512-TUf1H++8U10+stJbFydnvrpG5Sznz5Rilez/oZlV5zI0C/e4cSxd8rALAJ8VpTvjVWxLmL3SVSJUK6Ap9AoiNg==",
|
"integrity": "sha512-TUf1H++8U10+stJbFydnvrpG5Sznz5Rilez/oZlV5zI0C/e4cSxd8rALAJ8VpTvjVWxLmL3SVSJUK6Ap9AoiNg==",
|
||||||
"dev": true
|
"dev": true,
|
||||||
|
"peer": true
|
||||||
},
|
},
|
||||||
"webassembly-interpreter": {
|
"webassembly-interpreter": {
|
||||||
"version": "0.0.30",
|
"version": "0.0.30",
|
||||||
"resolved": "https://registry.npmjs.org/webassembly-interpreter/-/webassembly-interpreter-0.0.30.tgz",
|
"resolved": "https://registry.npmjs.org/webassembly-interpreter/-/webassembly-interpreter-0.0.30.tgz",
|
||||||
"integrity": "sha512-+Jdy2piEvz9T5j751mOE8+rBO12p+nNW6Fg4kJZ+zP1oUfsm+151sbAbM8AFxWTURmWCGP+r8Lxwfv3pzN1bCQ==",
|
"integrity": "sha512-+Jdy2piEvz9T5j751mOE8+rBO12p+nNW6Fg4kJZ+zP1oUfsm+151sbAbM8AFxWTURmWCGP+r8Lxwfv3pzN1bCQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"peer": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"@babel/code-frame": "^7.0.0-beta.36",
|
"@babel/code-frame": "^7.0.0-beta.36",
|
||||||
"long": "^3.2.0",
|
"long": "^3.2.0",
|
||||||
|
@ -70008,7 +70024,8 @@
|
||||||
"version": "3.2.0",
|
"version": "3.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/long/-/long-3.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/long/-/long-3.2.0.tgz",
|
||||||
"integrity": "sha1-2CG3E4yhy1gcFymQ7xTbIAtcR0s=",
|
"integrity": "sha1-2CG3E4yhy1gcFymQ7xTbIAtcR0s=",
|
||||||
"dev": true
|
"dev": true,
|
||||||
|
"peer": true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
"@solana/wallet-base": "^0.0.1",
|
"@solana/wallet-base": "^0.0.1",
|
||||||
"@solana/web3.js": "^1.22.0",
|
"@solana/web3.js": "^1.22.0",
|
||||||
"@terra-money/wallet-provider": "^1.4.0-alpha.1",
|
"@terra-money/wallet-provider": "^1.4.0-alpha.1",
|
||||||
|
"bech32": "^1.1.4",
|
||||||
"ethers": "^5.4.1",
|
"ethers": "^5.4.1",
|
||||||
"js-base64": "^3.6.1",
|
"js-base64": "^3.6.1",
|
||||||
"notistack": "^1.0.10",
|
"notistack": "^1.0.10",
|
||||||
|
|
|
@ -63,7 +63,7 @@ function Source() {
|
||||||
</TextField>
|
</TextField>
|
||||||
<KeyAndBalance chainId={sourceChain} />
|
<KeyAndBalance chainId={sourceChain} />
|
||||||
<TextField
|
<TextField
|
||||||
placeholder="Asset"
|
label="Asset"
|
||||||
fullWidth
|
fullWidth
|
||||||
className={classes.transferField}
|
className={classes.transferField}
|
||||||
value={sourceAsset}
|
value={sourceAsset}
|
||||||
|
|
|
@ -75,7 +75,7 @@ function Source() {
|
||||||
<KeyAndBalance chainId={sourceChain} balance={uiAmountString} />
|
<KeyAndBalance chainId={sourceChain} balance={uiAmountString} />
|
||||||
{/* TODO: token list for eth, check own */}
|
{/* TODO: token list for eth, check own */}
|
||||||
<TextField
|
<TextField
|
||||||
placeholder="Asset"
|
label="Asset"
|
||||||
fullWidth
|
fullWidth
|
||||||
className={classes.transferField}
|
className={classes.transferField}
|
||||||
value={sourceAsset}
|
value={sourceAsset}
|
||||||
|
@ -83,7 +83,7 @@ function Source() {
|
||||||
disabled={shouldLockFields}
|
disabled={shouldLockFields}
|
||||||
/>
|
/>
|
||||||
<TextField
|
<TextField
|
||||||
placeholder="Amount"
|
label="Amount"
|
||||||
type="number"
|
type="number"
|
||||||
fullWidth
|
fullWidth
|
||||||
className={classes.transferField}
|
className={classes.transferField}
|
||||||
|
|
|
@ -3,11 +3,13 @@ import { Button, makeStyles, MenuItem, TextField } from "@material-ui/core";
|
||||||
import { PublicKey } from "@solana/web3.js";
|
import { PublicKey } from "@solana/web3.js";
|
||||||
import { useCallback, useMemo } from "react";
|
import { useCallback, useMemo } from "react";
|
||||||
import { useDispatch, useSelector } from "react-redux";
|
import { useDispatch, useSelector } from "react-redux";
|
||||||
|
import useSyncTargetAddress from "../../hooks/useSyncTargetAddress";
|
||||||
import {
|
import {
|
||||||
selectTransferIsSourceAssetWormholeWrapped,
|
selectTransferIsSourceAssetWormholeWrapped,
|
||||||
selectTransferIsTargetComplete,
|
selectTransferIsTargetComplete,
|
||||||
selectTransferShouldLockFields,
|
selectTransferShouldLockFields,
|
||||||
selectTransferSourceChain,
|
selectTransferSourceChain,
|
||||||
|
selectTransferTargetAddressHex,
|
||||||
selectTransferTargetAsset,
|
selectTransferTargetAsset,
|
||||||
selectTransferTargetBalanceString,
|
selectTransferTargetBalanceString,
|
||||||
selectTransferTargetChain,
|
selectTransferTargetChain,
|
||||||
|
@ -32,6 +34,7 @@ function Target() {
|
||||||
[sourceChain]
|
[sourceChain]
|
||||||
);
|
);
|
||||||
const targetChain = useSelector(selectTransferTargetChain);
|
const targetChain = useSelector(selectTransferTargetChain);
|
||||||
|
const targetAddressHex = useSelector(selectTransferTargetAddressHex); // TODO: make readable
|
||||||
const targetAsset = useSelector(selectTransferTargetAsset);
|
const targetAsset = useSelector(selectTransferTargetAsset);
|
||||||
const isSourceAssetWormholeWrapped = useSelector(
|
const isSourceAssetWormholeWrapped = useSelector(
|
||||||
selectTransferIsSourceAssetWormholeWrapped
|
selectTransferIsSourceAssetWormholeWrapped
|
||||||
|
@ -47,6 +50,7 @@ function Target() {
|
||||||
const uiAmountString = useSelector(selectTransferTargetBalanceString);
|
const uiAmountString = useSelector(selectTransferTargetBalanceString);
|
||||||
const isTargetComplete = useSelector(selectTransferIsTargetComplete);
|
const isTargetComplete = useSelector(selectTransferIsTargetComplete);
|
||||||
const shouldLockFields = useSelector(selectTransferShouldLockFields);
|
const shouldLockFields = useSelector(selectTransferShouldLockFields);
|
||||||
|
useSyncTargetAddress(!shouldLockFields);
|
||||||
const handleTargetChange = useCallback(
|
const handleTargetChange = useCallback(
|
||||||
(event) => {
|
(event) => {
|
||||||
dispatch(setTargetChain(event.target.value));
|
dispatch(setTargetChain(event.target.value));
|
||||||
|
@ -76,7 +80,14 @@ function Target() {
|
||||||
</TextField>
|
</TextField>
|
||||||
<KeyAndBalance chainId={targetChain} balance={uiAmountString} />
|
<KeyAndBalance chainId={targetChain} balance={uiAmountString} />
|
||||||
<TextField
|
<TextField
|
||||||
placeholder="Asset"
|
label="Address"
|
||||||
|
fullWidth
|
||||||
|
className={classes.transferField}
|
||||||
|
value={targetAddressHex || ""}
|
||||||
|
disabled={true}
|
||||||
|
/>
|
||||||
|
<TextField
|
||||||
|
label="Asset"
|
||||||
fullWidth
|
fullWidth
|
||||||
className={classes.transferField}
|
className={classes.transferField}
|
||||||
value={readableTargetAsset}
|
value={readableTargetAsset}
|
||||||
|
|
|
@ -11,22 +11,17 @@ import {
|
||||||
transferFromEth,
|
transferFromEth,
|
||||||
transferFromSolana,
|
transferFromSolana,
|
||||||
} from "@certusone/wormhole-sdk";
|
} from "@certusone/wormhole-sdk";
|
||||||
import {
|
|
||||||
ASSOCIATED_TOKEN_PROGRAM_ID,
|
|
||||||
Token,
|
|
||||||
TOKEN_PROGRAM_ID,
|
|
||||||
} from "@solana/spl-token";
|
|
||||||
import { WalletContextState } from "@solana/wallet-adapter-react";
|
import { WalletContextState } from "@solana/wallet-adapter-react";
|
||||||
import { Connection, PublicKey } from "@solana/web3.js";
|
import { Connection } from "@solana/web3.js";
|
||||||
import { MsgExecuteContract } from "@terra-money/terra.js";
|
import { MsgExecuteContract } from "@terra-money/terra.js";
|
||||||
import {
|
import {
|
||||||
ConnectedWallet,
|
ConnectedWallet,
|
||||||
useConnectedWallet,
|
useConnectedWallet,
|
||||||
} from "@terra-money/wallet-provider";
|
} from "@terra-money/wallet-provider";
|
||||||
import { Signer } from "ethers";
|
import { Signer } from "ethers";
|
||||||
import { arrayify, parseUnits, zeroPad } from "ethers/lib/utils";
|
import { parseUnits, zeroPad } from "ethers/lib/utils";
|
||||||
import { useSnackbar } from "notistack";
|
import { useSnackbar } from "notistack";
|
||||||
import { useCallback, useEffect, useMemo, useRef } from "react";
|
import { useCallback, useMemo } from "react";
|
||||||
import { useDispatch, useSelector } from "react-redux";
|
import { useDispatch, useSelector } from "react-redux";
|
||||||
import { useEthereumProvider } from "../contexts/EthereumProviderContext";
|
import { useEthereumProvider } from "../contexts/EthereumProviderContext";
|
||||||
import { useSolanaWallet } from "../contexts/SolanaWalletContext";
|
import { useSolanaWallet } from "../contexts/SolanaWalletContext";
|
||||||
|
@ -40,9 +35,7 @@ import {
|
||||||
selectTransferSourceAsset,
|
selectTransferSourceAsset,
|
||||||
selectTransferSourceChain,
|
selectTransferSourceChain,
|
||||||
selectTransferSourceParsedTokenAccount,
|
selectTransferSourceParsedTokenAccount,
|
||||||
selectTransferTargetAsset,
|
|
||||||
selectTransferTargetChain,
|
selectTransferTargetChain,
|
||||||
selectTransferTargetParsedTokenAccount,
|
|
||||||
} from "../store/selectors";
|
} from "../store/selectors";
|
||||||
import { setIsSending, setSignedVAAHex } from "../store/transferSlice";
|
import { setIsSending, setSignedVAAHex } from "../store/transferSlice";
|
||||||
import { hexToUint8Array, uint8ArrayToHex } from "../utils/array";
|
import { hexToUint8Array, uint8ArrayToHex } from "../utils/array";
|
||||||
|
@ -56,6 +49,7 @@ import {
|
||||||
} from "../utils/consts";
|
} from "../utils/consts";
|
||||||
import { getSignedVAAWithRetry } from "../utils/getSignedVAAWithRetry";
|
import { getSignedVAAWithRetry } from "../utils/getSignedVAAWithRetry";
|
||||||
import { signSendAndConfirm } from "../utils/solana";
|
import { signSendAndConfirm } from "../utils/solana";
|
||||||
|
import useTransferTargetAddressHex from "./useTransferTargetAddress";
|
||||||
|
|
||||||
async function eth(
|
async function eth(
|
||||||
dispatch: any,
|
dispatch: any,
|
||||||
|
@ -104,8 +98,8 @@ async function solana(
|
||||||
mintAddress: string,
|
mintAddress: string,
|
||||||
amount: string,
|
amount: string,
|
||||||
decimals: number,
|
decimals: number,
|
||||||
targetAddressStr: string,
|
|
||||||
targetChain: ChainId,
|
targetChain: ChainId,
|
||||||
|
targetAddress: Uint8Array,
|
||||||
originAddressStr?: string,
|
originAddressStr?: string,
|
||||||
originChain?: ChainId
|
originChain?: ChainId
|
||||||
) {
|
) {
|
||||||
|
@ -114,7 +108,6 @@ async function solana(
|
||||||
//TODO: check if token attestation exists on the target chain
|
//TODO: check if token attestation exists on the target chain
|
||||||
// TODO: share connection in context?
|
// TODO: share connection in context?
|
||||||
const connection = new Connection(SOLANA_HOST, "confirmed");
|
const connection = new Connection(SOLANA_HOST, "confirmed");
|
||||||
const targetAddress = zeroPad(arrayify(targetAddressStr), 32);
|
|
||||||
const amountParsed = parseUnits(amount, decimals).toBigInt();
|
const amountParsed = parseUnits(amount, decimals).toBigInt();
|
||||||
const originAddress = originAddressStr
|
const originAddress = originAddressStr
|
||||||
? zeroPad(hexToUint8Array(originAddressStr), 32)
|
? zeroPad(hexToUint8Array(originAddressStr), 32)
|
||||||
|
@ -164,8 +157,8 @@ async function terra(
|
||||||
wallet: ConnectedWallet,
|
wallet: ConnectedWallet,
|
||||||
asset: string,
|
asset: string,
|
||||||
amount: string,
|
amount: string,
|
||||||
targetAddressStr: string,
|
targetChain: ChainId,
|
||||||
targetChain: ChainId
|
targetAddress: Uint8Array
|
||||||
) {
|
) {
|
||||||
dispatch(setIsSending(true));
|
dispatch(setIsSending(true));
|
||||||
try {
|
try {
|
||||||
|
@ -180,7 +173,7 @@ async function terra(
|
||||||
asset: asset,
|
asset: asset,
|
||||||
amount: amount,
|
amount: amount,
|
||||||
recipient_chain: targetChain,
|
recipient_chain: targetChain,
|
||||||
recipient: targetAddressStr,
|
recipient: targetAddress,
|
||||||
fee: 1000,
|
fee: 1000,
|
||||||
nonce: 0,
|
nonce: 0,
|
||||||
},
|
},
|
||||||
|
@ -221,11 +214,11 @@ export function useHandleTransfer() {
|
||||||
const originAsset = useSelector(selectTransferOriginAsset);
|
const originAsset = useSelector(selectTransferOriginAsset);
|
||||||
const amount = useSelector(selectTransferAmount);
|
const amount = useSelector(selectTransferAmount);
|
||||||
const targetChain = useSelector(selectTransferTargetChain);
|
const targetChain = useSelector(selectTransferTargetChain);
|
||||||
const targetAsset = useSelector(selectTransferTargetAsset);
|
const targetAddress = useTransferTargetAddressHex();
|
||||||
const isTargetComplete = useSelector(selectTransferIsTargetComplete);
|
const isTargetComplete = useSelector(selectTransferIsTargetComplete);
|
||||||
const isSending = useSelector(selectTransferIsSending);
|
const isSending = useSelector(selectTransferIsSending);
|
||||||
const isSendComplete = useSelector(selectTransferIsSendComplete);
|
const isSendComplete = useSelector(selectTransferIsSendComplete);
|
||||||
const { signer, signerAddress } = useEthereumProvider();
|
const { signer } = useEthereumProvider();
|
||||||
const solanaWallet = useSolanaWallet();
|
const solanaWallet = useSolanaWallet();
|
||||||
const solPK = solanaWallet?.publicKey;
|
const solPK = solanaWallet?.publicKey;
|
||||||
const terraWallet = useConnectedWallet();
|
const terraWallet = useConnectedWallet();
|
||||||
|
@ -234,37 +227,7 @@ export function useHandleTransfer() {
|
||||||
);
|
);
|
||||||
const sourceTokenPublicKey = sourceParsedTokenAccount?.publicKey;
|
const sourceTokenPublicKey = sourceParsedTokenAccount?.publicKey;
|
||||||
const decimals = sourceParsedTokenAccount?.decimals;
|
const decimals = sourceParsedTokenAccount?.decimals;
|
||||||
const targetParsedTokenAccount = useSelector(
|
|
||||||
selectTransferTargetParsedTokenAccount
|
|
||||||
);
|
|
||||||
const disabled = !isTargetComplete || isSending || isSendComplete;
|
const disabled = !isTargetComplete || isSending || isSendComplete;
|
||||||
// TODO: we probably shouldn't get here if we don't have this public key
|
|
||||||
// TODO: also this is just for solana... send help(ers)
|
|
||||||
const targetTokenAccountPublicKey = targetParsedTokenAccount?.publicKey;
|
|
||||||
// TODO: AVOID THIS DANGEROUS CACOPHONY
|
|
||||||
const tpkRef = useRef<undefined | Uint8Array>(undefined);
|
|
||||||
useEffect(() => {
|
|
||||||
(async () => {
|
|
||||||
if (targetChain === CHAIN_ID_SOLANA) {
|
|
||||||
tpkRef.current = targetTokenAccountPublicKey
|
|
||||||
? zeroPad(new PublicKey(targetTokenAccountPublicKey).toBytes(), 32) // use the target's TokenAccount if it exists
|
|
||||||
: solPK && targetAsset // otherwise, use the associated token account (which we create in the case it doesn't exist)
|
|
||||||
? zeroPad(
|
|
||||||
(
|
|
||||||
await Token.getAssociatedTokenAddress(
|
|
||||||
ASSOCIATED_TOKEN_PROGRAM_ID,
|
|
||||||
TOKEN_PROGRAM_ID,
|
|
||||||
new PublicKey(targetAsset),
|
|
||||||
solPK
|
|
||||||
)
|
|
||||||
).toBytes(),
|
|
||||||
32
|
|
||||||
)
|
|
||||||
: undefined;
|
|
||||||
} else tpkRef.current = undefined;
|
|
||||||
})();
|
|
||||||
}, [targetChain, solPK, targetAsset, targetTokenAccountPublicKey]);
|
|
||||||
// TODO: dynamically get "to" wallet
|
|
||||||
const handleTransferClick = useCallback(() => {
|
const handleTransferClick = useCallback(() => {
|
||||||
// TODO: we should separate state for transaction vs fetching vaa
|
// TODO: we should separate state for transaction vs fetching vaa
|
||||||
// TODO: more generic way of calling these
|
// TODO: more generic way of calling these
|
||||||
|
@ -272,7 +235,7 @@ export function useHandleTransfer() {
|
||||||
sourceChain === CHAIN_ID_ETH &&
|
sourceChain === CHAIN_ID_ETH &&
|
||||||
!!signer &&
|
!!signer &&
|
||||||
decimals !== undefined &&
|
decimals !== undefined &&
|
||||||
!!tpkRef.current
|
!!targetAddress
|
||||||
) {
|
) {
|
||||||
eth(
|
eth(
|
||||||
dispatch,
|
dispatch,
|
||||||
|
@ -282,14 +245,14 @@ export function useHandleTransfer() {
|
||||||
decimals,
|
decimals,
|
||||||
amount,
|
amount,
|
||||||
targetChain,
|
targetChain,
|
||||||
tpkRef.current
|
targetAddress
|
||||||
);
|
);
|
||||||
} else if (
|
} else if (
|
||||||
sourceChain === CHAIN_ID_SOLANA &&
|
sourceChain === CHAIN_ID_SOLANA &&
|
||||||
!!solanaWallet &&
|
!!solanaWallet &&
|
||||||
!!solPK &&
|
!!solPK &&
|
||||||
!!sourceTokenPublicKey &&
|
!!sourceTokenPublicKey &&
|
||||||
!!signerAddress &&
|
!!targetAddress &&
|
||||||
decimals !== undefined
|
decimals !== undefined
|
||||||
) {
|
) {
|
||||||
solana(
|
solana(
|
||||||
|
@ -299,10 +262,10 @@ export function useHandleTransfer() {
|
||||||
solPK.toString(),
|
solPK.toString(),
|
||||||
sourceTokenPublicKey,
|
sourceTokenPublicKey,
|
||||||
sourceAsset,
|
sourceAsset,
|
||||||
amount, //TODO: avoid decimals, pass in parsed amount
|
amount,
|
||||||
decimals,
|
decimals,
|
||||||
signerAddress,
|
|
||||||
targetChain,
|
targetChain,
|
||||||
|
targetAddress,
|
||||||
originAsset,
|
originAsset,
|
||||||
originChain
|
originChain
|
||||||
);
|
);
|
||||||
|
@ -310,7 +273,7 @@ export function useHandleTransfer() {
|
||||||
sourceChain === CHAIN_ID_TERRA &&
|
sourceChain === CHAIN_ID_TERRA &&
|
||||||
!!terraWallet &&
|
!!terraWallet &&
|
||||||
decimals !== undefined &&
|
decimals !== undefined &&
|
||||||
!!signerAddress
|
!!targetAddress
|
||||||
) {
|
) {
|
||||||
terra(
|
terra(
|
||||||
dispatch,
|
dispatch,
|
||||||
|
@ -318,8 +281,8 @@ export function useHandleTransfer() {
|
||||||
terraWallet,
|
terraWallet,
|
||||||
sourceAsset,
|
sourceAsset,
|
||||||
amount,
|
amount,
|
||||||
signerAddress, // TODO: only works for Eth
|
targetChain,
|
||||||
targetChain
|
targetAddress
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
// enqueueSnackbar("Transfers from this chain are not yet supported", {
|
// enqueueSnackbar("Transfers from this chain are not yet supported", {
|
||||||
|
@ -331,7 +294,6 @@ export function useHandleTransfer() {
|
||||||
enqueueSnackbar,
|
enqueueSnackbar,
|
||||||
sourceChain,
|
sourceChain,
|
||||||
signer,
|
signer,
|
||||||
signerAddress,
|
|
||||||
solanaWallet,
|
solanaWallet,
|
||||||
solPK,
|
solPK,
|
||||||
terraWallet,
|
terraWallet,
|
||||||
|
@ -340,6 +302,7 @@ export function useHandleTransfer() {
|
||||||
amount,
|
amount,
|
||||||
decimals,
|
decimals,
|
||||||
targetChain,
|
targetChain,
|
||||||
|
targetAddress,
|
||||||
originAsset,
|
originAsset,
|
||||||
originChain,
|
originChain,
|
||||||
]);
|
]);
|
||||||
|
|
|
@ -0,0 +1,110 @@
|
||||||
|
import {
|
||||||
|
CHAIN_ID_ETH,
|
||||||
|
CHAIN_ID_SOLANA,
|
||||||
|
CHAIN_ID_TERRA,
|
||||||
|
} from "@certusone/wormhole-sdk";
|
||||||
|
import { arrayify, zeroPad } from "@ethersproject/bytes";
|
||||||
|
import {
|
||||||
|
ASSOCIATED_TOKEN_PROGRAM_ID,
|
||||||
|
Token,
|
||||||
|
TOKEN_PROGRAM_ID,
|
||||||
|
} from "@solana/spl-token";
|
||||||
|
import { PublicKey } from "@solana/web3.js";
|
||||||
|
import { useConnectedWallet } from "@terra-money/wallet-provider";
|
||||||
|
import { useEffect } from "react";
|
||||||
|
import { useDispatch, useSelector } from "react-redux";
|
||||||
|
import { useEthereumProvider } from "../contexts/EthereumProviderContext";
|
||||||
|
import { useSolanaWallet } from "../contexts/SolanaWalletContext";
|
||||||
|
import {
|
||||||
|
selectTransferTargetAsset,
|
||||||
|
selectTransferTargetChain,
|
||||||
|
selectTransferTargetParsedTokenAccount,
|
||||||
|
} from "../store/selectors";
|
||||||
|
import { setTargetAddressHex } from "../store/transferSlice";
|
||||||
|
import { uint8ArrayToHex } from "../utils/array";
|
||||||
|
import bech32 from "bech32";
|
||||||
|
|
||||||
|
function useSyncTargetAddress(shouldFire: boolean) {
|
||||||
|
const dispatch = useDispatch();
|
||||||
|
const targetChain = useSelector(selectTransferTargetChain);
|
||||||
|
const { signerAddress } = useEthereumProvider();
|
||||||
|
const solanaWallet = useSolanaWallet();
|
||||||
|
const solPK = solanaWallet?.publicKey;
|
||||||
|
const targetAsset = useSelector(selectTransferTargetAsset);
|
||||||
|
const targetParsedTokenAccount = useSelector(
|
||||||
|
selectTransferTargetParsedTokenAccount
|
||||||
|
);
|
||||||
|
const targetTokenAccountPublicKey = targetParsedTokenAccount?.publicKey;
|
||||||
|
const terraWallet = useConnectedWallet();
|
||||||
|
useEffect(() => {
|
||||||
|
if (shouldFire) {
|
||||||
|
let cancelled = false;
|
||||||
|
if (targetChain === CHAIN_ID_ETH && signerAddress) {
|
||||||
|
dispatch(
|
||||||
|
setTargetAddressHex(
|
||||||
|
uint8ArrayToHex(zeroPad(arrayify(signerAddress), 32))
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
// TODO: have the user explicitly select an account on solana
|
||||||
|
else if (targetChain === CHAIN_ID_SOLANA && targetTokenAccountPublicKey) {
|
||||||
|
// use the target's TokenAccount if it exists
|
||||||
|
dispatch(
|
||||||
|
setTargetAddressHex(
|
||||||
|
uint8ArrayToHex(
|
||||||
|
zeroPad(new PublicKey(targetTokenAccountPublicKey).toBytes(), 32)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
} else if (targetChain === CHAIN_ID_SOLANA && solPK && targetAsset) {
|
||||||
|
// otherwise, use the associated token account (which we create in the case it doesn't exist)
|
||||||
|
(async () => {
|
||||||
|
const associatedTokenAccount = await Token.getAssociatedTokenAddress(
|
||||||
|
ASSOCIATED_TOKEN_PROGRAM_ID,
|
||||||
|
TOKEN_PROGRAM_ID,
|
||||||
|
new PublicKey(targetAsset),
|
||||||
|
solPK
|
||||||
|
);
|
||||||
|
if (!cancelled) {
|
||||||
|
dispatch(
|
||||||
|
setTargetAddressHex(
|
||||||
|
uint8ArrayToHex(zeroPad(associatedTokenAccount.toBytes(), 32))
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
} else if (
|
||||||
|
targetChain === CHAIN_ID_TERRA &&
|
||||||
|
terraWallet &&
|
||||||
|
terraWallet.walletAddress
|
||||||
|
) {
|
||||||
|
dispatch(
|
||||||
|
setTargetAddressHex(
|
||||||
|
uint8ArrayToHex(
|
||||||
|
zeroPad(
|
||||||
|
new Uint8Array(bech32.decode(terraWallet.walletAddress).words),
|
||||||
|
32
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
dispatch(setTargetAddressHex(undefined));
|
||||||
|
}
|
||||||
|
return () => {
|
||||||
|
cancelled = true;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}, [
|
||||||
|
dispatch,
|
||||||
|
shouldFire,
|
||||||
|
targetChain,
|
||||||
|
signerAddress,
|
||||||
|
solPK,
|
||||||
|
targetAsset,
|
||||||
|
targetTokenAccountPublicKey,
|
||||||
|
terraWallet,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default useSyncTargetAddress;
|
|
@ -0,0 +1,13 @@
|
||||||
|
import { useMemo } from "react";
|
||||||
|
import { useSelector } from "react-redux";
|
||||||
|
import { selectTransferTargetAddressHex } from "../store/selectors";
|
||||||
|
import { hexToUint8Array } from "../utils/array";
|
||||||
|
|
||||||
|
export default function useTransferTargetAddressHex() {
|
||||||
|
const targetAddressHex = useSelector(selectTransferTargetAddressHex);
|
||||||
|
const targetAddress = useMemo(
|
||||||
|
() => (targetAddressHex ? hexToUint8Array(targetAddressHex) : undefined),
|
||||||
|
[targetAddressHex]
|
||||||
|
);
|
||||||
|
return targetAddress;
|
||||||
|
}
|
|
@ -57,6 +57,8 @@ export const selectTransferSourceBalanceString = (state: RootState) =>
|
||||||
export const selectTransferAmount = (state: RootState) => state.transfer.amount;
|
export const selectTransferAmount = (state: RootState) => state.transfer.amount;
|
||||||
export const selectTransferTargetChain = (state: RootState) =>
|
export const selectTransferTargetChain = (state: RootState) =>
|
||||||
state.transfer.targetChain;
|
state.transfer.targetChain;
|
||||||
|
export const selectTransferTargetAddressHex = (state: RootState) =>
|
||||||
|
state.transfer.targetAddressHex;
|
||||||
export const selectTransferTargetAsset = (state: RootState) =>
|
export const selectTransferTargetAsset = (state: RootState) =>
|
||||||
state.transfer.targetAsset;
|
state.transfer.targetAsset;
|
||||||
export const selectTransferTargetParsedTokenAccount = (state: RootState) =>
|
export const selectTransferTargetParsedTokenAccount = (state: RootState) =>
|
||||||
|
@ -96,11 +98,8 @@ export const selectTransferIsTargetComplete = (state: RootState) =>
|
||||||
!!state.transfer.targetChain &&
|
!!state.transfer.targetChain &&
|
||||||
!!state.transfer.targetAsset &&
|
!!state.transfer.targetAsset &&
|
||||||
(state.transfer.targetChain !== CHAIN_ID_ETH ||
|
(state.transfer.targetChain !== CHAIN_ID_ETH ||
|
||||||
state.transfer.targetAsset !== ethers.constants.AddressZero); //&&
|
state.transfer.targetAsset !== ethers.constants.AddressZero) &&
|
||||||
// Associated Token Account exists
|
!!state.transfer.targetAddressHex;
|
||||||
// (state.transfer.targetChain !== CHAIN_ID_SOLANA ||
|
|
||||||
// (!!state.transfer.targetParsedTokenAccount &&
|
|
||||||
// !!state.transfer.targetParsedTokenAccount.publicKey));
|
|
||||||
export const selectTransferIsSendComplete = (state: RootState) =>
|
export const selectTransferIsSendComplete = (state: RootState) =>
|
||||||
!!selectTransferSignedVAAHex(state);
|
!!selectTransferSignedVAAHex(state);
|
||||||
export const selectTransferShouldLockFields = (state: RootState) =>
|
export const selectTransferShouldLockFields = (state: RootState) =>
|
||||||
|
|
|
@ -34,6 +34,7 @@ export interface TransferState {
|
||||||
sourceParsedTokenAccount: ParsedTokenAccount | undefined;
|
sourceParsedTokenAccount: ParsedTokenAccount | undefined;
|
||||||
amount: string;
|
amount: string;
|
||||||
targetChain: ChainId;
|
targetChain: ChainId;
|
||||||
|
targetAddressHex: string | undefined;
|
||||||
targetAsset: string | null | undefined;
|
targetAsset: string | null | undefined;
|
||||||
targetParsedTokenAccount: ParsedTokenAccount | undefined;
|
targetParsedTokenAccount: ParsedTokenAccount | undefined;
|
||||||
signedVAAHex: string | undefined;
|
signedVAAHex: string | undefined;
|
||||||
|
@ -51,6 +52,7 @@ const initialState: TransferState = {
|
||||||
originAsset: undefined,
|
originAsset: undefined,
|
||||||
amount: "",
|
amount: "",
|
||||||
targetChain: CHAIN_ID_ETH,
|
targetChain: CHAIN_ID_ETH,
|
||||||
|
targetAddressHex: undefined,
|
||||||
targetAsset: undefined,
|
targetAsset: undefined,
|
||||||
targetParsedTokenAccount: undefined,
|
targetParsedTokenAccount: undefined,
|
||||||
signedVAAHex: undefined,
|
signedVAAHex: undefined,
|
||||||
|
@ -86,6 +88,7 @@ export const transferSlice = createSlice({
|
||||||
}
|
}
|
||||||
if (state.targetChain === action.payload) {
|
if (state.targetChain === action.payload) {
|
||||||
state.targetChain = prevSourceChain;
|
state.targetChain = prevSourceChain;
|
||||||
|
state.targetAddressHex = undefined;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
setSourceAsset: (state, action: PayloadAction<string>) => {
|
setSourceAsset: (state, action: PayloadAction<string>) => {
|
||||||
|
@ -117,6 +120,8 @@ export const transferSlice = createSlice({
|
||||||
setTargetChain: (state, action: PayloadAction<ChainId>) => {
|
setTargetChain: (state, action: PayloadAction<ChainId>) => {
|
||||||
const prevTargetChain = state.targetChain;
|
const prevTargetChain = state.targetChain;
|
||||||
state.targetChain = action.payload;
|
state.targetChain = action.payload;
|
||||||
|
state.targetAddressHex = undefined;
|
||||||
|
// targetAsset is handled by useFetchTargetAsset
|
||||||
if (state.sourceChain === action.payload) {
|
if (state.sourceChain === action.payload) {
|
||||||
state.sourceChain = prevTargetChain;
|
state.sourceChain = prevTargetChain;
|
||||||
state.activeStep = 0;
|
state.activeStep = 0;
|
||||||
|
@ -132,6 +137,9 @@ export const transferSlice = createSlice({
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
setTargetAddressHex: (state, action: PayloadAction<string | undefined>) => {
|
||||||
|
state.targetAddressHex = action.payload;
|
||||||
|
},
|
||||||
setTargetAsset: (
|
setTargetAsset: (
|
||||||
state,
|
state,
|
||||||
action: PayloadAction<string | null | undefined>
|
action: PayloadAction<string | null | undefined>
|
||||||
|
@ -169,6 +177,7 @@ export const {
|
||||||
setSourceParsedTokenAccount,
|
setSourceParsedTokenAccount,
|
||||||
setAmount,
|
setAmount,
|
||||||
setTargetChain,
|
setTargetChain,
|
||||||
|
setTargetAddressHex,
|
||||||
setTargetAsset,
|
setTargetAsset,
|
||||||
setTargetParsedTokenAccount,
|
setTargetParsedTokenAccount,
|
||||||
setSignedVAAHex,
|
setSignedVAAHex,
|
||||||
|
|
Loading…
Reference in New Issue