Skip to content

Commit

Permalink
Type Rearrangements (#142)
Browse files Browse the repository at this point in the history
  • Loading branch information
bh2smith authored Oct 26, 2024
1 parent 49d4f08 commit 3b8937b
Show file tree
Hide file tree
Showing 10 changed files with 109 additions and 116 deletions.
18 changes: 11 additions & 7 deletions src/beta.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import { Hex, Signature, serializeSignature } from "viem";
import { addSignature, relaySignedTransaction } from "./utils/transaction";
import { NearEthTxData, signMethods } from "./types";
import {
addSignature,
relaySignedTransaction,
toPayload,
} from "./utils/transaction";
import { NearEncodedSignRequest, signMethods } from "./types";
import { NearEthAdapter } from "./chains/ethereum";
import { Web3WalletTypes } from "@walletconnect/web3wallet";
import { isSignMethod } from "./guards";
Expand All @@ -23,7 +27,7 @@ export class Beta {

async handleSessionRequest(
request: Partial<Web3WalletTypes.SessionRequest>
): Promise<NearEthTxData> {
): Promise<NearEncodedSignRequest> {
const {
chainId,
request: { method, params },
Expand All @@ -34,20 +38,20 @@ export class Beta {
`Unsupported sign method ${method}: Available sign methods ${signMethods}`
);
}
const { evmMessage, payload, recoveryData } = await requestRouter({
const { evmMessage, hashToSign } = await requestRouter({
method,
chainId: parseInt(stripEip155Prefix(chainId)),
params,
});
console.log("Parsed Request:", payload, recoveryData);
console.log("Parsed Request:", evmMessage, hashToSign);
return {
nearPayload: await this.adapter.mpcContract.encodeSignatureRequestTx({
path: this.adapter.derivationPath,
payload,
payload: toPayload(hashToSign),
key_version: 0,
}),
evmMessage,
recoveryData,
hashToSign,
};
}

Expand Down
11 changes: 5 additions & 6 deletions src/chains/ethereum.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ import {
toPayload,
broadcastSignedTransaction,
SignRequestData,
NearEthTxData,
IMpcContract,
NearEncodedSignRequest,
} from "..";
import { Beta } from "../beta";
import { requestRouter } from "../utils/request";
Expand Down Expand Up @@ -233,17 +233,16 @@ export class NearEthAdapter {
*/
async encodeSignRequest(
signRequest: SignRequestData
): Promise<NearEthTxData> {
const { evmMessage, payload, recoveryData } =
await requestRouter(signRequest);
): Promise<NearEncodedSignRequest> {
const { evmMessage, hashToSign } = await requestRouter(signRequest);
return {
nearPayload: await this.mpcContract.encodeSignatureRequestTx({
path: this.derivationPath,
payload,
payload: toPayload(hashToSign),
key_version: 0,
}),
evmMessage,
recoveryData,
hashToSign,
};
}
}
2 changes: 1 addition & 1 deletion src/network/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ export const CHAIN_INFO: Record<number, ChainInfo> = {
},

// OP Testnet
11155420:{
11155420: {
currencyIcon: ETHER,
icon: OPTIMISM_ICON,
wrappedToken: "0x4200000000000000000000000000000000000006",
Expand Down
52 changes: 32 additions & 20 deletions src/types.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { IMpcContract } from "./mpcContract";
import {
Address,
Hash,
Hex,
SignableMessage,
Signature,
Expand Down Expand Up @@ -53,18 +54,41 @@ export interface AdapterParams {
}

/**
* Represents the data required for a NEAR to Ethereum transaction.
* Represents a message that can be signed within an Ethereum Virtual Machine (EVM) context.
* This can be a raw string, an EIP-712 typed data structure, or a serializable transaction.
*
* @property {string | TransactionSerializable} evmMessage - The EVM message or transaction.
* @property {FunctionCallTransaction<{ request: SignArgs }>} nearPayload - The NEAR payload containing the function call transaction.
* @property {RecoveryData} recoveryData - The data required to recover partial signature.
* @typedef {string | EIP712TypedData | TransactionSerializable} EvmMessage
*/
export interface NearEthTxData {
evmMessage: string | TransactionSerializable;
nearPayload: FunctionCallTransaction<{ request: SignArgs }>;
recoveryData: RecoveryData;
export type EvmMessage = string | EIP712TypedData | TransactionSerializable;

/**
* Encapsulates a signature request for an Ethereum-based message.
*
* @interface EncodedSignRequest
* @property {EvmMessage} evmMessage - The message to be signed, which could be in plain string format,
* an EIP-712 typed data, or a serializable transaction.
* @property {Hash} hashToSign - A unique hash derived from `evmMessage` to identify the signature request.
*/
export interface EncodedSignRequest {
evmMessage: EvmMessage;
hashToSign: Hash;
}

/**
* Extends the `EncodedSignRequest` for use with NEAR protocol.
* This structure contains an additional payload to facilitate transaction signing in NEAR.
*
* @interface NearEncodedSignRequest
* @extends EncodedSignRequest
* @property {FunctionCallTransaction<{ request: SignArgs }>} nearPayload - A NEAR-specific transaction payload,
* typically including a request with arguments
* for the function call.
*/
export interface NearEncodedSignRequest extends EncodedSignRequest {
nearPayload: FunctionCallTransaction<{
request: SignArgs;
}>;
}
/**
* Represents the gas fees for an Ethereum transaction.
*
Expand Down Expand Up @@ -168,18 +192,6 @@ export type EIP712TypedData = {
primaryType: string;
};

/**
* Represents the recovery data.
*
* @property {string} type - The type of the recovery data.
* @property {MessageData | EIP712TypedData | Hex} data - The recovery data.
*/
export interface RecoveryData {
// TODO use enum!
type: string;
data: MessageData | EIP712TypedData | Hex;
}

/**
* Sufficient data required to construct a signed Ethereum Transaction.
*
Expand Down
17 changes: 7 additions & 10 deletions src/utils/mock-sign.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,13 @@
import { Address, Hex, Signature, toHex } from "viem";
import { Address, Hex, Signature } from "viem";
import { PrivateKeyAccount, privateKeyToAccount } from "viem/accounts";
import { FunctionCallTransaction, SignArgs } from "../types";
import { Account } from "near-api-js";
import { IMpcContract, nearAccountFromAccountId, NearEthAdapter } from "..";

function fromPayload(payload: number[]): Hex {
if (payload.length !== 32) {
throw new Error(`Payload must have 32 bytes: ${payload}`);
}
// Convert number[] back to Uint8Array
return toHex(new Uint8Array(payload));
}
import {
fromPayload,
IMpcContract,
nearAccountFromAccountId,
NearEthAdapter,
} from "..";

/**
* Converts a raw hexadecimal signature into a structured Signature object
Expand Down
52 changes: 11 additions & 41 deletions src/utils/request.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@ import {
keccak256,
serializeTransaction,
} from "viem";
import { populateTx, toPayload } from "./transaction";
import { populateTx } from "./transaction";
import {
EncodedSignRequest,
EthSignParams,
EthTransactionParams,
PersonalSignParams,
RecoveryData,
SignRequestData,
TypedDataParams,
} from "../types";
Expand All @@ -23,47 +23,28 @@ import {
* @async
* @function requestRouter
* @param {SignRequestData} params - An object containing the method, chain ID, and request parameters.
* @returns {Promise<{ evmMessage: string; payload: number[]; recoveryData: RecoveryData }>}
* @returns {Promise<NearEncodedSignRequest>}
* - Returns a promise that resolves to an object containing the Ethereum Virtual Machine (EVM) message,
* the payload (hashed data), and recovery data needed for reconstructing the signature request.
*/
export async function requestRouter({
method,
chainId,
params,
}: SignRequestData): Promise<{
evmMessage: string;
payload: number[];
// We may eventually be able to abolish this.
recoveryData: RecoveryData;
}> {
}: SignRequestData): Promise<EncodedSignRequest> {
switch (method) {
case "eth_sign": {
const [sender, messageHash] = params as EthSignParams;
const [_, messageHash] = params as EthSignParams;
return {
evmMessage: fromHex(messageHash, "string"),
payload: toPayload(hashMessage({ raw: messageHash })),
recoveryData: {
type: method,
data: {
address: sender,
message: { raw: messageHash },
},
},
hashToSign: hashMessage({ raw: messageHash }),
};
}
case "personal_sign": {
const [messageHash, sender] = params as PersonalSignParams;
const [messageHash, _] = params as PersonalSignParams;
return {
evmMessage: fromHex(messageHash, "string"),
payload: toPayload(hashMessage({ raw: messageHash })),
recoveryData: {
type: method,
data: {
address: sender,
message: { raw: messageHash },
},
},
hashToSign: hashMessage({ raw: messageHash }),
};
}
case "eth_sendTransaction": {
Expand All @@ -87,28 +68,17 @@ export async function requestRouter({
}

return {
payload: toPayload(keccak256(rlpTx)),
hashToSign: keccak256(rlpTx),
evmMessage: rlpTx,
recoveryData: {
type: "eth_sendTransaction",
data: rlpTx,
},
};
}
case "eth_signTypedData":
case "eth_signTypedData_v4": {
const [sender, dataString] = params as TypedDataParams;
const [_, dataString] = params as TypedDataParams;
const typedData = JSON.parse(dataString);
return {
evmMessage: dataString,
payload: toPayload(hashTypedData(typedData)),
recoveryData: {
type: "eth_signTypedData",
data: {
address: sender,
...typedData,
},
},
hashToSign: hashTypedData(typedData),
};
}
}
Expand Down
9 changes: 9 additions & 0 deletions src/utils/transaction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
parseTransaction,
serializeTransaction,
toBytes,
toHex,
} from "viem";
import { BaseTx, TransactionWithSignature } from "../types";
import { Network } from "../network";
Expand All @@ -20,6 +21,14 @@ export function toPayload(msgHash: Hex | Uint8Array): number[] {
return Array.from(bytes);
}

export function fromPayload(payload: number[]): Hex {
if (payload.length !== 32) {
throw new Error(`Payload must have 32 bytes: ${payload}`);
}
// Convert number[] back to Uint8Array
return toHex(new Uint8Array(payload));
}

export function buildTxPayload(serializedTx: `0x${string}`): number[] {
return toPayload(keccak256(serializedTx));
}
Expand Down
9 changes: 2 additions & 7 deletions tests/unit/ethereum.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,13 +79,8 @@ describe("ethereum", () => {
],
},
evmMessage: "",
recoveryData: {
type: "eth_sign",
data: {
address: "0xe09907d0a59bf84a68f5249ab328fc0ce0417a28",
message: { raw: "0x" },
},
},
hashToSign:
"0x5f35dce98ba4fba25530a026ed80b2cecdaa31091ba4958b99b52ea1d068adad",
});
});
});
15 changes: 15 additions & 0 deletions tests/unit/utils.transaction.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
addSignature,
toPayload,
populateTx,
fromPayload,
} from "../../src/utils/transaction";

describe("Transaction Builder Functions", () => {
Expand All @@ -18,6 +19,15 @@ describe("Transaction Builder Functions", () => {
]);
});

it("pass: toPayload", async () => {
const txHash =
"0x52b6437db56d87f5991d7c173cf11b9dd0f9fb083260bef1bf0c338042bc398c";
expect(toPayload(txHash)).toStrictEqual([
82, 182, 67, 125, 181, 109, 135, 245, 153, 29, 124, 23, 60, 241, 27, 157,
208, 249, 251, 8, 50, 96, 190, 241, 191, 12, 51, 128, 66, 188, 57, 140,
]);
});

it("fails: toPayload", async () => {
const txHash =
"0x02e783aa36a7808309e8bb84773f7cbb8094deadbeef0000000000000000000000000b00b1e50180c00";
Expand All @@ -26,6 +36,11 @@ describe("Transaction Builder Functions", () => {
);
});

it("pass: fromPayload", async () => {
const txHash =
"0x52b6437db56d87f5991d7c173cf11b9dd0f9fb083260bef1bf0c338042bc398c";
expect(fromPayload(toPayload(txHash))).toBe(txHash);
});
it("addSignature", async () => {
const testTx: TransactionWithSignature = {
transaction:
Expand Down
Loading

0 comments on commit 3b8937b

Please sign in to comment.