Skip to content

Commit

Permalink
Merge pull request #45 from near-examples/homogenize
Browse files Browse the repository at this point in the history
feat: Homogenize Bitcoin and Ethereum Examples
  • Loading branch information
gagdiez authored Dec 2, 2024
2 parents a21bf19 + f4be31a commit ca34d12
Show file tree
Hide file tree
Showing 13 changed files with 237 additions and 411 deletions.
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,15 @@
"@ethereumjs/common": "^4.3.0",
"@ethereumjs/tx": "^5.3.0",
"@ethereumjs/util": "^9.0.3",
"@near-wallet-selector/bitte-wallet": "^8.9.13",
"@near-wallet-selector/core": "^8.9.13",
"@near-wallet-selector/here-wallet": "^8.9.13",
"@near-wallet-selector/meteor-wallet": "^8.9.13",
"@near-wallet-selector/modal-ui": "^8.9.13",
"@near-wallet-selector/my-near-wallet": "^8.9.13",
"@near-wallet-selector/bitte-wallet": "^8.9.13",
"@vitejs/plugin-react": "^4.2.1",
"axios": "^1.6.8",
"bech32": "^2.0.0",
"bitcoinjs-lib": "^6.1.5",
"bn.js": "^5.2.1",
"bs58check": "^3.0.1",
Expand Down
8 changes: 3 additions & 5 deletions src/App.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,7 @@ import Navbar from "./components/Navbar"
import { Wallet } from "./services/near-wallet";
import { EthereumView } from "./components/Ethereum/Ethereum";
import { BitcoinView } from "./components/Bitcoin";

// CONSTANTS
const MPC_CONTRACT = 'v1.signer-prod.testnet';
import { MPC_CONTRACT } from './services/kdf/mpc';

// NEAR WALLET
const wallet = new Wallet({ network: 'testnet' });
Expand Down Expand Up @@ -47,8 +45,8 @@ function App() {
</select>
</div>

{chain === 'eth' && <EthereumView props={{ setStatus, MPC_CONTRACT, transactions }} />}
{chain === 'btc' && <BitcoinView props={{ setStatus, MPC_CONTRACT, transactions }} />}
{chain === 'eth' && <EthereumView props={{ setStatus, transactions }} />}
{chain === 'btc' && <BitcoinView props={{ setStatus, transactions }} />}
</div>
}

Expand Down
20 changes: 12 additions & 8 deletions src/components/Bitcoin.jsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { useState, useEffect, useContext } from "react";
import { NearContext } from "../context";

import { Bitcoin as Bitcoin } from "../services/bitcoin";
import { useDebounce } from "../hooks/debounce";
import PropTypes from 'prop-types';
import { Bitcoin } from "../services/bitcoin";

const BTC = Bitcoin;
const BTC = new Bitcoin('testnet');

