Skip to content

Commit

Permalink
add getSignature with test
Browse files Browse the repository at this point in the history
  • Loading branch information
bh2smith committed May 5, 2024
1 parent bd91be9 commit 2686602
Show file tree
Hide file tree
Showing 4 changed files with 270 additions and 0 deletions.
131 changes: 131 additions & 0 deletions src/types/rpc.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
// Basic structure of the JSON-RPC response
export interface JSONRPCResponse {
jsonrpc: string;
result: Result;
id: string;
}

// Result contains various fields like final execution status, an array of receipts, etc.
export interface Result {
final_execution_status: string;
receipts: Receipt[];
receipts_outcome: ReceiptOutcome[];
status: TransactionStatus;
transaction: Transaction;
transaction_outcome: TransactionOutcome;
}

// Define Receipt type with its structure
interface Receipt {
predecessor_id: string;
receipt: ReceiptDetail;
receipt_id: string;
receiver_id: string;
}

// Detailed structure of a receipt which includes actions and other properties
interface ReceiptDetail {
Action: ActionDetail;
}

// Actions within the receipt
interface ActionDetail {
actions: Action[];
gas_price: string;
input_data_ids: any[];

Check failure on line 35 in src/types/rpc.ts

View workflow job for this annotation

GitHub Actions / types

Unexpected any. Specify a different type
output_data_receivers: any[];

Check failure on line 36 in src/types/rpc.ts

View workflow job for this annotation

GitHub Actions / types

Unexpected any. Specify a different type
signer_id: string;
signer_public_key: string;
}

// Action can have different types like FunctionCall or Transfer
interface Action {
FunctionCall?: FunctionCall;
Transfer?: Transfer;
}

// FunctionCall action specifics
interface FunctionCall {
args: string;
deposit: string;
gas: number;
method_name: string;
}

// Transfer action specifics
interface Transfer {
deposit: string;
}

// Receipt outcomes are listed in an array
export interface ReceiptOutcome {
block_hash: string;
id: string;
outcome: Outcome;
proof: Proof[];
}

// Outcome of executing the action
interface Outcome {
executor_id: string;
gas_burnt: number;
logs: string[];
metadata: Metadata;
receipt_ids: string[];
status: OutcomeStatus;
tokens_burnt: string;
}

// Metadata may contain various gas profiling information
interface Metadata {
gas_profile: GasProfile[];
version: number;
}

// Detailed gas usage per action or computation step
interface GasProfile {
cost: string;
cost_category: string;
gas_used: number;
}

// Status of the outcome, success or failure specifics
interface OutcomeStatus {
SuccessReceiptId?: string;
SuccessValue?: string;
}

// Proofs for the transaction validation
interface Proof {
direction: string;
hash: string;
}

// Status field detailing the transaction execution result
interface TransactionStatus {
SuccessValue: string;
}

// Transaction detail structure
interface Transaction {
actions: TransactionAction[];
hash: string;
nonce: number;
public_key: string;
receiver_id: string;
signature: string;
signer_id: string;
}

// Actions within a transaction
interface TransactionAction {
FunctionCall: FunctionCall;
}

// Transaction outcome mirrors structure similar to receipt outcomes
interface TransactionOutcome {
block_hash: string;
id: string;
outcome: Outcome;
proof: Proof[];
}
87 changes: 87 additions & 0 deletions src/types/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import { MultichainContract } from "../mpcContract";
import { FunctionCallAction } from "@near-wallet-selector/core";
import BN from "bn.js";
import { Hex } from "viem";

export interface BaseTx {
/// Recipient of the transaction
to: `0x${string}`;
/// ETH value of transaction
value?: bigint;
/// Call Data of the transaction
data?: `0x${string}`;
/// integer ID of the network for the transaction.
chainId: number;
/// Specified transaction nonce
nonce?: number;
}

export interface NearEthAdapterParams {
/// 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;
}

export interface GasPrices {
maxFeePerGas: bigint;
maxPriorityFeePerGas: bigint;
}

/// Near Contract Type for change methods
export interface ChangeMethodArgs<T> {
/// Change method function agruments.
args: T;
/// GasLimit on transaction execution.
gas: BN;
/// Deposit (i.e. payable amount) to attach to transaction.
attachedDeposit: BN;
}

/**
* Arguments required for signature request from MPC Contract
* cf. https://github.com/near/mpc-recovery/blob/ac040bcbb31ba9362a6641a5899647105a53ee4a/contract/src/lib.rs#L297-L320
*/
export interface SignArgs {
/// Derivation Path of for ETH account associated with Near AccountId
path: string;
/// Serialized Ethereum Transaction Bytes.
payload: number[];
/// version number associated with derived ETH Address (must be increasing).
key_version: number;
}

export interface TxPayload {
/// Deserialized Ethereum Transaction.
transaction: Hex;
/// Arguments required by Near MPC Contract signature request.
signArgs: SignArgs;
}

export interface NearContractFunctionPayload {
/// Signer of function call.
signerId: string;
/// Transaction Recipient (a Near ContractId).
receiverId: string;
/// Function call actions.
actions: Array<FunctionCallAction>;
}

/**
* Result Type of MPC contract signature request.
* Representing Affine Points on eliptic curve.
*/
export interface MPCSignature {
big_r: string;
big_s: string;
}

/**
* Sufficient data required to construct a signed Ethereum Transaction.
*/
export interface TransactionWithSignature {
/// Unsigned Ethereum transaction data.
transaction: Hex;
/// Representation of the transaction's signature.
signature: MPCSignature;
}
43 changes: 43 additions & 0 deletions src/utils/getSignature.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { JSONRPCResponse, ReceiptOutcome } from "../types/rpc";

export async function signatureFromTxHash(
txHash: string,
accountId: string
): Promise<[string, string]> {
const url: string = "https://archival-rpc.testnet.near.org";
const payload = {
jsonrpc: "2.0",
id: "dontcare",
method: "EXPERIMENTAL_tx_status",
params: [txHash, accountId],
};

// Make the POST request with the fetch API
const response = await fetch(url, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(payload),
});

const jsonResponse = (await response.json()) as JSONRPCResponse;

const receiptsOutcome = jsonResponse.result.receipts_outcome;
const successValues = receiptsOutcome.map(
(outcome: ReceiptOutcome) => outcome.outcome.status.SuccessValue
);

// Find the first non-undefined value
const firstValidValue = successValues.find((value) => value !== undefined);

if (firstValidValue) {
// Decode from base64
const decodedValue = Buffer.from(firstValidValue, "base64").toString(
"utf-8"
);
return JSON.parse(decodedValue);
} else {
throw new Error("No valid values found in the array.");
}
}
9 changes: 9 additions & 0 deletions tests/utils.getSignature.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { signatureFromTxHash } from "../src/utils/getSignature";

describe("utility: get Signature", () => {
it("signatureFromTxHash", async () => {
const hash = "88LS5pkj99pd6B6noZU6sagQ1QDwHHoSy3qpHr5xLNsR";
const sig = await signatureFromTxHash(hash, "neareth-dev.testnet");
console.log(sig);
});
});

0 comments on commit 2686602

Please sign in to comment.