Skip to content

adding functions to get the total flow balance of an account with all… #23

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 22 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 14 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
147 changes: 147 additions & 0 deletions cadence/contracts/AccountUtils.cdc
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@

import "FungibleToken"
import "FlowToken"
import "FlowIDTableStaking"
import "LockedTokens"
import "FlowStakingCollection"
import "FlowStorageFees"


pub contract AccountUtils {

pub struct AccountInfo {

pub(set) var primaryAddress: Address
pub(set) var primaryAcctBalance: UFix64
pub(set) var secondaryAddress: Address?
pub(set) var secondaryAcctBalance: UFix64
pub(set) var stakedBalance: UFix64

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would probably prefer this to be called nodeStakedBalance just to be consistent on the terminology

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure we can do that. Totally forget about this pr.

pub(set) var delegatedBalance: UFix64

init(_ address:Address) {
self.primaryAddress=address
self.primaryAcctBalance = 0.0
self.secondaryAddress = nil
self.secondaryAcctBalance = 0.0
self.stakedBalance = 0.0
self.delegatedBalance = 0.0
}

pub fun getTotalBalance() :UFix64 {
return self.primaryAcctBalance+self.secondaryAcctBalance+self.stakedBalance+self.delegatedBalance
}
}

/// Get the total flow balance for this account and its linked account
pub fun getTotalFlowBalance(address: Address): UFix64? {

if let info = self.getAccountInfo(address: address) {
return info.getTotalBalance()
}
return nil
}

/// Get the account info for this account
pub fun getAccountInfo(address: Address): AccountInfo?{

var info: AccountInfo = AccountInfo(address)

let account = getAccount(address)
//if balance is 0 the account is not valid
if account.balance == 0.0 {
return nil
}

//TODO: should we return something here
if account.getLinkTarget(/public/lockedFlowTokenReceiver) != nil {
return nil
}

// Get the main Vault balance of this account
if let vaultRef = account.getCapability(/public/flowTokenBalance).borrow<&FlowToken.Vault{FungibleToken.Balance}>(){
info.primaryAcctBalance = vaultRef.balance
}

// Get the locked account associated with the primary account if there is one
if let lockedAccount = account.getCapability(LockedTokens.LockedAccountInfoPublicPath).borrow<&LockedTokens.TokenHolder{LockedTokens.LockedAccountInfo}>() {
}

var allNodeInfo: [FlowIDTableStaking.NodeInfo] = []
var allDelegateInfo: [FlowIDTableStaking.DelegatorInfo] = []


// get all node objects using the original basic node account configuration
if let nodeStaker = account.getCapability<&{FlowIDTableStaking.NodeStakerPublic}>(FlowIDTableStaking.NodeStakerPublicPath).borrow() {
allNodeInfo.append(FlowIDTableStaking.NodeInfo(nodeID: nodeStaker.id))
}

// get all delegator objects using the original basic delegator account configuration
if let delegator = account.getCapability<&{FlowIDTableStaking.NodeDelegatorPublic}>(/public/flowStakingDelegator).borrow() {
allDelegateInfo.append(FlowIDTableStaking.DelegatorInfo(nodeID: delegator.nodeID, delegatorID: delegator.id))
}

// get all nodes/delegators from the staking collection
// includes all nodes and delegators that are in the locked account
var doesAccountHaveStakingCollection = FlowStakingCollection.doesAccountHaveStakingCollection(address: account.address)
if doesAccountHaveStakingCollection {
allNodeInfo.appendAll(FlowStakingCollection.getAllNodeInfo(address: account.address))
allDelegateInfo.appendAll(FlowStakingCollection.getAllDelegatorInfo(address: account.address))
}

// If we have a lockedAccount linked but don't have a staking collection we need to add nodes/delegators there
// If there is a locked account and a staking collection, the staking collection staking information would have already included the locked account
if let lockedAccountInfo = account.getCapability<&LockedTokens.TokenHolder{LockedTokens.LockedAccountInfo}>(LockedTokens.LockedAccountInfoPublicPath).borrow() {

info.secondaryAddress = lockedAccountInfo.getLockedAccountAddress()
info.secondaryAcctBalance = lockedAccountInfo.getLockedAccountBalance() + FlowStorageFees.minimumStorageReservation
if !doesAccountHaveStakingCollection {
if let nodeID = lockedAccountInfo.getNodeID() {
allNodeInfo.append(FlowIDTableStaking.NodeInfo(nodeID: nodeID))
}

if let delegatorID = lockedAccountInfo.getDelegatorID() {
if let nodeID = lockedAccountInfo.getDelegatorNodeID() {
allDelegateInfo.append(FlowIDTableStaking.DelegatorInfo(nodeID: nodeID, delegatorID: delegatorID))
}
}
}
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
}
}
}

adding a closing bracket for the addition of the does account have staking collection conditional above


