TransactionSEALED

□*●!░░╲╲▫●╱▫@□●▫■╱●!▒█■$◇░╱~█▫$?▫◆^?!@╱○??○◆█▓╳^~&□□○╲$╱◇&?~%░#%

Transaction ID

Timestamp

Sep 05, 2024, 12:47:02 PM UTC
1y ago

Block Height

86,041,824

Computation

0

Proposerseq:17 key:0

Authorizers

1

Transaction Summary

Transaction

Script 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}