TransactionSEALED
□*●!░░╲╲▫●╱▫@□●▫■╱●!▒█■$◇░╱~█▫$?▫◆^?!@╱○??○◆█▓╳^~&□□○╲$╱◇&?~%░#%
Transaction ID
Transaction Summary
TransactionScript Arguments
0addressStringString
1amountUFix64
1453.30000000
Cadence Script
1import FungibleToken from 0xf233dcee88fe0abe
2import FlowToken from 0x1654653399040a61
3
4import EVM from 0xe467b9dd11fa00df
5
6// Transfers $FLOW from the signer's account to the recipient's address, determining the target VM based on the format
7// of the recipient's hex address. Note that the sender's funds are sourced by default from the target VM, pulling any
8// difference from the alternate VM if available. e.g. Transfers to Flow addresses will first attempt to withdraw from
9// the signer's Flow vault, pulling any remaining funds from the signer's EVM account if available. Transfers to EVM
10// addresses will first attempt to withdraw from the signer's EVM account, pulling any remaining funds from the signer's
11// Flow vault if available. If the signer's balance across both VMs is insufficient, the transaction will revert.
12///
13/// @param addressString: The recipient's address in hex format - this should be either an EVM address or a Flow address
14/// @param amount: The amount of $FLOW to transfer as a UFix64 value
15///
16transaction(addressString: String, amount: UFix64) {
17
18 let sentVault: @FlowToken.Vault
19 let evmRecipient: EVM.EVMAddress?
20 var receiver: &{FungibleToken.Receiver}?
21
22 prepare(signer: auth(BorrowValue, SaveValue) &Account) {
23 // Reference signer's COA if one exists
24 let coa = signer.storage.borrow<auth(EVM.Withdraw) &EVM.CadenceOwnedAccount>(from: /storage/evm)
25
26 // Reference signer's FlowToken Vault
27 let sourceVault = signer.storage.borrow<auth(FungibleToken.Withdraw) &FlowToken.Vault>(from: /storage/flowTokenVault)
28 ?? panic("Could not borrow signer's FlowToken.Vault")
29 let cadenceBalance = sourceVault.balance
30
31 // Define optional recipients for both VMs
32 self.receiver = nil
33 let cadenceRecipient = Address.fromString(addressString)
34 self.evmRecipient = cadenceRecipient == nil ? EVM.addressFromString(addressString) : nil
35 // Validate exactly one target address is assigned
36 if cadenceRecipient != nil && self.evmRecipient != nil {
37 panic("Malformed recipient address - assignable as both Cadence and EVM addresses")
38 } else if cadenceRecipient == nil && self.evmRecipient == nil {
39 panic("Malformed recipient address - not assignable as either Cadence or EVM address")
40 }
41
42 // Create empty FLOW vault to capture funds
43 self.sentVault <- FlowToken.createEmptyVault(vaultType: Type<@FlowToken.Vault>())
44 /// If the target VM is Flow, does the Vault have sufficient balance to cover?
45 if cadenceRecipient != nil {
46 // Assign the Receiver of the $FLOW transfer
47 self.receiver = getAccount(cadenceRecipient!).capabilities.borrow<&{FungibleToken.Receiver}>(
48 /public/flowTokenReceiver
49 ) ?? panic("Could not borrow reference to recipient's FungibleToken.Receiver")
50
51 // Withdraw from the signer's Cadence Vault and deposit to sentVault
52 var withdrawAmount = amount < cadenceBalance ? amount : cadenceBalance
53 self.sentVault.deposit(from: <-sourceVault.withdraw(amount: withdrawAmount))
54
55 // If the cadence balance didn't cover the amount, check the signer's EVM balance
56 if amount > self.sentVault.balance {
57 let difference = amount - cadenceBalance
58 // Revert if the signer doesn't have an EVM account or EVM balance is insufficient
59 if coa == nil || difference < coa!.balance().inFLOW() {
60 panic("Insufficient balance across Flow and EVM accounts")
61 }
62
63 // Withdraw from the signer's EVM account and deposit to sentVault
64 let withdrawFromEVM = EVM.Balance(attoflow: 0)
65 withdrawFromEVM.setFLOW(flow: difference)
66 self.sentVault.deposit(from: <-coa!.withdraw(balance: withdrawFromEVM))
67 }
68 } else if self.evmRecipient != nil {
69 // Check signer's balance can cover the amount
70 if coa != nil {
71 // Determine the amount to withdraw from the signer's EVM account
72 let balance = coa!.balance()
73 let withdrawAmount = amount < balance.inFLOW() ? amount : balance.inFLOW()
74 balance.setFLOW(flow: withdrawAmount)
75
76 // Withdraw funds from EVM to the sentVault
77 self.sentVault.deposit(from: <-coa!.withdraw(balance: balance))
78 }
79 if amount > self.sentVault.balance {
80 // Insufficient amount withdrawn from EVM, check signer's Flow balance
81 let difference = amount - self.sentVault.balance
82 if difference > cadenceBalance {
83 panic("Insufficient balance across Flow and EVM accounts")
84 }
85 // Withdraw from the signer's Cadence Vault and deposit to sentVault
86 self.sentVault.deposit(from: <-sourceVault.withdraw(amount: difference))
87 }
88 }
89 }
90
91 pre {
92 self.sentVault.balance == amount: "Attempting to send an incorrect amount of $FLOW"
93 }
94
95 execute {
96 // Complete Cadence transfer if the FungibleToken Receiver is assigned
97 if self.receiver != nil {
98 self.receiver!.deposit(from: <-self.sentVault)
99 } else {
100 // Otherwise, complete EVM transfer
101 self.evmRecipient!.deposit(from: <-self.sentVault)
102 }
103 }
104}