1
+ import " EVM"
2
+ import " FungibleToken"
3
+ import " FlowEVMBridgeUtils"
4
+ import " FlowEVMBridgeConfig"
5
+ import " FungibleTokenMetadataViews"
6
+
7
+ /// Returns the balance of the owner of a given Fungible Token
8
+ /// from their Cadence account and their COA
9
+ /// Accepts multiple optional arguments, so the caller can query
10
+ /// the token by its EVM ERC20 address or by its Cadence contract address and name
11
+ ///
12
+ /// @param owner: The Flow address of the owner
13
+ /// @param contractAddressArg: The optional address of the FT contract in Cadence
14
+ /// @param contractNameArg: The optional name of the FT contract in Cadence
15
+ /// @param erc20AddressHex: The optional ERC20 address of the FT to query
16
+ ///
17
+ /// @return An array that contains the balance information for the user's accounts
18
+ /// in this order:
19
+ /// decimals (UInt256), cadence Balance (UFix64), EVM Balance (UInt256), Total Balance (UInt256)
20
+ ///
21
+
22
+ access (all) fun main (
23
+ owner : Address ,
24
+ vaultIdentifier : String ?,
25
+ erc20AddressHexArg : String ?
26
+ ): [AnyStruct ] {
27
+ pre {
28
+ vaultIdentifier == nil ? erc20AddressHexArg ! = nil : true :
29
+ " If the Cadence contract information is not provided, the ERC20 contract address must be provided."
30
+ }
31
+
32
+ var typeIdentifier : String = " "
33
+ var compType : Type ? = nil
34
+ var contractAddress : Address ? = nil
35
+ var contractName : String ? = nil
36
+ var tokenEVMAddress : String ? = nil
37
+ var cadenceBalance : UFix64 = 0 .0
38
+ var cadenceBalanceUInt256 : UInt256 = 0
39
+ var coaBalance : UInt256 = 0
40
+ var decimals : UInt8 = 0
41
+
42
+ // If the caller provided the Cadence information,
43
+ // Construct the composite type
44
+ if vaultIdentifier ! = nil {
45
+ typeIdentifier = vaultIdentifier!
46
+ compType = CompositeType (typeIdentifier)
47
+ ?? panic (" Could not construct Cadence type with \(typeIdentifier)" )
48
+
49
+ // Get the EVM address of the bridged version of the Cadence FT contract
50
+ if let evmAddress = FlowEVMBridgeConfig.getEVMAddressAssociated (with : compType! ) {
51
+ tokenEVMAddress = evmAddress.toString ()
52
+ }
53
+ } else {
54
+ // If the caller provided the EVM information,
55
+ // get the Cadence type from the bridge
56
+ // If getting the Cadence type doesn't work, then we'll just return the EVM balance
57
+ tokenEVMAddress = erc20AddressHexArg!
58
+ let address = EVM.addressFromString (tokenEVMAddress! )
59
+ compType = FlowEVMBridgeConfig.getTypeAssociated (with : address)
60
+ }
61
+
62
+ // Parse the FT identifier into its components if necessary
63
+ if compType ! = nil {
64
+ contractAddress = FlowEVMBridgeUtils.getContractAddress (fromType : compType! )
65
+ contractName = FlowEVMBridgeUtils.getContractName (fromType : compType! )
66
+ }
67
+
68
+ if let address = contractAddress {
69
+ // Borrow a reference to the FT contract
70
+ let resolverRef = getAccount (address)
71
+ .contracts.borrow< &{FungibleToken}> (name: contractName! )
72
+ ?? panic (" Could not borrow FungibleToken reference to the contract. Make sure the provided contract name ("
73
+ .concat (contractName! ).concat (" ) and address (" ).concat (address.toString ()).concat (" ) are correct!" ))
74
+
75
+ // Use that reference to retrieve the FTView
76
+ let vaultData = resolverRef.resolveContractView (resourceType : nil , viewType : Type< FungibleTokenMetadataViews.FTVaultData> ()) as! FungibleTokenMetadataViews.FTVaultData?
77
+ ?? panic (" Could not resolve FTVaultData view. The " .concat (contractName! )
78
+ .concat (" contract needs to implement the FTVaultData Metadata view in order to execute this transaction." ))
79
+
80
+ // Get the Cadence balance of the token
81
+ cadenceBalance = getAccount (owner).capabilities.borrow< &{FungibleToken.Balance}> (
82
+ vaultData.metadataPath
83
+ )? .balance
84
+ ?? 0 .0
85
+ }
86
+
87
+ // Get the COA from the owner's account
88
+ if let coa = getAuthAccount< auth (BorrowValue) &Account> (owner)
89
+ .storage.borrow< auth (EVM.Call) &EVM.CadenceOwnedAccount> (
90
+ from : / storage/ evm
91
+ )
92
+ {
93
+ if let erc20Address = tokenEVMAddress {
94
+ // Get the COA address
95
+ let coaAddress = coa.address ().toString ()
96
+
97
+ // Get the ERC20 balance of the COA
98
+ coaBalance = FlowEVMBridgeUtils.balanceOf (
99
+ owner : EVM.addressFromString (coaAddress),
100
+ evmContractAddress : EVM.addressFromString (erc20Address)
101
+ )
102
+
103
+ if cadenceBalance ! = 0 .0 {
104
+ // Convert the Cadence balance to UInt256
105
+ cadenceBalanceUInt256 = FlowEVMBridgeUtils.convertCadenceAmountToERC20Amount (
106
+ cadenceBalance,
107
+ erc20Address : EVM.addressFromString (erc20Address)
108
+ )
109
+ }
110
+
111
+ // Get the token decimals of the ERC20 contract
112
+ decimals = FlowEVMBridgeUtils.getTokenDecimals (
113
+ evmContractAddress : EVM.addressFromString (erc20Address)
114
+ )
115
+ }
116
+ }
117
+
118
+ let balances = [decimals, cadenceBalance, coaBalance, cadenceBalanceUInt256+ coaBalance]
119
+
120
+ return balances
121
+ }
0 commit comments