diff --git a/index.html b/index.html
index bb65a66..5eab5a3 100644
--- a/index.html
+++ b/index.html
@@ -2,9 +2,10 @@
-
+
- Vite + React
+
+ NEAR Multi-Chain
diff --git a/package.json b/package.json
index e127dd3..52995e4 100644
--- a/package.json
+++ b/package.json
@@ -19,7 +19,9 @@
"@near-wallet-selector/my-near-wallet": "^8.9.5",
"axios": "^1.6.8",
"bitcoinjs-lib": "^6.1.5",
+ "bn.js": "^5.2.1",
"bs58check": "^3.0.1",
+ "elliptic": "^6.5.5",
"ethers": "^6.11.1",
"hash.js": "^1.1.7",
"keccak": "^3.0.4",
@@ -27,9 +29,13 @@
"prop-types": "^15.8.1",
"react": "^18.2.0",
"react-dom": "^18.2.0",
+ "rxjs": "^7.8.1",
"vite-plugin-node-polyfills": "^0.21.0",
"web3": "^4.6.0"
},
+ "overrides": {
+ "near-api-js": "^3.0.4"
+ },
"devDependencies": {
"@types/react": "^18.2.64",
"@types/react-dom": "^18.2.21",
@@ -40,4 +46,4 @@
"eslint-plugin-react-refresh": "^0.4.5",
"vite": "^5.1.6"
}
-}
+}
\ No newline at end of file
diff --git a/src/assets/logo-black.svg b/public/logo-black.svg
similarity index 100%
rename from src/assets/logo-black.svg
rename to public/logo-black.svg
diff --git a/public/vite.svg b/public/vite.svg
deleted file mode 100644
index e7b8dfb..0000000
--- a/public/vite.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/src/App.jsx b/src/App.jsx
index ee87bc9..e765b13 100644
--- a/src/App.jsx
+++ b/src/App.jsx
@@ -1,3 +1,5 @@
+import { NearContext } from './context';
+
import { useEffect, useState } from "react";
import Navbar from "./components/Navbar"
import { Wallet } from "./services/near-wallet";
@@ -11,29 +13,22 @@ const MPC_CONTRACT = 'multichain-testnet-2.testnet';
const wallet = new Wallet({ network: 'testnet', createAccessKeyFor: MPC_CONTRACT });
function App() {
- const [isSignedIn, setIsSignedIn] = useState(false);
+ const [signedAccountId, setSignedAccountId] = useState('');
const [status, setStatus] = useState("Please login to request a signature");
const [chain, setChain] = useState('eth');
- useEffect(() => {
- const initFunction = async () => {
- const isSignedIn = await wallet.startUp();
- setIsSignedIn(isSignedIn);
- }
-
- initFunction();
- }, []);
+ useEffect(() => { wallet.startUp(setSignedAccountId) }, []);
return (
- <>
-
+
+
🔗 NEAR Multi Chain
Safely control accounts on other chains through the NEAR MPC service. Learn more in the documentation.
- {isSignedIn &&
+ {signedAccountId &&
@@ -48,16 +43,16 @@ function App() {
- {chain === 'eth' &&
}
- {chain === 'btc' &&
}
+ {chain === 'eth' &&
}
+ {chain === 'btc' &&
}
}
- {status}
+ {status}
- >
+
)
}
diff --git a/src/assets/favicon.ico b/src/assets/favicon.ico
deleted file mode 100644
index 405779a..0000000
Binary files a/src/assets/favicon.ico and /dev/null differ
diff --git a/src/assets/logo-white.svg b/src/assets/logo-white.svg
deleted file mode 100644
index 47cb783..0000000
--- a/src/assets/logo-white.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/src/components/Bitcoin.jsx b/src/components/Bitcoin.jsx
index d8fa44d..c5dea7c 100644
--- a/src/components/Bitcoin.jsx
+++ b/src/components/Bitcoin.jsx
@@ -1,12 +1,16 @@
+import { useState, useEffect, useContext } from "react";
+import { NearContext } from "../context";
+
import { Bitcoin as Bitcoin } from "../services/bitcoin";
-import { useState, useEffect } from "react";
import { useDebounce } from "../hooks/debounce";
import PropTypes from 'prop-types';
const BTC_NETWORK = 'testnet';
const BTC = new Bitcoin('https://blockstream.info/testnet/api', BTC_NETWORK);
-export function BitcoinView({ props: { setStatus, wallet, MPC_CONTRACT } }) {
+export function BitcoinView({ props: { setStatus, MPC_CONTRACT } }) {
+ const { wallet, signedAccountId } = useContext(NearContext);
+
const [receiver, setReceiver] = useState("tb1q86ec0aszet5r3qt02j77f3dvxruk7tuqdlj0d5");
const [amount, setAmount] = useState(1000);
const [loading, setLoading] = useState(false);
@@ -15,44 +19,56 @@ export function BitcoinView({ props: { setStatus, wallet, MPC_CONTRACT } }) {
const [senderAddress, setSenderAddress] = useState("")
const [senderPK, setSenderPK] = useState("")
- const [derivation, setDerivation] = useState("test");
+ const [derivation, setDerivation] = useState("bitcoin-1");
const derivationPath = useDebounce(derivation, 500);
- useEffect(() => { setBtcAddress(derivationPath) }, [derivationPath]);
+ useEffect(() => {
+ setSenderAddress('Waiting for you to stop typing...')
+ }, [derivation]);
- async function setBtcAddress() {
- setStatus('Querying your address and balance');
- setSenderAddress('Deriving address...');
+ useEffect(() => {
+ setBtcAddress()
- const { address, publicKey } = await BTC.deriveAddress(wallet.accountId, derivationPath);
- const balance = await BTC.getBalance(address);
+ async function setBtcAddress() {
+ setStatus('Querying your address and balance');
+ setSenderAddress(`Deriving address from path ${derivationPath}...`);
- setSenderAddress(address);
- setSenderPK(publicKey);
- setStatus(`Your Bitcoin address is: ${address}, balance: ${balance} satoshi`);
- }
+ const { address, publicKey } = await BTC.deriveAddress(signedAccountId, derivationPath);
+ setSenderAddress(address);
+ setSenderPK(publicKey);
+
+ const balance = await BTC.getBalance(address);
+ setStatus(`Your Bitcoin address is: ${address}, balance: ${balance} satoshi`);
+ }
+ }, [signedAccountId, derivationPath]);
async function chainSignature() {
setStatus('🏗️ Creating transaction');
const payload = await BTC.createPayload(senderAddress, receiver, amount);
-
- setStatus('🕒 Asking MPC to sign the transaction, this might take a while...');
- const signedTransaction = await BTC.requestSignatureToMPC(wallet, MPC_CONTRACT, derivationPath, payload, senderPK);
- console.log(signedTransaction)
-
- setStatus('✅ Signed payload ready to be relayed to the Bitcoin network');
- setSignedTransaction(signedTransaction);
- setStep('relay');
+ setStatus('🕒 Asking MPC to sign the transaction, this might take a while...');
+ try{
+ const signedTransaction = await BTC.requestSignatureToMPC(wallet, MPC_CONTRACT, derivationPath, payload, senderPK);
+ setStatus('✅ Signed payload ready to be relayed to the Bitcoin network');
+ setSignedTransaction(signedTransaction);
+ setStep('relay');
+ } catch (e) {
+ setStatus(`❌ Error: ${e.message}`);
+ setLoading(false);
+ }
}
async function relayTransaction() {
setLoading(true);
setStatus('🔗 Relaying transaction to the Bitcoin network... this might take a while');
-
+
try {
const txHash = await BTC.relayTransaction(signedTransaction);
- setStatus(`✅ Successful: https://blockstream.info/testnet/tx/${txHash}`);
+ setStatus(
+ <>
+ ✅ Successful
+ >
+ );
} catch (e) {
setStatus(`❌ Error: ${e.message}`);
}
@@ -61,12 +77,6 @@ export function BitcoinView({ props: { setStatus, wallet, MPC_CONTRACT } }) {
setLoading(false);
}
- const handleDerivationChange = (event) => {
- setStatus('Derivation path changed');
- setSenderAddress('Waiting for you to stop typing...');
- setDerivation(event.target.value);
- }
-
const UIChainSignature = async () => {
setLoading(true);
await chainSignature();
@@ -76,22 +86,22 @@ export function BitcoinView({ props: { setStatus, wallet, MPC_CONTRACT } }) {
return (
<>
@@ -107,7 +117,6 @@ export function BitcoinView({ props: { setStatus, wallet, MPC_CONTRACT } }) {
BitcoinView.propTypes = {
props: PropTypes.shape({
setStatus: PropTypes.func.isRequired,
- wallet: PropTypes.object.isRequired,
MPC_CONTRACT: PropTypes.string.isRequired,
}).isRequired
};
\ No newline at end of file
diff --git a/src/components/Ethereum.jsx b/src/components/Ethereum.jsx
index 30b7148..b9fd01b 100644
--- a/src/components/Ethereum.jsx
+++ b/src/components/Ethereum.jsx
@@ -1,12 +1,15 @@
+import { useState, useEffect, useContext } from "react";
+import { NearContext } from "../context";
+
import { Ethereum } from "../services/ethereum";
-import { useEffect, useState } from "react";
import { useDebounce } from "../hooks/debounce";
import PropTypes from 'prop-types';
const Sepolia = 11155111;
const Eth = new Ethereum('https://rpc2.sepolia.org', Sepolia);
-export function EthereumView({ props: { setStatus, wallet, MPC_CONTRACT } }) {
+export function EthereumView({ props: { setStatus, MPC_CONTRACT } }) {
+ const { wallet, signedAccountId } = useContext(NearContext);
const [receiver, setReceiver] = useState("0xe0f3B7e68151E9306727104973752A415c2bcbEb");
const [amount, setAmount] = useState(0.01);
@@ -15,21 +18,27 @@ export function EthereumView({ props: { setStatus, wallet, MPC_CONTRACT } }) {
const [signedTransaction, setSignedTransaction] = useState(null);
const [senderAddress, setSenderAddress] = useState("")
- const [derivation, setDerivation] = useState("test");
+ const [derivation, setDerivation] = useState("ethereum-1");
const derivationPath = useDebounce(derivation, 1000);
- useEffect(() => { setEthAddress(derivationPath) }, [derivationPath]);
+ useEffect(() => {
+ setSenderAddress('Waiting for you to stop typing...')
+ }, [derivation]);
- async function setEthAddress() {
- setStatus('Querying your address and balance');
- setSenderAddress('Deriving address...');
+ useEffect(() => {
+ setEthAddress()
- const { address } = await Eth.deriveAddress(wallet.accountId, derivationPath);
- const balance = await Eth.getBalance(address);
-
- setSenderAddress(address);
- setStatus(`Your Ethereum address is: ${address}, balance: ${balance} ETH`);
- }
+ async function setEthAddress() {
+ setStatus('Querying your address and balance');
+ setSenderAddress(`Deriving address from path ${derivationPath}...`);
+
+ const { address } = await Eth.deriveAddress(signedAccountId, derivationPath);
+ setSenderAddress(address);
+
+ const balance = await Eth.getBalance(address);
+ setStatus(`Your Ethereum address is: ${address}, balance: ${balance} ETH`);
+ }
+ }, [signedAccountId, derivationPath]);
async function chainSignature() {
setStatus('🏗️ Creating transaction');
@@ -41,7 +50,7 @@ export function EthereumView({ props: { setStatus, wallet, MPC_CONTRACT } }) {
setSignedTransaction(signedTransaction);
setStatus(`✅ Signed payload ready to be relayed to the Ethereum network`);
setStep('relay');
- } catch(e) {
+ } catch (e) {
setStatus(`❌ Error: ${e.message}`);
setLoading(false);
}
@@ -51,9 +60,12 @@ export function EthereumView({ props: { setStatus, wallet, MPC_CONTRACT } }) {
setLoading(true);
setStatus('🔗 Relaying transaction to the Ethereum network... this might take a while');
- try{
+ try {
const txHash = await Eth.relayTransaction(signedTransaction);
- setStatus(`✅ Successful: https://sepolia.etherscan.io/tx/${txHash}`);
+ setStatus(<>
+ ✅ Successful
+ >
+ );
} catch (e) {
setStatus(`❌ Error: ${e.message}`);
}
@@ -62,12 +74,6 @@ export function EthereumView({ props: { setStatus, wallet, MPC_CONTRACT } }) {
setLoading(false);
}
- const handleDerivationChange = (event) => {
- setStatus('Derivation path changed');
- setSenderAddress('Waiting for you to stop typing...');
- setDerivation(event.target.value);
- }
-
const UIChainSignature = async () => {
setLoading(true);
await chainSignature();
@@ -77,22 +83,22 @@ export function EthereumView({ props: { setStatus, wallet, MPC_CONTRACT } }) {
return (
<>
@@ -108,7 +114,6 @@ export function EthereumView({ props: { setStatus, wallet, MPC_CONTRACT } }) {
EthereumView.propTypes = {
props: PropTypes.shape({
setStatus: PropTypes.func.isRequired,
- wallet: PropTypes.object.isRequired,
MPC_CONTRACT: PropTypes.string.isRequired,
}).isRequired
};
\ No newline at end of file
diff --git a/src/components/Navbar.jsx b/src/components/Navbar.jsx
index a3a2c55..513feba 100644
--- a/src/components/Navbar.jsx
+++ b/src/components/Navbar.jsx
@@ -1,27 +1,26 @@
-import logo from "../assets/logo-black.svg";
-import PropTypes from 'prop-types';
-import { Wallet } from "../services/near-wallet";
+import { useContext } from "react";
+import { NearContext } from "../context";
-const Navbar = ({wallet, isSignedIn}) =>{
- const signIn = () => { wallet.signIn() }
- const signOut = () => { wallet.signOut() }
- return(