Skip to content

Commit

Permalink
decode TxData singular
Browse files Browse the repository at this point in the history
  • Loading branch information
bh2smith committed Oct 2, 2024
1 parent 374b29a commit 30acdf7
Show file tree
Hide file tree
Showing 6 changed files with 183 additions and 12 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
},
"dependencies": {
"@safe-global/safe-gateway-typescript-sdk": "^3.22.2",
"ethers-multisend": "^3.1.0",
"near-api-js": "^5.0.0",
"near-ca": "^0.5.6",
"semver": "^7.6.3",
Expand Down
8 changes: 8 additions & 0 deletions src/lib/multisend.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,3 +58,11 @@ export function encodeMulti(
}),
};
}

export function isMultisendTx(args: readonly unknown[]): boolean {
const to = (args[0] as string).toLowerCase();
return (
to === MULTISEND_141.toLowerCase() ||
to === MULTISEND_CALLONLY_141.toLowerCase()
);
}
46 changes: 44 additions & 2 deletions src/near-safe.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { decodeMulti } from "ethers-multisend";
import { NearConfig } from "near-api-js/lib/near";
import { FinalExecutionOutcome } from "near-api-js/lib/providers";
import {
Expand All @@ -9,14 +10,22 @@ import {
toPayload,
PersonalSignParams,
} from "near-ca";
import { Address, Hash, Hex, serializeSignature } from "viem";
import {
Address,
decodeFunctionData,
formatEther,
Hash,
Hex,
serializeSignature,
} from "viem";

import { Erc4337Bundler } from "./lib/bundler";
import { encodeMulti } from "./lib/multisend";
import { encodeMulti, isMultisendTx } from "./lib/multisend";
import { SafeContractSuite } from "./lib/safe";
import { decodeSafeMessage } from "./lib/safe-message";
import {
EncodedTxData,
EvmTransactionData,
MetaTransaction,
UserOperation,
UserOperationReceipt,
Expand Down Expand Up @@ -243,6 +252,39 @@ export class NearSafe {
);
}

decodeTxData(data: EvmTransactionData): {
chainId: number;
costEstimate: string;
transactions: MetaTransaction[];
} {
// TODO: data.data may not always parse to UserOperation. We will have to handle the other cases.
const userOp: UserOperation = JSON.parse(data.data);
const { callGasLimit, maxFeePerGas, maxPriorityFeePerGas } = userOp;
const maxGasPrice = BigInt(maxFeePerGas) + BigInt(maxPriorityFeePerGas);
const { args } = decodeFunctionData({
abi: this.safePack.m4337.abi,
data: userOp.callData,
});

// Determine if sungular or double!
const transactions = isMultisendTx(args)
? decodeMulti(args[2] as string)
: [
{
to: args[0],
value: args[1],
data: args[2],
operation: args[3],
} as MetaTransaction,
];
return {
chainId: data.chainId,
// This is an upper bound on the gas fees (could be lower)
costEstimate: formatEther(BigInt(callGasLimit) * maxGasPrice),
transactions,
};
}

/**
* Handles routing of signature requests based on the provided method, chain ID, and parameters.
*
Expand Down
15 changes: 9 additions & 6 deletions src/types.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { FunctionCallTransaction, SignArgs } from "near-ca";
import { Address, Hash, Hex, ParseAbi, TransactionSerializable } from "viem";
import { Address, Hex, ParseAbi } from "viem";

export type SafeDeployments = {
singleton: Deployment;
Expand Down Expand Up @@ -115,12 +115,15 @@ export interface MetaTransaction {
readonly data: string;
readonly operation?: OperationType;
}

export interface EvmTransactionData {
chainId: number;
data: string;
hash: string;
}

export interface EncodedTxData {
evmData: {
chainId: number;
data: string | TransactionSerializable;
hash: Hash;
};
evmData: EvmTransactionData;
nearPayload: FunctionCallTransaction<{
request: SignArgs;
}>;
Expand Down
42 changes: 42 additions & 0 deletions tests/unit/nearsafe.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { NearSafe } from "../../src";
describe("NearSafe", () => {
it("decodeTxData (singular)", async () => {
const adapter = await NearSafe.create({
accountId: "neareth-dev.testnet",
mpcContractId: "v1.signer-prod.testnet",
pimlicoKey: "dummyKey",
});
const txData = {
chainId: 11155111,
data: JSON.stringify({
sender: "0x4184cabfD63Da66828dE8486FE20DC015D800BbB",
nonce: "0xc",
callData:
"0x7bb374280000000000000000000000008d99f8b2710e6a3b94d9bf465a98e5273069acbd0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002B00B000000000000000000000000000000000000000000000000000000000000",
maxFeePerGas: "0x3575104828",
maxPriorityFeePerGas: "0x47868c00",
paymaster: "0x0000000000000039cd5e8aE05257CE51C473ddd1",
paymasterData:
"0x00000066fd3196000000000000ec1da1a540e872a6b82ad0e5622ff24e06f5a928477aa2f3c9655c1a92c2ed7f153b8bcb8e5ad52f734a58d498b60d58bd307f1d2ccbd5115f09773d804cbc0c1b",
preVerificationGas: "0xd257",
verificationGasLimit: "0x138b1",
callGasLimit: "0x14a6a",
paymasterVerificationGasLimit: "0x6c8e",
paymasterPostOpGasLimit: "0x1",
}),
hash: "0xfcfe9c2a4a5faade2bb5e9e483eece0fee77760db1698a6eb8060d1d33c56377",
};
expect(adapter.decodeTxData(txData)).toStrictEqual({
chainId: 11155111,
costEstimate: "0.019522217711724688",
transactions: [
{
data: "0xb00b",
operation: 0,
to: "0x8d99F8b2710e6A3B94d9bf465A98E5273069aCBd",
value: 0n,
},
],
});
});
});
83 changes: 79 additions & 4 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -479,7 +479,22 @@
dependencies:
levn "^0.4.1"

"@ethersproject/abstract-provider@^5.7.0":
"@ethersproject/abi@^5.0.0", "@ethersproject/abi@^5.7.0":
version "5.7.0"
resolved "https://registry.yarnpkg.com/@ethersproject/abi/-/abi-5.7.0.tgz#b3f3e045bbbeed1af3947335c247ad625a44e449"
integrity sha512-351ktp42TiRcYB3H1OP8yajPeAQstMW/yCFokj/AthP9bLHzQFPlOrxOcwYEDkUAICmOHljvN4K39OMTMUa9RA==
dependencies:
"@ethersproject/address" "^5.7.0"
"@ethersproject/bignumber" "^5.7.0"
"@ethersproject/bytes" "^5.7.0"
"@ethersproject/constants" "^5.7.0"
"@ethersproject/hash" "^5.7.0"
"@ethersproject/keccak256" "^5.7.0"
"@ethersproject/logger" "^5.7.0"
"@ethersproject/properties" "^5.7.0"
"@ethersproject/strings" "^5.7.0"

"@ethersproject/abstract-provider@^5.5.1", "@ethersproject/abstract-provider@^5.7.0":
version "5.7.0"
resolved "https://registry.yarnpkg.com/@ethersproject/abstract-provider/-/abstract-provider-5.7.0.tgz#b0a8550f88b6bf9d51f90e4795d48294630cb9ef"
integrity sha512-R41c9UkchKCpAqStMYUpdunjo3pkEvZC3FAwZn5S5MGbXoMQOHIdHItezTETxAO5bevtMApSyEhn9+CHcDsWBw==
Expand All @@ -503,7 +518,7 @@
"@ethersproject/logger" "^5.7.0"
"@ethersproject/properties" "^5.7.0"

"@ethersproject/address@^5.7.0":
"@ethersproject/address@^5.0.0", "@ethersproject/address@^5.7.0":
version "5.7.0"
resolved "https://registry.yarnpkg.com/@ethersproject/address/-/address-5.7.0.tgz#19b56c4d74a3b0a46bfdbb6cfcc0a153fc697f37"
integrity sha512-9wYhYt7aghVGo758POM5nqcOMaE168Q6aRLJZwUmiqSrAungkG74gSSeKEIR7ukixesdRZGPgVqme6vmxs1fkA==
Expand All @@ -521,7 +536,7 @@
dependencies:
"@ethersproject/bytes" "^5.7.0"

"@ethersproject/bignumber@^5.7.0":
"@ethersproject/bignumber@^5.0.0", "@ethersproject/bignumber@^5.7.0":
version "5.7.0"
resolved "https://registry.yarnpkg.com/@ethersproject/bignumber/-/bignumber-5.7.0.tgz#e2f03837f268ba655ffba03a57853e18a18dc9c2"
integrity sha512-n1CAdIHRWjSucQO3MC1zPSVgV/6dy/fjL9pMrPP9peL+QxEg9wOsVqwD4+818B6LUEtaXzVHQiuivzRoxPxUGw==
Expand All @@ -530,7 +545,7 @@
"@ethersproject/logger" "^5.7.0"
bn.js "^5.2.1"

"@ethersproject/bytes@^5.7.0":
"@ethersproject/bytes@^5.0.0", "@ethersproject/bytes@^5.7.0":
version "5.7.0"
resolved "https://registry.yarnpkg.com/@ethersproject/bytes/-/bytes-5.7.0.tgz#a00f6ea8d7e7534d6d87f47188af1148d71f155d"
integrity sha512-nsbxwgFXWh9NyYWo+U8atvmMsSdKJprTcICAkvbBffT75qDocbuggBU0SJiVK2MuTrp0q+xvLkTnGMPK1+uA9A==
Expand All @@ -544,6 +559,22 @@
dependencies:
"@ethersproject/bignumber" "^5.7.0"

"@ethersproject/contracts@^5.5.0":
version "5.7.0"
resolved "https://registry.yarnpkg.com/@ethersproject/contracts/-/contracts-5.7.0.tgz#c305e775abd07e48aa590e1a877ed5c316f8bd1e"
integrity sha512-5GJbzEU3X+d33CdfPhcyS+z8MzsTrBGk/sc+G+59+tPa9yFkl6HQ9D6L0QMgNTA9q8dT0XKxxkyp883XsQvbbg==
dependencies:
"@ethersproject/abi" "^5.7.0"
"@ethersproject/abstract-provider" "^5.7.0"
"@ethersproject/abstract-signer" "^5.7.0"
"@ethersproject/address" "^5.7.0"
"@ethersproject/bignumber" "^5.7.0"
"@ethersproject/bytes" "^5.7.0"
"@ethersproject/constants" "^5.7.0"
"@ethersproject/logger" "^5.7.0"
"@ethersproject/properties" "^5.7.0"
"@ethersproject/transactions" "^5.7.0"

"@ethersproject/hash@^5.7.0":
version "5.7.0"
resolved "https://registry.yarnpkg.com/@ethersproject/hash/-/hash-5.7.0.tgz#eb7aca84a588508369562e16e514b539ba5240a7"
Expand Down Expand Up @@ -594,6 +625,15 @@
"@ethersproject/bytes" "^5.7.0"
"@ethersproject/logger" "^5.7.0"

"@ethersproject/sha2@^5.7.0":
version "5.7.0"
resolved "https://registry.yarnpkg.com/@ethersproject/sha2/-/sha2-5.7.0.tgz#9a5f7a7824ef784f7f7680984e593a800480c9fb"
integrity sha512-gKlH42riwb3KYp0reLsFTokByAKoJdgFCwI+CCiX/k+Jm2mbNs6oOaCjYQSlI1+XBVejwH2KrmCbMAT/GnRDQw==
dependencies:
"@ethersproject/bytes" "^5.7.0"
"@ethersproject/logger" "^5.7.0"
hash.js "1.1.7"

"@ethersproject/signing-key@^5.7.0":
version "5.7.0"
resolved "https://registry.yarnpkg.com/@ethersproject/signing-key/-/signing-key-5.7.0.tgz#06b2df39411b00bc57c7c09b01d1e41cf1b16ab3"
Expand All @@ -606,6 +646,18 @@
elliptic "6.5.4"
hash.js "1.1.7"

"@ethersproject/solidity@^5.0.0":
version "5.7.0"
resolved "https://registry.yarnpkg.com/@ethersproject/solidity/-/solidity-5.7.0.tgz#5e9c911d8a2acce2a5ebb48a5e2e0af20b631cb8"
integrity sha512-HmabMd2Dt/raavyaGukF4XxizWKhKQ24DoLtdNbBmNKUOPqwjsKQSdV9GQtj9CBEea9DlzETlVER1gYeXXBGaA==
dependencies:
"@ethersproject/bignumber" "^5.7.0"
"@ethersproject/bytes" "^5.7.0"
"@ethersproject/keccak256" "^5.7.0"
"@ethersproject/logger" "^5.7.0"
"@ethersproject/sha2" "^5.7.0"
"@ethersproject/strings" "^5.7.0"

"@ethersproject/strings@^5.7.0":
version "5.7.0"
resolved "https://registry.yarnpkg.com/@ethersproject/strings/-/strings-5.7.0.tgz#54c9d2a7c57ae8f1205c88a9d3a56471e14d5ed2"
Expand All @@ -630,6 +682,15 @@
"@ethersproject/rlp" "^5.7.0"
"@ethersproject/signing-key" "^5.7.0"

"@ethersproject/units@^5.0.0":
version "5.7.0"
resolved "https://registry.yarnpkg.com/@ethersproject/units/-/units-5.7.0.tgz#637b563d7e14f42deeee39245275d477aae1d8b1"
integrity sha512-pD3xLMy3SJu9kG5xDGI7+xhTEmGXlEqXU4OfNapmfnxLVY4EMSSRp7j1k7eezutBPH7RBN/7QPnwR7hzNlEFeg==
dependencies:
"@ethersproject/bignumber" "^5.7.0"
"@ethersproject/constants" "^5.7.0"
"@ethersproject/logger" "^5.7.0"

"@ethersproject/web@^5.7.0":
version "5.7.1"
resolved "https://registry.yarnpkg.com/@ethersproject/web/-/web-5.7.1.tgz#de1f285b373149bee5928f4eb7bcb87ee5fbb4ae"
Expand Down Expand Up @@ -2826,6 +2887,20 @@ esutils@^2.0.2:
resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64"
integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==

ethers-multisend@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/ethers-multisend/-/ethers-multisend-3.1.0.tgz#76d6743904250c8f172635301732fc7e41b48a7b"
integrity sha512-PVfe4v9vs96cAages4yMoEAagOw0Hdh3fHe8IyMnLPNgV8KcGOY1Kv4NYnwB3t7EilnZbQ4jw3Nx0r+1Dc09kw==
dependencies:
"@ethersproject/abi" "^5.0.0"
"@ethersproject/abstract-provider" "^5.5.1"
"@ethersproject/address" "^5.0.0"
"@ethersproject/bignumber" "^5.0.0"
"@ethersproject/bytes" "^5.0.0"
"@ethersproject/contracts" "^5.5.0"
"@ethersproject/solidity" "^5.0.0"
"@ethersproject/units" "^5.0.0"

ethers@^6.13.1:
version "6.13.2"
resolved "https://registry.yarnpkg.com/ethers/-/ethers-6.13.2.tgz#4b67d4b49e69b59893931a032560999e5e4419fe"
Expand Down

0 comments on commit 30acdf7

Please sign in to comment.