66//
77
88import Foundation
9+ import Flow
910import WalletCore
1011
1112// MARK: - Support EOA
@@ -72,7 +73,7 @@ extension Wallet {
7273 guard let publicKey = PublicKey . recover ( signature: normalizedSignature, message: digest) else {
7374 throw FWKError . invalidEthereumSignature
7475 }
75- let address = AnyAddress ( publicKey: publicKey, coin: . ethereum)
76+ let address = AnyAddress ( publicKey: publicKey, coin: . ethereum)
7677 return address. description
7778 }
7879
@@ -82,7 +83,7 @@ extension Wallet {
8283 var signingInput = input
8384 signingInput. privateKey = try key. ethPrivateKey ( index: index)
8485 defer { signingInput. privateKey = Data ( ) }
85- var output : EthereumSigningOutput = AnySigner . sign ( input: signingInput, coin: . ethereum)
86+ var output : EthereumSigningOutput = AnySigner . sign ( input: signingInput, coin: . ethereum)
8687 let transactionHash = Hash . keccak256 ( data: output. encoded)
8788 output. preHash = transactionHash
8889 return output
@@ -131,4 +132,83 @@ extension Wallet {
131132 }
132133 return ethereumKey
133134 }
135+
136+ /// Sends an EOA-signed Ethereum transaction to Flow EVM through Cadence.
137+ /// - Parameters:
138+ /// - account: Flow account used as proposer/payer/authorizer.
139+ /// - rlpEncodedTransaction: Signed Ethereum transaction payload.
140+ /// - coinbaseAddr: EOA coinbase address.
141+ /// - Returns: Flow transaction ID after submission.
142+ public func ethSendSignedTransactionByCadence( chainId: Flow . ChainID = . mainnet,
143+ account: Flow . Address ,
144+ rlpEncodedTransaction: Data ,
145+ coinbaseAddr: String ,
146+ signers: [ FlowSigner ] ,
147+ payer: Flow . Address ? = nil
148+ ) async throws -> Flow . ID {
149+ try await flow. runEVMTransaction (
150+ chainID: chainId,
151+ proposer: account,
152+ payer: payer ?? account,
153+ rlpEncodedTransaction: Array ( rlpEncodedTransaction) ,
154+ coinbaseAddress: coinbaseAddr,
155+ signers: signers
156+ )
157+ }
158+
159+ /// Sign an Ethereum transaction (WalletCore input) and submit it to Flow EVM via Cadence.
160+ /// Returns both the Flow transaction ID and the EVM transaction hash.
161+ /// - Parameters:
162+ /// - chain: Flow EVM chain (mainnet/testnet only).
163+ /// - input: Unsigned Ethereum signing input; chainId is set automatically based on `chain`.
164+ /// - fromAddress: Expected EOA sender/coinbase; must match the wallet's derived address for `index`.
165+ /// - signers: Flow signers (proposer/authorizers/payer).
166+ /// - flowAddress: Optional Flow address for proposer/payer; defaults to the first signer address.
167+ /// - payer: Optional custom payer; defaults to proposer.
168+ /// - index: HD derivation index for EVM key (defaults to 0).
169+ /// - Returns: `FlowEVMSubmitResult` containing Flow tx id and EVM tx hash (0x-prefixed).
170+ public func ethSignTransactionAndSendByCadence(
171+ chain: EVMChain = . flowMainnet,
172+ input: EthereumSigningInput ,
173+ fromAddress: String ,
174+ signers: [ FlowSigner ] ,
175+ flowAddress: Flow . Address ? = nil ,
176+ payer: Flow . Address ? = nil ,
177+ index: UInt32 = 0
178+ ) async throws -> FlowEVMSubmitResult {
179+ guard case . key = type else {
180+ throw FWKError . invaildWalletType
181+ }
182+ guard !signers. isEmpty else {
183+ throw FWKError . emptySignKey
184+ }
185+
186+ var signingInput = input
187+ signingInput. chainID = chain. chainIdData
188+ guard let fromAddr = AnyAddress ( string: fromAddress, coin: . ethereum) else {
189+ throw FWKError . invaildEVMAddress
190+ }
191+ let derivedAddr = try ethAddress ( index: index)
192+ guard fromAddr. description. lowercased ( ) == derivedAddr. lowercased ( ) else {
193+ throw FWKError . invaildEVMAddress
194+ }
195+
196+ let signed = try ethSignTransaction ( signingInput, index: index)
197+ guard let flowChainID = chain. flowChainID else {
198+ throw FWKError . unsupportedEVMChain
199+ }
200+ guard let proposer = flowAddress ?? signers. first? . address else {
201+ throw FWKError . emptyFlowAddress
202+ }
203+ let flowTxId = try await ethSendSignedTransactionByCadence (
204+ chainId: flowChainID,
205+ account: proposer,
206+ rlpEncodedTransaction: signed. encoded,
207+ coinbaseAddr: fromAddr. description,
208+ signers: signers,
209+ payer: payer ?? proposer
210+ )
211+ let flowTxIdString = String ( describing: flowTxId)
212+ return FlowEVMSubmitResult ( flowTxId: flowTxIdString, evmTxId: signed. txIdHex ( ) )
213+ }
134214}
0 commit comments