diff --git a/api/errors.go b/api/errors.go index 31f6feff3..2254e443f 100644 --- a/api/errors.go +++ b/api/errors.go @@ -27,7 +27,13 @@ var ( type ErrStorageError struct{ Err error } -func (e ErrStorageError) Error() string { return fmt.Sprintf("storage error: %s", e.Err.Error()) } +func (e ErrStorageError) Error() string { + if e.Err != nil { + return fmt.Sprintf("storage error: %s", e.Err.Error()) + } + // ErrStorageError shouldn't be constructed with a nil Err, but format it just in case. + return "storage error: internal bug, incorrectly instantiated error object with nil" +} func HttpCodeForError(err error) int { errVal := reflect.ValueOf(err) diff --git a/api/spec/v1.yaml b/api/spec/v1.yaml index 90b6dbe67..915718ec8 100644 --- a/api/spec/v1.yaml +++ b/api/spec/v1.yaml @@ -1686,7 +1686,7 @@ components: RuntimeEvmBalance: description: Balance of an account for a specific runtime and EVM token. type: object - required: [balance, token_contract_addr, token_decimals] + required: [balance, token_contract_addr, token_decimals, token_type] properties: balance: <<: *BigIntType @@ -2335,9 +2335,9 @@ components: type: string enum: - ERC20 - - ERC721 - - ERC1155 - - OasisSdk + # Desired support in the future, among others: + # - ERC721 + # - ERC1155 description: | The type of a EVM token. diff --git a/storage/client/client.go b/storage/client/client.go index 12d5d8531..0202bcf68 100644 --- a/storage/client/client.go +++ b/storage/client/client.go @@ -627,7 +627,7 @@ func (c *StorageClient) Account(ctx context.Context, address staking.Address) (* address.String(), ) if queryErr != nil { - return nil, wrapError(err) + return nil, wrapError(queryErr) } defer allowanceRows.Close() @@ -1451,7 +1451,7 @@ func (c *StorageClient) RuntimeTokens(ctx context.Context, p apiTypes.GetRuntime &t.Type, &t.NumHolders, ); err2 != nil { - return nil, wrapError(err) + return nil, wrapError(err2) } ts.EvmTokens = append(ts.EvmTokens, t) diff --git a/storage/client/queries/queries.go b/storage/client/queries/queries.go index 97cc3072a..3ec844648 100644 --- a/storage/client/queries/queries.go +++ b/storage/client/queries/queries.go @@ -440,14 +440,17 @@ const ( tokens.symbol, tokens.decimals, tokens.total_supply, - CASE + CASE -- NOTE: There are two queries that use this CASE via copy-paste; edit both if changing. WHEN tokens.token_type = 20 THEN 'ERC20' + ELSE 'unexpected_other_type' -- Our openapi spec doesn't allow us to output this, but better this than a null value (which causes nil dereference) END AS type, holders.cnt AS num_holders FROM chain.evm_tokens AS tokens JOIN chain.address_preimages AS preimages ON (token_address = preimages.address) JOIN holders USING (token_address) - WHERE (tokens.runtime = $1) + WHERE + (tokens.runtime = $1) AND + tokens.token_type != 0 -- exclude unknown-type tokens; they're often just contracts that emitted Transfer events but don't expose the token ticker, name, balance etc. ORDER BY num_holders DESC LIMIT $2::bigint OFFSET $3::bigint` @@ -470,13 +473,17 @@ const ( balances.token_address AS token_address, tokens.symbol AS token_symbol, tokens.token_name AS token_name, - 'ERC20' AS token_type, -- TODO: fetch from the table once available + CASE -- NOTE: There are two queries that use this CASE via copy-paste; edit both if changing. + WHEN tokens.token_type = 20 THEN 'ERC20' + ELSE 'unexpected_other_type' -- Our openapi spec doesn't allow us to output this, but better this than a null value (which causes nil dereference) + END AS token_type, tokens.decimals AS token_decimals FROM chain.evm_token_balances AS balances JOIN chain.evm_tokens AS tokens USING (runtime, token_address) WHERE runtime = $1 AND - account_address = $2::text AND - balance != 0 + balances.account_address = $2::text AND + tokens.token_type != 0 AND -- exclude unknown-type tokens; they're often just contracts that emitted Transfer events but don't expose the token ticker, name, balance etc. + balances.balance != 0 ORDER BY balance DESC LIMIT 1000 -- To prevent huge responses. Hardcoded because API exposes this as a subfield that does not lend itself to pagination. `