Skip to content

Commit

Permalink
hack Wallet integration
Browse files Browse the repository at this point in the history
  • Loading branch information
bh2smith committed Mar 22, 2024
1 parent e583277 commit 369fc00
Show file tree
Hide file tree
Showing 6 changed files with 163 additions and 40 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
"@near-js/accounts": "^1.0.4",
"@near-js/crypto": "^1.2.1",
"@near-js/keystores": "^0.0.9",
"@near-wallet-selector/core": "^8.9.5",
"bn.js": "^5.2.1",
"bs58check": "^3.0.1",
"elliptic": "^6.5.5",
Expand Down
90 changes: 52 additions & 38 deletions src/chains/ethereum.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,12 @@ import {
http,
Hash,
} from "viem";
import { BaseTx, NearEthAdapterParams, TxPayload } from "../types";
import {
BaseTx,
NearEthAdapterParams,
NearSignPayload,
TxPayload,
} from "../types";
import { queryGasPrice } from "../utils/gasPrice";
import { MultichainContract } from "../mpcContract";
import BN from "bn.js";
Expand Down Expand Up @@ -71,59 +76,38 @@ export class NearEthAdapter {
nearGas
);

const signedTx = NearEthAdapter.reconstructSignature(
transaction,
big_r,
big_s,
this.sender
);
const signedTx = this.reconstructSignature(transaction, big_r, big_s);
console.log("Relaying signed tx to EVM...");
return this.relayTransaction(signedTx);
}