export function BitcoinView({ props: { setStatus, MPC_CONTRACT, transactions } }) {
export function BitcoinView({ props: { setStatus, transactions } }) {
const { wallet, signedAccountId } = useContext(NearContext);

const [receiver, setReceiver] = useState("tb1q86ec0aszet5r3qt02j77f3dvxruk7tuqdlj0d5");
Expand All @@ -20,7 +20,7 @@ export function BitcoinView({ props: { setStatus, MPC_CONTRACT, transactions } }

const [derivation, setDerivation] = useState("bitcoin-1");
const derivationPath = useDebounce(derivation, 500);

const getSignedTx = async () => {
const signedTx = await wallet.getTransactionResult(transactions[0])
console.log('signedTx', signedTx)
Expand Down Expand Up @@ -53,9 +53,13 @@ export function BitcoinView({ props: { setStatus, MPC_CONTRACT, transactions } }

async function chainSignature() {
setStatus('🏗️ Creating transaction');

const { psbt, utxos } = await BTC.createTransaction({ from: senderAddress, to: receiver, amount, path: derivationPath, wallet });

setStatus('🕒 Asking MPC to sign the transaction, this might take a while...');

try {
const signedTransaction = await BTC.getSignature({ from: senderAddress, publicKey: senderPK, to: receiver, amount, path: derivationPath, wallet });
const signedTransaction = await BTC.requestSignatureToMPC({ psbt, utxos, publicKey: senderPK, path: derivationPath, wallet });
setStatus('✅ Signed payload ready to be relayed to the Bitcoin network');
setSignedTransaction(signedTransaction);
setStep('relay');
Expand All @@ -71,10 +75,10 @@ export function BitcoinView({ props: { setStatus, MPC_CONTRACT, transactions } }
setStatus('🔗 Relaying transaction to the Bitcoin network... this might take a while');

try {
const txHash = await BTC.broadcast({ from: senderAddress, publicKey: senderPK, to: receiver, amount, path: derivationPath, sig: signedTransaction });
const txHash = await BTC.broadcastTX(signedTransaction);
setStatus(
<>
<a href={`https://blockstream.info/testnet/tx/${txHash}`} target="_blank">Successful </a>
<a href={`https://blockstream.info/testnet/tx/${txHash}`} target="_blank">Successfully Broadcasted </a>
</>
);
} catch (e) {
Expand Down Expand Up @@ -125,6 +129,6 @@ export function BitcoinView({ props: { setStatus, MPC_CONTRACT, transactions } }
BitcoinView.propTypes = {
props: PropTypes.shape({
setStatus: PropTypes.func.isRequired,
MPC_CONTRACT: PropTypes.string.isRequired,
transactions: PropTypes.arrayOf(PropTypes.string).isRequired
}).isRequired
};
31 changes: 16 additions & 15 deletions src/components/Ethereum/Ethereum.jsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
import { useState, useEffect, useContext } from "react";
import { NearContext } from "../../context";

import { Ethereum } from "../../services/ethereum";
import { useDebounce } from "../../hooks/debounce";
import PropTypes from 'prop-types';
import { useRef } from "react";
import { TransferForm } from "./Transfer";
import { FunctionCallForm } from "./FunctionCall";
import { Ethereum } from "../../services/ethereum";
import { MPC_CONTRACT } from "../../services/kdf/mpc";

const Sepolia = 11155111;
const Eth = new Ethereum('https://rpc2.sepolia.org', Sepolia);
const Eth = new Ethereum('https://sepolia.drpc.org', Sepolia);

export function EthereumView({ props: { setStatus, MPC_CONTRACT, transactions } }) {
export function EthereumView({ props: { setStatus, transactions } }) {
const { wallet, signedAccountId } = useContext(NearContext);

const [loading, setLoading] = useState(false);
Expand All @@ -24,7 +25,7 @@ export function EthereumView({ props: { setStatus, MPC_CONTRACT, transactions }
const [derivation, setDerivation] = useState(sessionStorage.getItem('derivation') || "ethereum-1");
const derivationPath = useDebounce(derivation, 1200);

const [reloaded, setReloaded] = useState(transactions.length? true : false);
const [reloaded, setReloaded] = useState(transactions.length ? true : false);

const childRef = useRef();

Expand All @@ -34,8 +35,8 @@ export function EthereumView({ props: { setStatus, MPC_CONTRACT, transactions }

async function signTransaction() {
const { big_r, s, recovery_id } = await wallet.getTransactionResult(transactions[0]);
console.log({ big_r, s, recovery_id });
const signedTransaction = await Eth.reconstructSignatureFromLocalSession(big_r, s, recovery_id, senderAddress);
const signedTransaction = await Eth.reconstructSignedTXFromLocalSession(big_r, s, recovery_id, senderAddress);

setSignedTransaction(signedTransaction);
setStatus(`✅ Signed payload ready to be relayed to the Ethereum network`);
setStep('relay');
Expand All @@ -55,7 +56,7 @@ export function EthereumView({ props: { setStatus, MPC_CONTRACT, transactions }

useEffect(() => {
setEthAddress()
console.log(derivationPath)

async function setEthAddress() {
const { address } = await Eth.deriveAddress(signedAccountId, derivationPath);
setSenderAddress(address);
Expand All @@ -69,13 +70,15 @@ export function EthereumView({ props: { setStatus, MPC_CONTRACT, transactions }
async function chainSignature() {
setStatus('🏗️ Creating transaction');

const { transaction, payload } = await childRef.current.createPayload();
// const { transaction, payload } = await Eth.createPayload(senderAddress, receiver, amount, undefined);
const { transaction } = await childRef.current.createTransaction();

setStatus(`🕒 Asking ${MPC_CONTRACT} to sign the transaction, this might take a while`);
try {
const { big_r, s, recovery_id } = await Eth.requestSignatureToMPC(wallet, MPC_CONTRACT, derivationPath, payload, transaction, senderAddress);
const signedTransaction = await Eth.reconstructSignature(big_r, s, recovery_id, transaction, senderAddress);
// to reconstruct on reload
sessionStorage.setItem('derivation', derivationPath);

const { big_r, s, recovery_id } = await Eth.requestSignatureToMPC({ wallet, path: derivationPath, transaction });
const signedTransaction = await Eth.reconstructSignedTransaction(big_r, s, recovery_id, transaction);

setSignedTransaction(signedTransaction);
setStatus(`✅ Signed payload ready to be relayed to the Ethereum network`);
Expand All @@ -89,9 +92,8 @@ export function EthereumView({ props: { setStatus, MPC_CONTRACT, transactions }
async function relayTransaction() {
setLoading(true);
setStatus('🔗 Relaying transaction to the Ethereum network... this might take a while');

try {
const txHash = await Eth.relayTransaction(signedTransaction);
const txHash = await Eth.broadcastTX(signedTransaction);
setStatus(
<>
<a href={`https://sepolia.etherscan.io/tx/${txHash}`} target="_blank"> ✅ Successful </a>
Expand Down Expand Up @@ -142,7 +144,7 @@ export function EthereumView({ props: { setStatus, MPC_CONTRACT, transactions }
</>
)

function removeUrlParams () {
function removeUrlParams() {
const url = new URL(window.location.href);
url.searchParams.delete('transactionHashes');
window.history.replaceState({}, document.title, url);
Expand All @@ -152,7 +154,6 @@ export function EthereumView({ props: { setStatus, MPC_CONTRACT, transactions }
EthereumView.propTypes = {
props: PropTypes.shape({
setStatus: PropTypes.func.isRequired,
MPC_CONTRACT: PropTypes.string.isRequired,
transactions: PropTypes.arrayOf(PropTypes.string).isRequired
}).isRequired
};
12 changes: 5 additions & 7 deletions src/components/Ethereum/FunctionCall.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -60,15 +60,13 @@ export const FunctionCallForm = forwardRef(({ props: { Eth, senderAddress, loadi
useEffect(() => { getNumber() }, []);

useImperativeHandle(ref, () => ({
async createPayload() {
async createTransaction() {
const data = Eth.createTransactionData(contract, abi, 'set', [number]);
const { transaction, payload } = await Eth.createPayload(senderAddress, contract, 0, data);
return { transaction, payload };
const { transaction } = await Eth.createTransaction({ sender: senderAddress, receiver: contract, amount: 0, data });
return { transaction };
},

async afterRelay() {
getNumber();
}
async afterRelay() { getNumber(); }
}));

return (
Expand Down Expand Up @@ -110,7 +108,7 @@ FunctionCallForm.propTypes = {
senderAddress: PropTypes.string.isRequired,
loading: PropTypes.bool.isRequired,
Eth: PropTypes.shape({
createPayload: PropTypes.func.isRequired,
createTransaction: PropTypes.func.isRequired,
createTransactionData: PropTypes.func.isRequired,
getContractViewFunction: PropTypes.func.isRequired,
}).isRequired,
Expand Down
10 changes: 5 additions & 5 deletions src/components/Ethereum/Transfer.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@ import { forwardRef } from "react";
import { useImperativeHandle } from "react";

export const TransferForm = forwardRef(({ props: { Eth, senderAddress, loading } }, ref) => {
const [receiver, setReceiver] = useState("0xe0f3B7e68151E9306727104973752A415c2bcbEb");
const [receiver, setReceiver] = useState("0xb8A6a4eb89b27703E90ED18fDa1101c7aa02930D");
const [amount, setAmount] = useState(0.005);

useImperativeHandle(ref, () => ({
async createPayload() {
const { transaction, payload } = await Eth.createPayload(senderAddress, receiver, amount, undefined);
return { transaction, payload };
async createTransaction() {
const { transaction } = await Eth.createTransaction({ sender: senderAddress, receiver, amount });
return { transaction };
},
async afterRelay() { }
}));
Expand Down Expand Up @@ -40,7 +40,7 @@ TransferForm.propTypes = {
senderAddress: PropTypes.string.isRequired,
loading: PropTypes.bool.isRequired,
Eth: PropTypes.shape({
createPayload: PropTypes.func.isRequired
createTransaction: PropTypes.func.isRequired
}).isRequired
}).isRequired
};
Expand Down
Loading

0 comments on commit ca34d12

Please sign in to comment.