Skip to content

Commit

Permalink
Fix eth_sendTransaction (#2134)
Browse files Browse the repository at this point in the history
  • Loading branch information
jribbink authored Feb 12, 2025
1 parent 070f216 commit 4057abd
Show file tree
Hide file tree
Showing 6 changed files with 47 additions and 19 deletions.
18 changes: 9 additions & 9 deletions packages/fcl-ethereum-provider/src/accounts/account-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
FvmErrorCode,
} from "@onflow/typedefs"
import {
DEFAULT_EVM_GAS_LIMIT,
EVENT_IDENTIFIERS,
EventType,
FLOW_CHAINS,
Expand Down Expand Up @@ -113,9 +114,7 @@ export class AccountManager {

public async authenticate(): Promise<string[]> {
await this.user.authenticate({service: this.service})
return this.getAccounts().then(accounts => {
return accounts
})
return this.getAccounts()
}

public async unauthenticate(): Promise<void> {
Expand Down Expand Up @@ -307,8 +306,9 @@ export class AccountManager {
// Check if the from address matches the authenticated COA address
const expectedCOAAddress = await this.getCOAAddress()
if (
fcl.sansPrefix(from).toLowerCase() !==
fcl.sansPrefix(expectedCOAAddress)?.toLowerCase()
fcl.sansPrefix(from.toLowerCase()) !==
fcl.sansPrefix(expectedCOAAddress?.toLowerCase() || null) &&
!!expectedCOAAddress
) {
throw new Error(
`From address does not match authenticated user address.\nUser: ${expectedCOAAddress}\nFrom: ${from}`
Expand Down Expand Up @@ -353,10 +353,10 @@ export class AccountManager {
cadence: sendTransactionTx(parsedChainId),
limit: 9999,
args: (arg: typeof fcl.arg, t: typeof fcl.t) => [
arg(to, t.String),
arg(data, t.String),
arg(gas, t.UInt64),
arg(value, t.UInt256),
arg(fcl.sansPrefix(to), t.String),
arg(fcl.sansPrefix(data ?? ""), t.String),
arg(BigInt(gas ?? DEFAULT_EVM_GAS_LIMIT).toString(), t.UInt64),
arg(BigInt(value ?? 0).toString(), t.UInt),
],
authz: this.user,
})
Expand Down
2 changes: 1 addition & 1 deletion packages/fcl-ethereum-provider/src/cadence.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ export const sendTransactionTx = (
) => `import EVM from ${getContractAddress(ContractType.EVM, chainId)}
/// Executes the calldata from the signer's COA
transaction(evmContractAddressHex: String, calldata: String, gasLimit: UInt64, value: UInt256) {
transaction(evmContractAddressHex: String, calldata: String, gasLimit: UInt64, value: UInt) {
let evmAddress: EVM.EVMAddress
let coa: auth(EVM.Call) &EVM.CadenceOwnedAccount
Expand Down
4 changes: 4 additions & 0 deletions packages/fcl-ethereum-provider/src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,3 +58,7 @@ export interface TransactionExecutedEvent {
}

export const ACCESS_NODE_API_KEY = "accessNode.api"

// TODO: This is a fixed value matching what is used by Flow Wallet right now.
// We should investigate whether eth_estimateGas can be used (& should be used) to get a more accurate value.
export const DEFAULT_EVM_GAS_LIMIT = BigInt("0x76c0")
Original file line number Diff line number Diff line change
@@ -1,24 +1,38 @@
import {AccountManager} from "../../accounts/account-manager"
import {NetworkManager} from "../../network/network-manager"
import {ethSendTransaction} from "./eth-send-transaction"

jest.mock("../../accounts/account-manager")
jest.mock("../../network/network-manager")

describe("eth_sendTransaction handler", () => {
test("should call the AccountManager to send a transaction", async () => {
const mockAccountManager = new (AccountManager as any)()
mockAccountManager.sendTransaction.mockResolvedValue("0x123456")

const params = {
from: "0x1234",
to: "0x5678",
value: "0x100",
}
const mockNetworkManager = new (NetworkManager as any)()
mockNetworkManager.getChainId.mockResolvedValue(1)

const evmTxHash = await ethSendTransaction(mockAccountManager, params)
const params = [
{
from: "0x1234",
to: "0x5678",
value: "0x100",
},
]

const evmTxHash = await ethSendTransaction(
mockAccountManager,
mockNetworkManager,
params
)

expect(mockAccountManager.sendTransaction).toHaveBeenCalled()
expect(mockAccountManager.sendTransaction).toHaveBeenCalledTimes(1)
expect(mockAccountManager.sendTransaction).toHaveBeenCalledWith(params)
expect(mockAccountManager.sendTransaction).toHaveBeenCalledWith({
...params[0],
chainId: 1,
})
expect(evmTxHash).toEqual("0x123456")
})
})
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
import {AccountManager} from "../../accounts/account-manager"
import {NetworkManager} from "../../network/network-manager"

export async function ethSendTransaction(
accountManager: AccountManager,
networkManager: NetworkManager,
params: any
) {
return await accountManager.sendTransaction(params)
return await accountManager.sendTransaction({
...params[0],
// We pass the chainId to avoid race conditions where the chainId changes
chainId: await networkManager.getChainId(),
})
}
6 changes: 5 additions & 1 deletion packages/fcl-ethereum-provider/src/rpc/rpc-processor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,11 @@ export class RpcProcessor {
case "eth_requestAccounts":
return ethRequestAccounts(this.accountManager, chainId)
case "eth_sendTransaction":
return await ethSendTransaction(this.accountManager, params)
return await ethSendTransaction(
this.accountManager,
this.networkManager,
params
)
case "eth_signTypedData":
case "eth_signTypedData_v3":
case "eth_signTypedData_v4": {
Expand Down

0 comments on commit 4057abd

Please sign in to comment.