/**
* Builds a complete, unsigned transaction (with nonce, gas estimates, current prices)
* and payload bytes in preparation to be relayed to Near MPC contract.
*
* @param {BaseTx} tx - Minimal transaction data to be signed by Near MPC and executed on EVM.
* @returns transacion and its bytes (the payload to be signed on Near)
*/
async createTxPayload(tx: BaseTx): Promise<TxPayload> {
const transaction = await this.buildTransaction(tx);
console.log("Built Transaction", JSON.stringify(transaction));
const payload = Array.from(
new Uint8Array(transaction.getHashedMessageToSign().slice().reverse())
async getSignatureRequstPayload(
txData: BaseTx,
nearGas?: BN
): Promise<NearSignPayload> {
console.log("Creating Payload for sender:", this.sender);
const { payload } = await this.createTxPayload(txData);
console.log("Requesting signature from Near...");
return this.mpcContract.buildSignatureRequestTx(
payload,
this.derivationPath,
nearGas
);
return { transaction, payload };
}

/**
* Relays signed transaction to Etherem mempool for execution.
* @param signedTx - Signed Ethereum transaction.
* @returns Transaction Hash of relayed transaction.
*/
async relayTransaction(signedTx: FeeMarketEIP1559Transaction): Promise<Hash> {
const serializedTx = bytesToHex(signedTx.serialize()) as Hex;
const txHash = await this.client.sendRawTransaction({
serializedTransaction: serializedTx,
});
console.log(`Transaction Confirmed: ${this.scanUrl}/tx/${txHash}`);
return txHash;
}

private static reconstructSignature = (
reconstructSignature = (
transaction: FeeMarketEIP1559Transaction,
big_r: string,
big_s: string,
sender: Address
big_s: string
): FeeMarketEIP1559Transaction => {
const r = Buffer.from(big_r.substring(2), "hex");
const s = Buffer.from(big_s, "hex");

const candidates = [0n, 1n].map((v) => transaction.addSignature(v, r, s));
const signature = candidates.find(
(c) =>
c.getSenderAddress().toString().toLowerCase() === sender.toLowerCase()
c.getSenderAddress().toString().toLowerCase() ===
this.sender.toLowerCase()
);

if (!signature) {
Expand All @@ -133,6 +117,36 @@ export class NearEthAdapter {
return signature;
};

/**
* Relays signed transaction to Etherem mempool for execution.
* @param signedTx - Signed Ethereum transaction.
* @returns Transaction Hash of relayed transaction.
*/
async relayTransaction(signedTx: FeeMarketEIP1559Transaction): Promise<Hash> {
const serializedTx = bytesToHex(signedTx.serialize()) as Hex;
const txHash = await this.client.sendRawTransaction({
serializedTransaction: serializedTx,
});
console.log(`Transaction Confirmed: ${this.scanUrl}/tx/${txHash}`);
return txHash;
}

/**
* Builds a complete, unsigned transaction (with nonce, gas estimates, current prices)
* and payload bytes in preparation to be relayed to Near MPC contract.
*
* @param {BaseTx} tx - Minimal transaction data to be signed by Near MPC and executed on EVM.
* @returns transacion and its bytes (the payload to be signed on Near)
*/
private async createTxPayload(tx: BaseTx): Promise<TxPayload> {
const transaction = await this.buildTransaction(tx);
console.log("Built Transaction", JSON.stringify(transaction));
const payload = Array.from(
new Uint8Array(transaction.getHashedMessageToSign().slice().reverse())
);
return { transaction, payload };
}

private async buildTransaction(
tx: BaseTx
): Promise<FeeMarketEIP1559Transaction> {
Expand Down
18 changes: 18 additions & 0 deletions src/chains/near.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import BN from "bn.js";
import { keyStores, KeyPair, connect, Account } from "near-api-js";
import { Wallet } from "@near-wallet-selector/core";

export const TGAS = new BN(1000000000000);
export const NO_DEPOSIT = "0";
Expand Down Expand Up @@ -53,3 +54,20 @@ export const nearAccountFromKeyPair = async (config: {
const account = await near.account(config.accountId);
return account;
};

/** Minimally sufficient Account instance to construct the signing contract instance.
* Can't be used to change methods.
*/
export const nearAccountFromWallet = async (
wallet: Wallet,
network?: NearConfig
): Promise<Account> => {
const keyStore = new keyStores.InMemoryKeyStore();
const near = await connect({
...(network || TESTNET_CONFIG),
keyStore,
});
const accountId = (await wallet.getAccounts())[0].accountId;
const account = await near.account(accountId);
return account;
};
23 changes: 23 additions & 0 deletions src/mpcContract.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
} from "./utils/kdf";
import { NO_DEPOSIT, nearAccountFromEnv, TGAS } from "./chains/near";
import BN from "bn.js";
import { NearSignPayload } from "./types";

interface ChangeMethodArgs<T> {
args: T;
Expand Down Expand Up @@ -76,4 +77,26 @@ export class MultichainContract {
});
return { big_r, big_s };
};

buildSignatureRequestTx = async (
payload: number[],
path: string,
gas?: BN
): Promise<NearSignPayload> => {
return {
signerId: this.contract.account.accountId,
receiverId: this.contract.contractId,
actions: [
{
type: "FunctionCall",
params: {
methodName: "sign",
args: { path, payload },
gas: (gas || TGAS.muln(200)).toString(),
deposit: NO_DEPOSIT,
},
},
],
};
};
}
9 changes: 8 additions & 1 deletion src/types.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { FeeMarketEIP1559Transaction } from "@ethereumjs/tx";
import { Address, Hex } from "viem";
import { MultichainContract } from "./mpcContract";
import { FunctionCallAction } from "@near-wallet-selector/core";

export interface BaseTx {
/// Recipient of the transaction
Expand Down Expand Up @@ -28,7 +29,7 @@ export interface EvmParams {
}

export interface NearParams {
// A instance of the NearMPC contract connected to the associated near account.
/// An instance of the NearMPC contract connected to the associated near account.
mpcContract: MultichainContract;
/// path used to generate ETH account from Near account (e.g. "ethereum,1")
derivationPath?: string;
Expand All @@ -43,3 +44,9 @@ export interface TxPayload {
transaction: FeeMarketEIP1559Transaction;
payload: number[];
}

export interface NearSignPayload {
signerId: string;
receiverId: string;
actions: Array<FunctionCallAction>;
}
62 changes: 61 additions & 1 deletion yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -787,6 +787,16 @@
bn.js "5.2.1"
borsh "1.0.0"

"@near-wallet-selector/core@^8.9.5":
version "8.9.5"
resolved "https://registry.yarnpkg.com/@near-wallet-selector/core/-/core-8.9.5.tgz#15e49f17252ee4e54a1c9719b8c2b98fd71aae74"
integrity sha512-wJiCL8M7z6tkNMY5H4n63/SZCmlW0Z15H6R1biWgpRuMDlVjhQOzxrmQggb1jbK4nYkzXyARNKyPh2gcRUuS+w==
dependencies:
borsh "0.7.0"
events "3.3.0"
js-sha256 "0.9.0"
rxjs "7.8.1"

"@noble/[email protected]", "@noble/curves@~1.2.0":
version "1.2.0"
resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.2.0.tgz#92d7e12e4e49b23105a2555c6984d41733d65c35"
Expand Down Expand Up @@ -1350,6 +1360,13 @@ base-x@^2.0.1:
dependencies:
safe-buffer "^5.0.1"

base-x@^3.0.2:
version "3.0.9"
resolved "https://registry.yarnpkg.com/base-x/-/base-x-3.0.9.tgz#6349aaabb58526332de9f60995e548a53fe21320"
integrity sha512-H7JU6iBHTal1gp56aKoaa//YUxEaAOUiydvrV/pILqIHXTtqxSkATOnDA2u+jZ/61sD+L/412+7kzXRtWukhpQ==
dependencies:
safe-buffer "^5.0.1"

base-x@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/base-x/-/base-x-4.0.0.tgz#d0e3b7753450c73f8ad2389b5c018a4af7b2224a"
Expand All @@ -1365,7 +1382,7 @@ [email protected]:
resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.6.tgz#53344adb14617a13f6e8dd2ce28905d1c0ba3215"
integrity sha512-XWwnNNFCuuSQ0m3r3C4LE3EiORltHd9M05pq6FOlVeiophzRbMo50Sbz1ehl8K3Z+jw9+vmgnXefY1hz8X+2wA==

[email protected], bn.js@^5.2.1:
[email protected], bn.js@^5.2.0, bn.js@^5.2.1:
version "5.2.1"
resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.2.1.tgz#0bc527a6a0d18d0aa8d5b0538ce4a77dccfa7b70"
integrity sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==
Expand All @@ -1375,6 +1392,15 @@ bn.js@^4.11.9:
resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.12.0.tgz#775b3f278efbb9718eec7361f483fb36fbbfea88"
integrity sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==

[email protected]:
version "0.7.0"
resolved "https://registry.yarnpkg.com/borsh/-/borsh-0.7.0.tgz#6e9560d719d86d90dc589bca60ffc8a6c51fec2a"
integrity sha512-CLCsZGIBCFnPtkNnieW/a8wmreDmfUtjU2m9yHrzPXIlNbqVs0AQrSatSG6vdNYUqdc83tkQi2eHfF98ubzQLA==
dependencies:
bn.js "^5.2.0"
bs58 "^4.0.0"
text-encoding-utf-8 "^1.0.2"

[email protected]:
version "1.0.0"
resolved "https://registry.yarnpkg.com/borsh/-/borsh-1.0.0.tgz#b564c8cc8f7a91e3772b9aef9e07f62b84213c1f"
Expand Down Expand Up @@ -1431,6 +1457,13 @@ [email protected]:
dependencies:
base-x "^2.0.1"

bs58@^4.0.0:
version "4.0.1"
resolved "https://registry.yarnpkg.com/bs58/-/bs58-4.0.1.tgz#be161e76c354f6f788ae4071f63f34e8c4f0a42a"
integrity sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw==
dependencies:
base-x "^3.0.2"

bs58@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/bs58/-/bs58-5.0.0.tgz#865575b4d13c09ea2a84622df6c8cbeb54ffc279"
Expand Down Expand Up @@ -1862,6 +1895,11 @@ [email protected]:
bn.js "4.11.6"
number-to-bn "1.7.0"

[email protected]:
version "3.3.0"
resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400"
integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==

execa@^5.0.0:
version "5.1.1"
resolved "https://registry.yarnpkg.com/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd"
Expand Down Expand Up @@ -2646,6 +2684,11 @@ jest@^29.7.0:
import-local "^3.0.2"
jest-cli "^29.7.0"

[email protected]:
version "0.9.0"
resolved "https://registry.yarnpkg.com/js-sha256/-/js-sha256-0.9.0.tgz#0b89ac166583e91ef9123644bd3c5334ce9d0966"
integrity sha512-sga3MHh9sgQN2+pJ9VYZ+1LPwXOxuBJBA5nrR5/ofPfuiJBE2hnjsaN8se8JznOmGLN2p49Pe5U/ttafcs/apA==

js-sha3@^0.8.0:
version "0.8.0"
resolved "https://registry.yarnpkg.com/js-sha3/-/js-sha3-0.8.0.tgz#b9b7a5da73afad7dedd0f8c463954cbde6818840"
Expand Down Expand Up @@ -3219,6 +3262,13 @@ run-parallel@^1.1.9:
dependencies:
queue-microtask "^1.2.2"

[email protected]:
version "7.8.1"
resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.8.1.tgz#6f6f3d99ea8044291efd92e7c7fcf562c4057543"
integrity sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==
dependencies:
tslib "^2.1.0"

safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@~5.2.0:
version "5.2.1"
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6"
Expand Down Expand Up @@ -3386,6 +3436,11 @@ test-exclude@^6.0.0:
glob "^7.1.4"
minimatch "^3.0.4"

text-encoding-utf-8@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/text-encoding-utf-8/-/text-encoding-utf-8-1.0.2.tgz#585b62197b0ae437e3c7b5d0af27ac1021e10d13"
integrity sha512-8bw4MY9WjdsD2aMtO0OzOCY3pXGYNx2d2FfHRVUKkiCPDWjKuOlhLVASS+pD7VkLTVjW268LYJHwsnPFlBpbAg==

text-table@^0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4"
Expand Down Expand Up @@ -3466,6 +3521,11 @@ [email protected]:
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.4.0.tgz#7cecaa7f073ce680a05847aa77be941098f36dc3"
integrity sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==

tslib@^2.1.0:
version "2.6.2"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.2.tgz#703ac29425e7b37cd6fd456e92404d46d1f3e4ae"
integrity sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==

type-check@^0.4.0, type-check@~0.4.0:
version "0.4.0"
resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1"
Expand Down

0 comments on commit 369fc00

Please sign in to comment.