Skip to content
Open
Show file tree
Hide file tree
Changes from 2 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
139 changes: 139 additions & 0 deletions cadence/contracts/AccountUtils.cdc
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@

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


pub contract AccountUtils {


//Not really sure what fields to keep here? what is useful?
pub struct AccountInfo {
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.


init() {
self.primaryAcctBalance = 0.0
self.secondaryAddress = nil
self.secondaryAcctBalance = 0.0
self.stakedBalance = 0.0
}
}

pub fun getStakesAndDelegations(_ account: PublicAccount) : {String:UFix64} {

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


//get all stakers in new way
if let nodeStaker = account.getCapability<&{FlowIDTableStaking.NodeStakerPublic}>(FlowIDTableStaking.NodeStakerPublicPath).borrow() {
allNodeInfo.append(FlowIDTableStaking.NodeInfo(nodeID: nodeStaker.id))
}

//get all delegators in new way
if let delegator = account.getCapability<&{FlowIDTableStaking.NodeDelegatorPublic}>(/public/flowStakingDelegator).borrow() {
allDelegateInfo.append(FlowIDTableStaking.DelegatorInfo(nodeID: delegator.nodeID, delegatorID: delegator.id))
}

//get all stakers/delegators from the staking collection
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 we need to add stakings/delegators there
if let lockedAccountInfo = account.getCapability<&LockedTokens.TokenHolder{LockedTokens.LockedAccountInfo}>(LockedTokens.LockedAccountInfoPublicPath).borrow() {
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 stakes : {String:UFix64} = {}
for nodeInfo in allNodeInfo {
let balance = nodeInfo.tokensStaked
+ nodeInfo.tokensCommitted
+ nodeInfo.tokensUnstaking
+ nodeInfo.tokensUnstaked
+ nodeInfo.tokensRewarded

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

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

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

return stakes
}

/// 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.stakedBalance+info.primaryAcctBalance+info.secondaryAcctBalance
}
return nil
}

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

var info: AccountInfo = AccountInfo()

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
}

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


//we get the locked account for this if any
if let lockedAccount = account.getCapability(LockedTokens.LockedAccountInfoPublicPath).borrow<&LockedTokens.TokenHolder{LockedTokens.LockedAccountInfo}>() {
info.secondaryAddress = lockedAccount.getLockedAccountAddress()
// \`+ FlowStorageFees.minimumStorageReservation\` is due to https://github.com/onflow/flow-core-contracts/blob/6fcd492d16186e5615d2e6589bc5b7ebce41f548/contracts/LockedTokens.cdc#L308
info.secondaryAcctBalance = lockedAccount.getLockedAccountBalance() + FlowStorageFees.minimumStorageReservation
}
// Get stakes and delegations of the account and secondary/locked account
let stakes = self.getStakesAndDelegations(account)

var stakeKey = ""
for key in stakes.keys {
let value = stakes[key]!
stakeKey = stakeKey.concat(key).concat(", ")
info.stakedBalance = info.stakedBalance + value
}
//what is worth to keep in the struct?
return info
}
}
45 changes: 44 additions & 1 deletion flow.json
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,39 @@
"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"
}
},
"FlowStorageFees": {
"aliases": {
"emulator": "0xf8d6e0586b0a20c7",
"testnet": "0x8c5303eaa26202d6",
"mainnet": "0xe467b9dd11fa00df"
}
}
},
"networks": {
Expand Down Expand Up @@ -103,6 +136,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 Down Expand Up @@ -138,4 +181,4 @@
]
}
}
}
}