// ===== Aggregate all stakes and delegations in a digestible set =====

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// ===== Aggregate all stakes and delegations in a digestible set =====
// ===== Aggregate all nodes and delegators in a digestible set =====

// deduplication between the old way and the new way will happen automatically because the result is stored in a map
let nodes : {String:UFix64} = {}
let delegators : {String:UFix64} = {}
for nodeInfo in allNodeInfo {
let balance = nodeInfo.tokensStaked
+ nodeInfo.tokensCommitted
+ nodeInfo.tokensUnstaking
+ nodeInfo.tokensUnstaked
+ nodeInfo.tokensRewarded

nodes["n:".concat(nodeInfo.id)] = balance
}

for delegatorInfo in allDelegateInfo {
let balance = delegatorInfo.tokensStaked
+ delegatorInfo.tokensCommitted
+ delegatorInfo.tokensUnstaking
+ delegatorInfo.tokensUnstaked
+ delegatorInfo.tokensRewarded

delegators["n:".concat(delegatorInfo.nodeID).concat(" d:").concat(delegatorInfo.id.toString())] = balance
}


for key in nodes.keys {
let value = nodes[key]!
info.stakedBalance = info.stakedBalance + value
}

for key in delegators.keys {
let value = delegators[key]!
info.delegatedBalance = info.delegatedBalance + value
}

return info
}
}
66 changes: 62 additions & 4 deletions flow.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,12 @@
"testing": "0x0000000000000007"
}
},
"AccountUtils": {
"source": "./cadence/contracts/AccountUtils.cdc",
"aliases": {
"testing": "0x0000000000000007"
}
},
"ScopedNFTProviders": {
"source": "./cadence/contracts/ScopedNFTProviders.cdc",
"aliases": {
Expand Down Expand Up @@ -71,6 +77,45 @@
"aliases": {
"testing": "0x0000000000000007"
}
},
"FlowToken": {
"aliases": {
"testnet": "0x7e60df042a9c0868",
"emulator": "0x0ae53cb6e3f42a79",
"mainnet": "0x1654653399040a61"
}
},
"FlowIDTableStaking": {
"aliases": {
"testnet": "0x9eca2b38b18b5dfe",
"emulator": "0xf8d6e0586b0a20c7",
"mainnet": "0x8624b52f9ddcd04a"
}
},
"LockedTokens": {
"aliases": {
"mainnet": "0x8d0e87b65159ae63",
"testnet": "0x95e019a17d0e23d7"
}
},
"FlowStakingCollection": {
"aliases": {
"mainnet": "0x8d0e87b65159ae63",
"testnet": "0x95e019a17d0e23d7",
"emulator": "0xf8d6e0586b0a20c7"
}
},
"FlowStakingProxy": {
"aliases": {
"emulator": "0xf8d6e0586b0a20c7"
}
},
"FlowStorageFees": {
"aliases": {
"emulator": "0xf8d6e0586b0a20c7",
"testnet": "0x8c5303eaa26202d6",
"mainnet": "0xe467b9dd11fa00df"
}
}
},
"networks": {
Expand Down Expand Up @@ -103,6 +148,16 @@
"hashAlgorithm": "SHA2_256",
"resourceID": "projects/flow-utils/locations/global/keyRings/contract/cryptoKeys/mainnet/cryptoKeyVersions/1"
}
},
"bjartek": {
"address": "0xa340dc0a4ec828ab",
"key": {
"type": "google-kms",
"index": 1,
"signatureAlgorithm": "ECDSA_P256",
"hashAlgorithm": "SHA2_256",
"resourceID": "projects/bjartek/locations/europe-north1/keyRings/flow/cryptoKeys/flow/cryptoKeyVersions/1"
}
}
},
"deployments": {
Expand All @@ -116,7 +171,8 @@
"ExampleNFT",
"ExampleToken",
"ScopedNFTProviders",
"ScopedFTProviders"
"ScopedFTProviders",
"AccountUtils"
]
},
"testnet": {
Expand All @@ -125,7 +181,8 @@
"StringUtils",
"AddressUtils",
"ScopedNFTProviders",
"ScopedFTProviders"
"ScopedFTProviders",
"AccountUtils"
]
},
"mainnet": {
Expand All @@ -134,8 +191,9 @@
"StringUtils",
"AddressUtils",
"ScopedNFTProviders",
"ScopedFTProviders"
"ScopedFTProviders",
"AccountUtils"
]
}
}
}
}
23 changes: 23 additions & 0 deletions test/AccountUtils_test.cdc
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import Test
import "AccountUtils"

access(all)
fun setup() {
var err = Test.deployContract(
name: "AccountUtils",
path: "../cadence/contracts/AccountUtils.cdc",
arguments: []
)
Test.expect(err, Test.beNil())
}

access(all)
fun testWithoutPrefix() {
// Act
var balance = AccountUtils.getTotalFlowBalance("0xf8d6e0586b0a20c7")


Test.assertEqual(balance, 0.1)

}