github.com/DapperCollectives/CAST/backend@v0.0.0-20230921221157-1350c8be7c96/main/cadence/scripts/get_total_balance.cdc (about) 1 import FlowStorageFees from 0xe467b9dd11fa00df 2 import FungibleToken from 0xf233dcee88fe0abe 3 import FlowToken from 0x1654653399040a61 4 import FlowIDTableStaking from 0x8624b52f9ddcd04a 5 import LockedTokens from 0x8d0e87b65159ae63 6 import FlowStakingCollection from 0x8d0e87b65159ae63 7 8 // This script gets the TOTAL number of FLOW an account owns, across unlocked, locked, and staking. 9 10 // Adds up these numbers: 11 12 // tokens in normal account 13 // tokens in normal account staking 14 // tokens in normal account delegating 15 // tokens in shared account 16 // tokens in shared account staking 17 // tokens in shared account delegating 18 19 pub struct AccountInfo { 20 pub(set) var primaryAcctBalance: UFix64 21 pub(set) var secondaryAddress: Address? 22 pub(set) var secondaryAcctBalance: UFix64 23 pub(set) var stakedBalance: UFix64 24 pub(set) var hasVault: Bool 25 pub(set) var stakes: String 26 27 init() { 28 self.primaryAcctBalance = 0.0 as UFix64 29 self.secondaryAddress = nil 30 self.secondaryAcctBalance = 0.0 as UFix64 31 self.stakedBalance = 0.0 as UFix64 32 self.hasVault = true 33 self.stakes = "" 34 } 35 } 36 37 pub fun getStakesAndDelegations(_ account: PublicAccount) : {String:UFix64} { 38 39 var allNodeInfo: [FlowIDTableStaking.NodeInfo] = [] 40 var allDelegateInfo: [FlowIDTableStaking.DelegatorInfo] = [] 41 42 // ====== Get account stake - Old Way ===== 43 let nodeStakerCap = account.getCapability<&{FlowIDTableStaking.NodeStakerPublic}>( 44 FlowIDTableStaking.NodeStakerPublicPath) 45 if let nodeStakerRef = nodeStakerCap.borrow() { 46 let nodeInfo = FlowIDTableStaking.NodeInfo(nodeID: nodeStakerRef.id) 47 allNodeInfo.append(nodeInfo) 48 } 49 50 // ====== Get account delegation - Old Way ===== 51 let delegatorCap = account.getCapability<&{FlowIDTableStaking.NodeDelegatorPublic}>( 52 /public/flowStakingDelegator) 53 if let delegatorRef = delegatorCap.borrow() { 54 let delegatorInfo = FlowIDTableStaking.DelegatorInfo( 55 nodeID: delegatorRef.nodeID, 56 delegatorID: delegatorRef.id 57 ) 58 allDelegateInfo.append(delegatorInfo) 59 } 60 61 // ====== Get account stakes and delegations ===== 62 var doesAccountHaveStakingCollection = FlowStakingCollection.doesAccountHaveStakingCollection(address: account.address) 63 if doesAccountHaveStakingCollection { 64 allNodeInfo.appendAll(FlowStakingCollection.getAllNodeInfo(address: account.address)) 65 allDelegateInfo.appendAll(FlowStakingCollection.getAllDelegatorInfo(address: account.address)) 66 } 67 68 // ====== Shared account ===== 69 let lockedAccountInfoCap = account 70 .getCapability<&LockedTokens.TokenHolder{LockedTokens.LockedAccountInfo}>( 71 LockedTokens.LockedAccountInfoPublicPath) 72 if let lockedAccountInfoRef = lockedAccountInfoCap.borrow() { 73 // ====== Get shared account stake - Old Way ===== 74 if let nodeID = lockedAccountInfoRef.getNodeID() { 75 let nodeInfo = FlowIDTableStaking.NodeInfo(nodeID: nodeID) 76 allNodeInfo.append(nodeInfo) 77 } 78 79 // ====== Get shared account delegation - Old Way ===== 80 if let delegatorID = lockedAccountInfoRef.getDelegatorID() { 81 if let nodeID = lockedAccountInfoRef.getDelegatorNodeID() { 82 let delegatorInfo = FlowIDTableStaking.DelegatorInfo(nodeID: nodeID, delegatorID: delegatorID) 83 allDelegateInfo.append(delegatorInfo) 84 } 85 } 86 87 // ====== Get shared account stakes and delegations ===== 88 doesAccountHaveStakingCollection = FlowStakingCollection.doesAccountHaveStakingCollection(address: lockedAccountInfoRef.getLockedAccountAddress()) 89 if doesAccountHaveStakingCollection { 90 allNodeInfo.appendAll(FlowStakingCollection.getAllNodeInfo(address: lockedAccountInfoRef.getLockedAccountAddress())) 91 allDelegateInfo.appendAll(FlowStakingCollection.getAllDelegatorInfo(address: lockedAccountInfoRef.getLockedAccountAddress())) 92 } 93 } 94 95 // ===== Aggregate all stakes and delegations in a digestible set ===== 96 // deduplication between the old way and the new way will happen automatically because the result is stored in a map 97 let stakes : {String:UFix64} = {} 98 for nodeInfo in allNodeInfo { 99 let balance = nodeInfo.tokensStaked 100 + nodeInfo.tokensCommitted 101 + nodeInfo.tokensUnstaking 102 + nodeInfo.tokensUnstaked 103 + nodeInfo.tokensRewarded 104 105 stakes["n:".concat(nodeInfo.id)] = balance 106 } 107 108 for delegatorInfo in allDelegateInfo { 109 let balance = delegatorInfo.tokensStaked 110 + delegatorInfo.tokensCommitted 111 + delegatorInfo.tokensUnstaking 112 + delegatorInfo.tokensUnstaked 113 + delegatorInfo.tokensRewarded 114 115 stakes["n:".concat(delegatorInfo.nodeID).concat(" d:").concat(delegatorInfo.id.toString())] = balance 116 } 117 118 return stakes 119 } 120 121 122 pub fun main(address: Address): [AnyStruct] { 123 var info: AccountInfo = AccountInfo() 124 125 let account = getAccount(address) 126 127 // If the account is an unlocked account, lets collect its balances 128 if account.getLinkTarget(/public/lockedFlowTokenReceiver) == nil { 129 info.hasVault = true 130 131 if account.storageUsed > 0 as UInt64 { 132 // Get the primary/normal account balance (unlocked tokens) 133 if let vaultRef = account.getCapability(/public/flowTokenBalance) 134 .borrow<&FlowToken.Vault{FungibleToken.Balance}>(){ 135 info.primaryAcctBalance = vaultRef.balance 136 } 137 // Accounts 0xf8ded0f117ba2462 and 0x3112dbb9973ff3ad have the same locked account 0x1cb9692c064024bd and the same stake id. 138 // This is expected, this was made manually. 0xf8ded0f117ba2462 has all keys revoked, and is safe to skip. 139 if account.address != 0xf8ded0f117ba2462 { 140 141 let lockedAccountInfoCap = account 142 .getCapability<&LockedTokens.TokenHolder{LockedTokens.LockedAccountInfo}>( 143 LockedTokens.LockedAccountInfoPublicPath) 144 145 // Get secondary/locked account address and balance 146 if let lockedAccountInfoRef = lockedAccountInfoCap.borrow() { 147 info.secondaryAddress = lockedAccountInfoRef.getLockedAccountAddress() as Address? 148 // `+ FlowStorageFees.minimumStorageReservation` is due to https://github.com/onflow/flow-core-contracts/blob/6fcd492d16186e5615d2e6589bc5b7ebce41f548/contracts/LockedTokens.cdc#L308 149 info.secondaryAcctBalance = lockedAccountInfoRef.getLockedAccountBalance() + FlowStorageFees.minimumStorageReservation 150 } 151 152 // Get stakes and delegations of the account and secondary/locked account 153 let stakes = getStakesAndDelegations(account) 154 155 var stakeKey = "" 156 for key in stakes.keys { 157 let value = stakes[key]! 158 stakeKey = stakeKey.concat(key).concat(", ") 159 info.stakedBalance = info.stakedBalance + value 160 } 161 info.stakes = stakeKey 162 } 163 } else { 164 info.hasVault = false 165 } 166 } 167 168 return [info.primaryAcctBalance, info.secondaryAcctBalance, info.stakedBalance] 169 }