Skip to content

Commit fe78417

Browse files
authored
API: Experimental full assets for account endpoint. (#5948)
Co-authored-by: Jason Paulos <jasonpaulos@users.noreply.github.com> Includes migration/addition of new ctype column on the resources table.
1 parent ff2c966 commit fe78417

File tree

32 files changed

+2782
-1379
lines changed

32 files changed

+2782
-1379
lines changed

cmd/goal/account.go

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,9 @@ var (
7171
listAccountInfo bool
7272
onlyShowAssetIds bool
7373
partKeyIDToDelete string
74+
75+
next string
76+
limit uint64
7477
)
7578

7679
func init() {
@@ -79,6 +82,7 @@ func init() {
7982
accountCmd.AddCommand(listCmd)
8083
accountCmd.AddCommand(renameCmd)
8184
accountCmd.AddCommand(infoCmd)
85+
accountCmd.AddCommand(assetDetailsCmd)
8286
accountCmd.AddCommand(balanceCmd)
8387
accountCmd.AddCommand(rewardsCmd)
8488
accountCmd.AddCommand(changeOnlineCmd)
@@ -136,6 +140,12 @@ func init() {
136140
infoCmd.MarkFlagRequired("address")
137141
infoCmd.Flags().BoolVar(&onlyShowAssetIds, "onlyShowAssetIds", false, "Only show ASA IDs and not pull asset metadata")
138142

143+
// Asset details flags
144+
assetDetailsCmd.Flags().StringVarP(&accountAddress, "address", "a", "", "Account address to look up (required)")
145+
assetDetailsCmd.MarkFlagRequired("address")
146+
assetDetailsCmd.Flags().StringVarP(&next, "next", "n", "", "The next asset index to use for pagination")
147+
assetDetailsCmd.Flags().Uint64VarP(&limit, "limit", "l", 0, "The maximum number of assets to return")
148+
139149
// Balance flags
140150
balanceCmd.Flags().StringVarP(&accountAddress, "address", "a", "", "Account address to retrieve balance (required)")
141151
balanceCmd.MarkFlagRequired("address")
@@ -539,6 +549,33 @@ var listCmd = &cobra.Command{
539549
},
540550
}
541551

552+
var assetDetailsCmd = &cobra.Command{
553+
Use: "assetdetails",
554+
Short: "Retrieve information about the assets belonging to the specified account inclusive of asset metadata",
555+
Long: `Retrieve information about the assets the specified account has created or opted into, inclusive of asset metadata.`,
556+
Args: validateNoPosArgsFn,
557+
Run: func(cmd *cobra.Command, args []string) {
558+
dataDir := datadir.EnsureSingleDataDir()
559+
client := ensureAlgodClient(dataDir)
560+
561+
var nextPtr *string
562+
var limitPtr *uint64
563+
if next != "" {
564+
nextPtr = &next
565+
}
566+
if limit != 0 {
567+
limitPtr = &limit
568+
}
569+
response, err := client.AccountAssetsInformation(accountAddress, nextPtr, limitPtr)
570+
571+
if err != nil {
572+
reportErrorf(errorRequestFail, err)
573+
}
574+
575+
printAccountAssetsInformation(accountAddress, response)
576+
577+
},
578+
}
542579
var infoCmd = &cobra.Command{
543580
Use: "info",
544581
Short: "Retrieve information about the assets and applications belonging to the specified account",
@@ -731,6 +768,48 @@ func printAccountInfo(client libgoal.Client, address string, onlyShowAssetIds bo
731768
return hasError
732769
}
733770

771+
func printAccountAssetsInformation(address string, response model.AccountAssetsInformationResponse) {
772+
fmt.Printf("Account: %s\n", address)
773+
fmt.Printf("Round: %d\n", response.Round)
774+
if response.NextToken != nil {
775+
fmt.Printf("NextToken (to retrieve more account assets): %s\n", *response.NextToken)
776+
}
777+
fmt.Printf("Assets:\n")
778+
for _, asset := range *response.AssetHoldings {
779+
fmt.Printf(" Asset ID: %d\n", asset.AssetHolding.AssetID)
780+
781+
if asset.AssetParams != nil {
782+
amount := assetDecimalsFmt(asset.AssetHolding.Amount, asset.AssetParams.Decimals)
783+
fmt.Printf(" Amount: %s\n", amount)
784+
fmt.Printf(" IsFrozen: %t\n", asset.AssetHolding.IsFrozen)
785+
fmt.Printf(" Asset Params:\n")
786+
fmt.Printf(" Creator: %s\n", asset.AssetParams.Creator)
787+
788+
name := "<unnamed>"
789+
if asset.AssetParams.Name != nil {
790+
_, name = unicodePrintable(*asset.AssetParams.Name)
791+
}
792+
fmt.Printf(" Name: %s\n", name)
793+
794+
units := "units"
795+
if asset.AssetParams.UnitName != nil {
796+
_, units = unicodePrintable(*asset.AssetParams.UnitName)
797+
}
798+
fmt.Printf(" Units: %s\n", units)
799+
fmt.Printf(" Total: %d\n", asset.AssetParams.Total)
800+
fmt.Printf(" Decimals: %d\n", asset.AssetParams.Decimals)
801+
safeURL := ""
802+
if asset.AssetParams.Url != nil {
803+
_, safeURL = unicodePrintable(*asset.AssetParams.Url)
804+
}
805+
fmt.Printf(" URL: %s\n", safeURL)
806+
} else {
807+
fmt.Printf(" Amount (without formatting): %d\n", asset.AssetHolding.Amount)
808+
fmt.Printf(" IsFrozen: %t\n", asset.AssetHolding.IsFrozen)
809+
}
810+
}
811+
}
812+
734813
var balanceCmd = &cobra.Command{
735814
Use: "balance",
736815
Short: "Retrieve the balances for the specified account",

daemon/algod/api/algod.oas2.json

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -344,6 +344,73 @@
344344
}
345345
]
346346
},
347+
"/v2/accounts/{address}/assets": {
348+
"get": {
349+
"description": "Lookup an account's asset holdings.",
350+
"tags": [
351+
"public",
352+
"experimental"
353+
],
354+
"produces": [
355+
"application/json"
356+
],
357+
"schemes": [
358+
"http"
359+
],
360+
"summary": "Get a list of assets held by an account, inclusive of asset params.",
361+
"operationId": "AccountAssetsInformation",
362+
"parameters": [
363+
{
364+
"pattern": "[A-Z0-9]{58}",
365+
"type": "string",
366+
"description": "An account public key",
367+
"name": "address",
368+
"in": "path",
369+
"required": true
370+
},
371+
{
372+
"$ref": "#/parameters/limit"
373+
},
374+
{
375+
"$ref": "#/parameters/next"
376+
}
377+
],
378+
"responses": {
379+
"200": {
380+
"$ref": "#/responses/AccountAssetsInformationResponse"
381+
},
382+
"400": {
383+
"description": "Malformed address",
384+
"schema": {
385+
"$ref": "#/definitions/ErrorResponse"
386+
}
387+
},
388+
"401": {
389+
"description": "Invalid API Token",
390+
"schema": {
391+
"$ref": "#/definitions/ErrorResponse"
392+
}
393+
},
394+
"500": {
395+
"description": "Internal Error",
396+
"schema": {
397+
"$ref": "#/definitions/ErrorResponse"
398+
}
399+
},
400+
"default": {
401+
"description": "Unknown Error"
402+
}
403+
}
404+
},
405+
"parameters": [
406+
{
407+
"type": "string",
408+
"name": "address",
409+
"in": "path",
410+
"required": true
411+
}
412+
]
413+
},
347414
"/v2/accounts/{address}/applications/{application-id}": {
348415
"get": {
349416
"description": "Given a specific account public key and application ID, this call returns the account's application local state and global state (AppLocalState and AppParams, if either exists). Global state will only be returned if the provided address is the application's creator.",
@@ -3087,6 +3154,23 @@
30873154
}
30883155
}
30893156
},
3157+
"AccountAssetHolding": {
3158+
"description": "AccountAssetHolding describes the account's asset holding and asset parameters (if either exist) for a specific asset ID.",
3159+
"type": "object",
3160+
"required": [
3161+
"asset-holding"
3162+
],
3163+
"properties": {
3164+
"asset-holding": {
3165+
"description": "\\[asset\\] Details about the asset held by this account.\n\nThe raw account uses `AssetHolding` for this type.",
3166+
"$ref": "#/definitions/AssetHolding"
3167+
},
3168+
"asset-params": {
3169+
"description": "\\[apar\\] parameters of the asset held by this account.\n\nThe raw account uses `AssetParams` for this type.",
3170+
"$ref": "#/definitions/AssetParams"
3171+
}
3172+
}
3173+
},
30903174
"AccountParticipation": {
30913175
"description": "AccountParticipation describes the parameters used by this account in consensus protocol.",
30923176
"type": "object",
@@ -4818,6 +4902,31 @@
48184902
}
48194903
}
48204904
},
4905+
"AccountAssetsInformationResponse": {
4906+
"description": "AccountAssetsInformationResponse contains a list of assets held by an account.",
4907+
"schema": {
4908+
"type": "object",
4909+
"required": [
4910+
"round"
4911+
],
4912+
"properties": {
4913+
"round": {
4914+
"description": "The round for which this information is relevant.",
4915+
"type": "integer"
4916+
},
4917+
"next-token": {
4918+
"description": "Used for pagination, when making another request provide this token with the next parameter.",
4919+
"type": "string"
4920+
},
4921+
"asset-holdings": {
4922+
"type": "array",
4923+
"items": {
4924+
"$ref": "#/definitions/AccountAssetHolding"
4925+
}
4926+
}
4927+
}
4928+
}
4929+
},
48214930
"AccountApplicationResponse": {
48224931
"description": "AccountApplicationResponse describes the account's application local state and global state (AppLocalState and AppParams, if either exists) for a specific application ID. Global state will only be returned if the provided address is the application's creator.",
48234932
"schema": {

0 commit comments

Comments
 (0)