Răsfoiți Sursa

Web page to publish message to ETH

Change-Id: Ia775175c5134c949ec1630ea3ad5a254275fe570
Justin Schuldt 4 ani în urmă
părinte
comite
3fd60e822a
4 a modificat fișierele cu 115 adăugiri și 6 ștergeri
  1. 4 1
      web/package.json
  2. 7 2
      web/src/App/App.tsx
  3. 3 3
      web/src/config.ts
  4. 101 0
      web/src/pages/Message.tsx

+ 4 - 1
web/package.json

@@ -44,7 +44,10 @@
     "eject": "react-scripts eject",
     "ethers": "typechain --target ethers-v4 --outDir src/contracts 'contracts/*.json'",
     "deploy": "gh-pages -d build",
-    "deploy:ar": "arweave deploy-dir build --key-file "
+    "deploy:ar": "arweave deploy-dir build --key-file ",
+    "rm-contracts": "rm -rf src/contracts && rm -rf contracts",
+    "import-contracts": "mkdir -p ./contracts && cp -r ../ethereum/build/contracts/* ./contracts/ && npm run ethers",
+    "refresh-contracts": "npm run rm-contracts && npm run import-contracts"
   },
   "eslintConfig": {
     "extends": "react-app"

+ 7 - 2
web/src/App/App.tsx

@@ -12,6 +12,7 @@ import WalletContext from '../providers/WalletContext';
 import Wallet from "@project-serum/sol-wallet-adapter";
 import {BridgeProvider} from "../providers/BridgeContext";
 import Assistant from "../pages/Assistant";
+import Message from "../pages/Message";
 import {SOLANA_HOST} from "../config";
 
 const {Header, Content, Footer} = Layout;
@@ -39,7 +40,8 @@ function App() {
             <Layout style={{height: '100%'}}>
                 <HashRouter basename={"/"}>
                     <Header style={{position: 'fixed', zIndex: 1, width: '100%'}}>
-                        <Link to="/" style={{paddingRight: 20}}>Assistant</Link>
+                        <Link to="/" style={{paddingRight: 20}}>Message</Link>
+                        <Link to="/assistant" style={{paddingRight: 20}}>Assistant</Link>
                         <Link to="/eth" style={{paddingRight: 20}}>Ethereum</Link>
                         <Link to="/solana">Solana</Link>
                         {
@@ -63,7 +65,7 @@ function App() {
                                             <BridgeProvider>
                                                 <SolanaTokenProvider>
                                                     <Switch>
-                                                        <Route path="/">
+                                                        <Route path="/assistant">
                                                             <Assistant/>
                                                         </Route>
                                                         <Route path="/solana">
@@ -72,6 +74,9 @@ function App() {
                                                         <Route path="/eth">
                                                             <Transfer/>
                                                         </Route>
+                                                        <Route path="/">
+                                                            <Message/>
+                                                        </Route>
                                                     </Switch>
                                                 </SolanaTokenProvider>
                                             </BridgeProvider>

+ 3 - 3
web/src/config.ts

@@ -1,13 +1,13 @@
 import {PublicKey} from "@solana/web3.js";
 
-const BRIDGE_ADDRESS = "0xf92cD566Ea4864356C5491c177A430C222d7e678";
+const BRIDGE_ADDRESS = "0x254dffcd3277c0b1660f6d42efbb754edababc2b";
 const WRAPPED_MASTER = "9A5e27995309a03f8B583feBdE7eF289FcCdC6Ae"
 
 
-const SOLANA_BRIDGE_PROGRAM = new PublicKey("WormT3McKhFJ2RkiGpdw9GKvNCrB2aB54gb2uV9MfQC");
+const SOLANA_BRIDGE_PROGRAM = new PublicKey("Bridge1p5gheXUvJ6jGWGeCsgPKgnE3YgdGKRVCMY9o");
 const TOKEN_PROGRAM = new PublicKey("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA");
 
-const SOLANA_HOST = "https://solana-api.projectserum.com";
+const SOLANA_HOST = "http://localhost:8899";
 
 export {
     BRIDGE_ADDRESS,

+ 101 - 0
web/src/pages/Message.tsx

@@ -0,0 +1,101 @@
+import React, { useState, useEffect } from 'react';
+import { Form, Input, Button, List } from 'antd';
+import { ethers } from "ethers";
+import { BRIDGE_ADDRESS } from "../config";
+import { ImplementationFactory } from '../contracts/ImplementationFactory';
+
+// @ts-ignore
+if (window.ethereum === undefined) {
+    alert("Please install the MetaMask extension before using this experimental demo web UI");
+}
+
+// @ts-ignore
+window.ethereum.enable();
+// @ts-ignore
+const provider = new ethers.providers.Web3Provider(window.ethereum);
+const signer = provider.getSigner();
+
+function Message() {
+    const [form] = Form.useForm();
+    const [, forceUpdate] = useState({});
+
+    // map: { txHash: payloadString }
+    const [txHashToPayload, setTxHashToPayload] = useState<{ [txHash: string]: string }>({})
+
+    // To disable submit button at the beginning.
+    useEffect(() => {
+        forceUpdate({});
+    }, []);
+
+    const sendMessage = async ({ payload }: { payload: string }) => {
+
+        let nonceConst = Math.random() * 100000
+        let nonceBuffer = Buffer.alloc(4);
+        nonceBuffer.writeUInt32LE(nonceConst, 0)
+
+        let i = ImplementationFactory.connect(BRIDGE_ADDRESS, signer)
+
+        let res = await i.publishMessage(nonceBuffer, Buffer.from(payload, 'utf16le'), true)
+
+        await res.wait(1)
+
+        if (res.hash) {
+            setTxHashToPayload({ ...txHashToPayload, [res.hash]: payload })
+        }
+
+        form.resetFields(['payload'])
+    }
+    const rmTxHash = (txHash: string) => {
+        const { [txHash]: rm, ...others } = txHashToPayload
+        setTxHashToPayload(others)
+        return undefined  // for typescript
+    }
+
+    return (
+        <>
+            <Form form={form} name="publish_message" layout="inline" onFinish={sendMessage}>
+                <Form.Item>
+                    <h1><code>publishMessage</code></h1>
+                </Form.Item>
+                <Form.Item
+                    name="payload"
+                    rules={[{ required: true, message: 'Please enter a payload for the message.' }]}
+                >
+                    <Input.TextArea placeholder="Payload to write to ETH" />
+                </Form.Item>
+                <Form.Item shouldUpdate>
+                    {() => (
+                        <Button
+                            type="primary"
+                            htmlType="submit"
+                            disabled={
+                                !form.isFieldsTouched(true) ||
+                                !!form.getFieldsError().filter(({ errors }) => errors.length).length
+                            }
+                        >
+                            Send to MetaMask
+                        </Button>
+                    )}
+                </Form.Item>
+            </Form>
+            {Object.keys(txHashToPayload).length >= 1 ? (
+                <List
+                    dataSource={Object.keys(txHashToPayload)}
+                    renderItem={item => (
+                        <List.Item
+                            actions={[<a onClick={() => rmTxHash(item)} >X</a>]}
+                        >
+                            <div style={{ display: 'flex', justifyContent: 'space-between', width: '100%' }}>
+                                <h4><code>{item}</code></h4>
+                                <h4><code><pre>{txHashToPayload[item]}</pre></code></h4>
+                            </div>
+                        </List.Item>
+                    )}
+                />
+
+            ) : null}
+        </>
+    );
+}
+
+export default Message;