use sollet

This commit is contained in:
Hendrik Hofstadt 2021-01-18 20:32:44 +01:00
parent f4a7e705c9
commit ad9e8cc45b
12 changed files with 1508 additions and 952 deletions

2293
web/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -3,9 +3,9 @@
"version": "0.1.0",
"private": true,
"dependencies": {
"@project-serum/sol-wallet-adapter": "^0.1.1",
"@project-serum/sol-wallet-adapter": "^0.1.4",
"@solana/spl-token": "^0.0.11",
"@solana/web3.js": "^0.87.1",
"@solana/web3.js": "^0.90.0",
"@testing-library/jest-dom": "^4.2.4",
"@testing-library/react": "^9.3.2",
"@testing-library/user-event": "^7.1.2",

View File

@ -3,7 +3,7 @@ import './App.css';
import * as solanaWeb3 from '@solana/web3.js';
import ClientContext from '../providers/ClientContext';
import Transfer from "../pages/Transfer";
import {Layout} from 'antd';
import {Empty, Layout} from 'antd';
import {SolanaTokenProvider} from "../providers/SolanaTokenContext";
import {SlotProvider} from "../providers/SlotContext";
import {BrowserRouter as Router, Link, Route, Switch} from 'react-router-dom';
@ -19,7 +19,7 @@ const {Header, Content, Footer} = Layout;
function App() {
let c = new solanaWeb3.Connection(SOLANA_HOST);
const wallet = useMemo(() => new Wallet("https://www.sollet.io", SOLANA_HOST), []);
const [, setConnected] = useState(false);
const [connected, setConnected] = useState(false);
useEffect(() => {
wallet.on('connect', () => {
setConnected(true);
@ -42,32 +42,46 @@ function App() {
<Link to="/assistant" style={{paddingRight: 20}}>Assistant</Link>
<Link to="/" style={{paddingRight: 20}}>Ethereum</Link>
<Link to="/solana">Solana</Link>
<div className="logo"/>
{
connected ? (<a style={{float: "right"}}>
Connected as {wallet.publicKey.toString()}
</a>) : (<a style={{float: "right"}} onClick={() => {
if (!connected) {
wallet.connect()
}
}
}>Connect</a>)
}
</Header>
<Content style={{padding: '0 50px', marginTop: 64}}>
<div style={{padding: 24}}>
<ClientContext.Provider value={c}>
<SlotProvider>
<WalletContext.Provider value={wallet}>
<BridgeProvider>
<SolanaTokenProvider>
{
connected?( <ClientContext.Provider value={c}>
<SlotProvider>
<WalletContext.Provider value={wallet}>
<BridgeProvider>
<SolanaTokenProvider>
<Switch>
<Route path="/assistant">
<Assistant/>
</Route>
<Route path="/solana">
<TransferSolana/>
</Route>
<Route path="/">
<Transfer/>
</Route>
</Switch>
</SolanaTokenProvider>
</BridgeProvider>
</WalletContext.Provider>
</SlotProvider>
</ClientContext.Provider>):(
<Empty description={"Please connect your wallet"}/>
)
}
<Switch>
<Route path="/assistant">
<Assistant/>
</Route>
<Route path="/solana">
<TransferSolana/>
</Route>
<Route path="/">
<Transfer/>
</Route>
</Switch>
</SolanaTokenProvider>
</BridgeProvider>
</WalletContext.Provider>
</SlotProvider>
</ClientContext.Provider>
</div>
</Content>
<Footer style={{textAlign: 'center'}}>nexantic GmbH 2020</Footer>

View File

@ -14,8 +14,9 @@ import debounce from "lodash.debounce"
import BN from "bignumber.js";
import {BigNumber} from "ethers/utils";
import {AssetMeta, SolanaBridge} from "../utils/bridge";
import KeyContext from "../providers/KeyContext";
import {ChainID} from "../pages/Assistant";
import WalletContext from "../providers/WalletContext";
import Wallet from "@project-serum/sol-wallet-adapter";
const {confirm} = Modal;
@ -64,7 +65,7 @@ export const defaultCoinInfo = {
let debounceUpdater = debounce((e) => e(), 500)
async function createWrapped(c: Connection, b: SolanaBridge, key: Account, meta: AssetMeta, mint: PublicKey) {
async function createWrapped(c: Connection, b: SolanaBridge, wallet: Wallet, meta: AssetMeta, mint: PublicKey) {
try {
let tx = new Transaction();
@ -73,9 +74,10 @@ async function createWrapped(c: Connection, b: SolanaBridge, key: Account, meta:
let recentHash = await c.getRecentBlockhash();
tx.recentBlockhash = recentHash.blockhash
tx.add(...ix_account)
tx.sign(key, newSigner)
tx.feePayer = wallet.publicKey;
let signed = await wallet.signTransaction(tx);
message.loading({content: "Waiting for transaction to be confirmed...", key: "tx", duration: 1000})
await c.sendTransaction(tx, [key, newSigner], {preflightCommitment: "single"})
await c.sendRawTransaction(signed.serialize(), {preflightCommitment: "single"})
message.success({content: "Creation succeeded!", key: "tx"})
} catch (e) {
console.log(e)
@ -88,7 +90,7 @@ export default function TransferInitiator(params: TransferInitiatorParams) {
let slot = useContext(SlotContext);
let b = useContext(SolanaTokenContext);
let bridge = useContext(BridgeContext);
let k = useContext(KeyContext);
let wallet = useContext(WalletContext);
let [fromNetwork, setFromNetwork] = useState(ChainID.ETH);
let [toNetwork, setToNetwork] = useState(ChainID.SOLANA);
@ -110,7 +112,6 @@ export default function TransferInitiator(params: TransferInitiatorParams) {
setCoinInfo(defaultCoinInfo);
return
}
console.log(acc.assetMeta)
setCoinInfo({
address: fromAddress,
@ -207,7 +208,7 @@ export default function TransferInitiator(params: TransferInitiatorParams) {
<Input.Group compact={true}>
<Select style={{width: '30%'}} defaultValue={ChainID.ETH} className="select-before"
value={fromNetwork}
onChange={(v) => {
onChange={(v: ChainID) => {
setFromNetwork(v);
setFromAddress("");
if (v === toNetwork) {
@ -252,7 +253,7 @@ export default function TransferInitiator(params: TransferInitiatorParams) {
<Input.Group compact={true}>
<Select style={{width: '30%'}} defaultValue={ChainID.SOLANA} className="select-before"
value={toNetwork}
onChange={(v) => {
onChange={(v: ChainID) => {
setToNetwork(v)
if (v === fromNetwork) {
setFromNetwork(v == ChainID.ETH ? ChainID.SOLANA : ChainID.ETH);
@ -282,7 +283,7 @@ export default function TransferInitiator(params: TransferInitiatorParams) {
content: (<>This will create a new token account for the
token: <code>{wrappedMint}</code></>),
onOk() {
createWrapped(c, bridge, k, {
createWrapped(c, bridge, wallet, {
chain: coinInfo.chainID,
address: coinInfo.assetAddress,
decimals: Math.min(coinInfo.decimals, 9)

View File

@ -10,8 +10,8 @@ import {BRIDGE_ADDRESS} from "../config";
import {keccak256} from "ethers/utils";
import BN from 'bn.js';
import {PublicKey, Transaction} from "@solana/web3.js";
import KeyContext from "../providers/KeyContext";
import ClientContext from "../providers/ClientContext";
import WalletContext from "../providers/WalletContext";
// @ts-ignore
if (window.ethereum === undefined) {
@ -39,7 +39,7 @@ function TransferProposals() {
let t = useContext(SolanaTokenContext);
let tokens = useContext(SolanaTokenContext);
let b = useContext(BridgeContext);
let k = useContext(KeyContext);
let wallet = useContext(WalletContext);
let c = useContext(ClientContext);
let [lockups, setLockups] = useState<LockupWithStatus[]>([])
@ -120,9 +120,10 @@ function TransferProposals() {
let tx = new Transaction();
tx.recentBlockhash = recentHash.blockhash
tx.add(ix)
tx.sign(k)
tx.feePayer = wallet.publicKey;
let signed = await wallet.signTransaction(tx);
try {
await c.sendTransaction(tx, [k])
await c.sendRawTransaction(signed.serialize())
message.success({content: "Poke succeeded", key: "poke"})
} catch (e) {
message.error({content: "Poke failed", key: "poke"})

View File

@ -10,11 +10,11 @@ import {WormholeFactory} from "../contracts/WormholeFactory";
import {BRIDGE_ADDRESS, TOKEN_PROGRAM} from "../config";
import {SolanaTokenContext} from "../providers/SolanaTokenContext";
import {BridgeContext} from "../providers/BridgeContext";
import KeyContext from "../providers/KeyContext";
import TransferInitiator, {defaultCoinInfo, TransferInitiatorData} from "../components/TransferInitiator";
import * as spl from "@solana/spl-token";
import BN from "bn.js"
import {SlotContext} from "../providers/SlotContext";
import WalletContext from "../providers/WalletContext";
// @ts-ignore
if (window.ethereum === undefined) {
@ -63,7 +63,7 @@ function Assistant() {
let c = useContext<solanaWeb3.Connection>(ClientContext);
let tokenAccounts = useContext(SolanaTokenContext);
let bridge = useContext(BridgeContext);
let k = useContext(KeyContext);
let wallet = useContext(WalletContext);
let slot = useContext(SlotContext);
let [fromNetwork, setFromNetwork] = useState(ChainID.ETH)
@ -87,7 +87,7 @@ function Assistant() {
loading: false
})
if (from == "approve") {
lockAssets(transferData.fromCoinInfo?.address, transferData.amount, transferData.toAddress, transferData.toNetwork)
lockAssets(transferData.fromCoinInfo.address, transferData.amount, transferData.toAddress, transferData.toNetwork)
} else if (from == "lock") {
// Await approvals or allow to submit guardian shit
if (fromNetwork == ChainID.ETH && transferData.toNetwork == ChainID.SOLANA) {
@ -164,9 +164,9 @@ function Assistant() {
if (fromNetwork == ChainID.ETH && transferData.fromCoinInfo) {
nextStep("init")
if (transferData.fromCoinInfo?.allowance.lt(transferData.amount)) {
approveAssets(transferData.fromCoinInfo?.address, transferData.amount)
approveAssets(transferData.fromCoinInfo.address, transferData.amount)
} else {
lockAssets(transferData.fromCoinInfo?.address, transferData.amount, transferData.toAddress, transferData.toNetwork)
lockAssets(transferData.fromCoinInfo.address, transferData.amount, transferData.toAddress, transferData.toNetwork)
}
} else if (fromNetwork == ChainID.SOLANA && transferData.fromCoinInfo) {
nextStep("init")
@ -183,7 +183,10 @@ function Assistant() {
message: "Locking tokens on Solana...",
})
let {ix: lock_ix, transferKey} = await bridge.createLockAssetInstruction(k.publicKey, new PublicKey(transferData.fromCoinInfo.address),
let {
ix: lock_ix,
transferKey
} = await bridge.createLockAssetInstruction(wallet.publicKey, new PublicKey(transferData.fromCoinInfo.address),
new PublicKey(transferData.fromCoinInfo.mint), new BN(transferData.amount.toString()),
transferData.toNetwork, transferData.toAddress,
{
@ -191,10 +194,10 @@ function Assistant() {
address: transferData.fromCoinInfo.assetAddress,
decimals: transferData.fromCoinInfo.decimals,
}, Math.random() * 100000);
let ix = spl.Token.createApproveInstruction(TOKEN_PROGRAM, new PublicKey(transferData.fromCoinInfo.address), await bridge.getConfigKey(), k.publicKey, [], transferData.amount.toNumber())
let ix = spl.Token.createApproveInstruction(TOKEN_PROGRAM, new PublicKey(transferData.fromCoinInfo.address), await bridge.getConfigKey(), wallet.publicKey, [], transferData.amount.toNumber())
let bridge_account = await bridge.getConfigKey();
let fee_ix = solanaWeb3.SystemProgram.transfer({
fromPubkey: k.publicKey,
fromPubkey: wallet.publicKey,
toPubkey: bridge_account,
lamports: await bridge.getTransferFee()
});
@ -204,9 +207,10 @@ function Assistant() {
tx.add(ix)
tx.add(fee_ix)
tx.add(lock_ix)
tx.sign(k)
tx.feePayer = wallet.publicKey;
let signed = await wallet.signTransaction(tx)
try {
await c.sendTransaction(tx, [k])
await c.sendRawTransaction(signed.serialize())
message.success({content: "Transfer succeeded", key: "transfer"})
} catch (e) {
message.error({content: "Transfer failed", key: "transfer"})

View File

@ -12,10 +12,11 @@ import {BRIDGE_ADDRESS} from "../config";
import {SolanaTokenContext} from "../providers/SolanaTokenContext";
import {BridgeContext} from "../providers/BridgeContext";
import {AssetMeta, SolanaBridge} from "../utils/bridge";
import KeyContext from "../providers/KeyContext";
import {FormInstance} from "antd/lib/form";
import SplBalances from "../components/SplBalances";
import TransferProposals from "../components/TransferProposals";
import WalletContext from "../providers/WalletContext";
import Wallet from "@project-serum/sol-wallet-adapter";
// @ts-ignore
if (window.ethereum === undefined) {
@ -59,7 +60,7 @@ async function approveAssets(asset: string,
}
}
async function createWrapped(c: Connection, b: SolanaBridge, key: Account, meta: AssetMeta, mint: PublicKey) {
async function createWrapped(c: Connection, b: SolanaBridge, wallet: Wallet, meta: AssetMeta, mint: PublicKey) {
try {
let tx = new Transaction();
@ -68,9 +69,11 @@ async function createWrapped(c: Connection, b: SolanaBridge, key: Account, meta:
let recentHash = await c.getRecentBlockhash();
tx.recentBlockhash = recentHash.blockhash
tx.add(...ix_account)
tx.sign(key, newSigner)
tx.sign(newSigner)
tx.feePayer = wallet.publicKey;
let signed = await wallet.signTransaction(tx);
message.loading({content: "Waiting for transaction to be confirmed...", key: "tx", duration: 1000})
await c.sendTransaction(tx, [key, newSigner])
await c.sendRawTransaction(signed.serialize())
message.success({content: "Creation succeeded!", key: "tx"})
} catch (e) {
console.log(e)
@ -82,7 +85,7 @@ function Transfer() {
let c = useContext<solanaWeb3.Connection>(ClientContext);
let tokenAccounts = useContext(SolanaTokenContext);
let bridge = useContext(BridgeContext);
let k = useContext(KeyContext);
let wallet = useContext(WalletContext);
let [coinInfo, setCoinInfo] = useState({
balance: new BigNumber(0),
@ -245,7 +248,7 @@ function Transfer() {
<Col><Button size={"small"}
disabled={wrappedMint === ""}
onClick={() => {
createWrapped(c, bridge, k, {
createWrapped(c, bridge, wallet, {
chain: coinInfo.chainID,
address: coinInfo.assetAddress,
decimals: Math.min(coinInfo.decimals, 9)

View File

@ -10,16 +10,16 @@ import {SlotContext} from "../providers/SlotContext";
import {SolanaTokenContext} from "../providers/SolanaTokenContext";
import {CHAIN_ID_SOLANA} from "../utils/bridge";
import {BridgeContext} from "../providers/BridgeContext";
import KeyContext from "../providers/KeyContext";
import BN from 'bn.js';
import {TOKEN_PROGRAM} from "../config";
import WalletContext from "../providers/WalletContext";
function TransferSolana() {
let c = useContext<solanaWeb3.Connection>(ClientContext);
let slot = useContext(SlotContext);
let b = useContext(SolanaTokenContext);
let bridge = useContext(BridgeContext);
let k = useContext(KeyContext);
let wallet = useContext(WalletContext);
let [coinInfo, setCoinInfo] = useState({
balance: new BigNumber(0),
@ -71,16 +71,16 @@ function TransferSolana() {
let send = async () => {
message.loading({content: "Transferring tokens...", key: "transfer"}, 1000)
let {ix: lock_ix} = await bridge.createLockAssetInstruction(k.publicKey, fromAccount, new PublicKey(coinInfo.mint), transferAmount, values["target_chain"], recipient,
let {ix: lock_ix} = await bridge.createLockAssetInstruction(wallet.publicKey, fromAccount, new PublicKey(coinInfo.mint), transferAmount, values["target_chain"], recipient,
{
chain: coinInfo.chainID,
address: coinInfo.wrappedAddress,
decimals: Math.min(coinInfo.decimals, 9)
}, Math.random() * 100000);
let ix = spl.Token.createApproveInstruction(TOKEN_PROGRAM, fromAccount, await bridge.getConfigKey(), k.publicKey, [], transferAmount.toNumber())
let ix = spl.Token.createApproveInstruction(TOKEN_PROGRAM, fromAccount, await bridge.getConfigKey(), wallet.publicKey, [], transferAmount.toNumber())
let bridge_account = await bridge.getConfigKey();
let fee_ix = solanaWeb3.SystemProgram.transfer({
fromPubkey: k.publicKey,
fromPubkey: wallet.publicKey,
toPubkey: bridge_account,
lamports: await bridge.getTransferFee()
});
@ -91,9 +91,10 @@ function TransferSolana() {
tx.add(ix)
tx.add(fee_ix)
tx.add(lock_ix)
tx.sign(k)
tx.feePayer = wallet.publicKey;
let signed = await wallet.signTransaction(tx)
try {
await c.sendTransaction(tx, [k])
await c.sendRawTransaction(signed.serialize())
message.success({content: "Transfer succeeded", key: "transfer"})
} catch (e) {
message.error({content: "Transfer failed", key: "transfer"})

View File

@ -1,7 +0,0 @@
import React from 'react'
import * as solanaWeb3 from '@solana/web3.js';
import {Account} from "@solana/web3.js";
const KeyContext = React.createContext<Account>(new Account([14,173,153,4,176,224,201,111,32,237,183,185,159,247,22,161,89,84,215,209,212,137,10,92,157,49,29,192,101,164,152,70,87,65,8,174,214,157,175,126,98,90,54,24,100,177,247,77,19,112,47,44,165,109,233,102,14,86,109,29,134,145,132,141]));
export default KeyContext

View File

@ -1,6 +1,5 @@
import React, {createContext, FunctionComponent, useContext, useEffect, useState} from "react"
import ClientContext from "../providers/ClientContext";
import KeyContext from "../providers/KeyContext";
import {AccountInfo, ParsedAccountData, PublicKey, RpcResponseAndContext} from "@solana/web3.js";
import {BigNumber} from "ethers/utils";
import {SlotContext} from "./SlotContext";
@ -9,6 +8,7 @@ import {BridgeContext} from "./BridgeContext";
import {message} from "antd";
import {AssetMeta} from "../utils/bridge";
import {Buffer} from "buffer";
import WalletContext from "./WalletContext";
export interface BalanceInfo {
mint: string,
@ -29,7 +29,7 @@ export const SolanaTokenContext = createContext<TokenInfo>({
})
export const SolanaTokenProvider: FunctionComponent = ({children}) => {
let k = useContext(KeyContext)
let wallet = useContext(WalletContext);
let c = useContext(ClientContext);
let b = useContext(BridgeContext);
let slot = useContext(SlotContext);
@ -47,7 +47,7 @@ export const SolanaTokenProvider: FunctionComponent = ({children}) => {
// @ts-ignore
setLoading(true)
let getAccounts = async () => {
let res: RpcResponseAndContext<Array<{ pubkey: PublicKey; account: AccountInfo<ParsedAccountData> }>> = await c.getParsedTokenAccountsByOwner(k.publicKey, {programId: TOKEN_PROGRAM}, "single")
let res: RpcResponseAndContext<Array<{ pubkey: PublicKey; account: AccountInfo<ParsedAccountData> }>> = await c.getParsedTokenAccountsByOwner(wallet.publicKey, {programId: TOKEN_PROGRAM}, "single")
let meta: AssetMeta[] = [];
for (let acc of res.value) {
let am = await b?.fetchAssetMeta(new PublicKey(acc.account.data.parsed.info.mint))

View File

@ -1,5 +1,6 @@
import React from 'react'
import Wallet from '@project-serum/sol-wallet-adapter'
import {SOLANA_HOST} from "../config";
const WalletContext = React.createContext<Wallet | undefined>(undefined);
const WalletContext = React.createContext<Wallet>(new Wallet("https://www.sollet.io", SOLANA_HOST));
export default WalletContext

3
web/src/sollet.d.ts vendored
View File

@ -1,6 +1,6 @@
declare module '@project-serum/sol-wallet-adapter' {
import EventEmitter = NodeJS.EventEmitter;
import {PublicKey} from "@solana/web3.js";
import {PublicKey, Transaction} from "@solana/web3.js";
export default class Wallet extends EventEmitter {
public publicKey: PublicKey;
@ -9,5 +9,6 @@ declare module '@project-serum/sol-wallet-adapter' {
async connect();
async disconnect();
async signTransaction(tx: Transaction): Promise<Transaction>;
}
}