Skip to content

Commit

Permalink
Merge pull request #529 from oasisprotocol/pro-wh/feature/holders15
Browse files Browse the repository at this point in the history
NFT query by owner
  • Loading branch information
pro-wh authored Oct 16, 2023
2 parents d1d6475 + 6c11561 commit a73a548
Show file tree
Hide file tree
Showing 10 changed files with 354 additions and 13 deletions.
31 changes: 31 additions & 0 deletions api/spec/v1.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1080,6 +1080,29 @@ paths:
$ref: '#/components/schemas/RuntimeAccount'
<<: *common_error_responses

/{runtime}/accounts/{address}/nfts:
get:
summary: |
Returns the list of non-fungible token (NFT) instances owned by an account.
parameters:
- *limit
- *offset
- *runtime
- in: path
name: address
required: true
schema:
<<: *StakingAddressType
description: The staking address of the owner of the NFT instances.
responses:
'200':
description: The requested instances.
content:
application/json:
schema:
$ref: '#/components/schemas/EvmNftList'
<<: *common_error_responses

/{runtime}/status:
get:
summary: Returns the runtime status.
Expand Down Expand Up @@ -2621,6 +2644,14 @@ components:
id:
<<: *BigIntType
description: The instance ID of this NFT within the collection represented by `token`.
owner:
<<: *AddressType
description: The Oasis address of this NFT instance's owner.
example: "oasis1qpclnnm0wu44pn43mt6vv3me59kl8zk9ty7qyj03"
owner_eth:
type: string
description: The Ethereum address of this NFT instance's owner.
example: "0xDEF1009df2d6872C214cd9148c6883893B7c4D91"
metadata_uri:
type: string
metadata_accessed:
Expand Down
10 changes: 9 additions & 1 deletion api/v1/strict_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -291,7 +291,7 @@ func (srv *StrictServerImpl) GetRuntimeEvmTokensAddressHolders(ctx context.Conte
}

func (srv *StrictServerImpl) GetRuntimeEvmTokensAddressNfts(ctx context.Context, request apiTypes.GetRuntimeEvmTokensAddressNftsRequestObject) (apiTypes.GetRuntimeEvmTokensAddressNftsResponseObject, error) {
nfts, err := srv.dbClient.RuntimeEVMNFTs(ctx, request.Params, request.Address)
nfts, err := srv.dbClient.RuntimeEVMNFTs(ctx, request.Params.Limit, request.Params.Offset, &request.Address, nil)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -333,6 +333,14 @@ func (srv *StrictServerImpl) GetRuntimeAccountsAddress(ctx context.Context, requ
return apiTypes.GetRuntimeAccountsAddress200JSONResponse(*account), nil
}

func (srv *StrictServerImpl) GetRuntimeAccountsAddressNfts(ctx context.Context, request apiTypes.GetRuntimeAccountsAddressNftsRequestObject) (apiTypes.GetRuntimeAccountsAddressNftsResponseObject, error) {
nfts, err := srv.dbClient.RuntimeEVMNFTs(ctx, request.Params.Limit, request.Params.Offset, nil, &request.Address)
if err != nil {
return nil, err
}
return apiTypes.GetRuntimeAccountsAddressNfts200JSONResponse(*nfts), nil
}

func (srv *StrictServerImpl) GetRuntimeStatus(ctx context.Context, request apiTypes.GetRuntimeStatusRequestObject) (apiTypes.GetRuntimeStatusResponseObject, error) {
if !request.Runtime.IsValid() {
return nil, &apiTypes.InvalidParamFormatError{ParamName: "runtime", Err: fmt.Errorf("not a valid enum value: %s", request.Runtime)}
Expand Down
20 changes: 16 additions & 4 deletions storage/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -1551,14 +1551,15 @@ func (c *StorageClient) RuntimeTokenHolders(ctx context.Context, p apiTypes.GetR
return &hs, nil
}

func (c *StorageClient) RuntimeEVMNFTs(ctx context.Context, p apiTypes.GetRuntimeEvmTokensAddressNftsParams, address staking.Address) (*EvmNftList, error) {
func (c *StorageClient) RuntimeEVMNFTs(ctx context.Context, limit *uint64, offset *uint64, tokenAddress *staking.Address, ownerAddress *staking.Address) (*EvmNftList, error) {
res, err := c.withTotalCount(
ctx,
queries.EvmNfts,
runtimeFromCtx(ctx),
address,
p.Limit,
p.Offset,
tokenAddress,
ownerAddress,
limit,
offset,
)
if err != nil {
return nil, wrapError(err)
Expand All @@ -1576,6 +1577,9 @@ func (c *StorageClient) RuntimeEVMNFTs(ctx context.Context, p apiTypes.GetRuntim
var contractAddrContextVersion int
var contractAddrData []byte
var tokenType sql.NullInt32
var ownerAddrContextIdentifier string
var ownerAddrContextVersion int
var ownerAddrData []byte
var metadataAccessedN sql.NullTime
if err = res.rows.Scan(
&nft.Token.ContractAddr,
Expand All @@ -1591,6 +1595,10 @@ func (c *StorageClient) RuntimeEVMNFTs(ctx context.Context, p apiTypes.GetRuntim
&nft.Token.NumHolders,
&nft.Token.IsVerified,
&nft.Id,
&nft.Owner,
&ownerAddrContextIdentifier,
&ownerAddrContextVersion,
&ownerAddrData,
&nft.MetadataUri,
&metadataAccessedN,
&nft.Name,
Expand All @@ -1606,6 +1614,10 @@ func (c *StorageClient) RuntimeEVMNFTs(ctx context.Context, p apiTypes.GetRuntim
if tokenType.Valid {
nft.Token.Type = translateTokenType(common.TokenType(tokenType.Int32))
}
if ownerEthAddr, err1 := EVMEthAddrFromPreimage(ownerAddrContextIdentifier, ownerAddrContextVersion, ownerAddrData); err1 == nil {
ownerECAddr := ethCommon.BytesToAddress(ownerEthAddr)
nft.OwnerEth = common.Ptr(ownerECAddr.String())
}
if metadataAccessedN.Valid {
nft.MetadataAccessed = common.Ptr(metadataAccessedN.Time.String())
}
Expand Down
23 changes: 15 additions & 8 deletions storage/client/queries/queries.go
Original file line number Diff line number Diff line change
Expand Up @@ -504,9 +504,9 @@ const (
)
SELECT
chain.evm_nfts.token_address,
chain.address_preimages.context_identifier,
chain.address_preimages.context_version,
chain.address_preimages.address_data,
token_preimage.context_identifier,
token_preimage.context_version,
token_preimage.address_data,
chain.evm_tokens.token_name,
chain.evm_tokens.symbol,
chain.evm_tokens.decimals,
Expand All @@ -516,25 +516,32 @@ const (
COALESCE(token_holders.num_holders, 0) AS num_holders,
chain.evm_contracts.verification_info_downloaded_at IS NOT NULL AS is_verified,
chain.evm_nfts.nft_id,
chain.evm_nfts.owner,
owner_preimage.context_identifier,
owner_preimage.context_version,
owner_preimage.address_data,
chain.evm_nfts.metadata_uri,
chain.evm_nfts.metadata_accessed,
chain.evm_nfts.name,
chain.evm_nfts.description,
chain.evm_nfts.image
FROM chain.evm_nfts
LEFT JOIN chain.address_preimages ON
chain.address_preimages.address = chain.evm_nfts.token_address
LEFT JOIN chain.address_preimages AS token_preimage ON
token_preimage.address = chain.evm_nfts.token_address
LEFT JOIN chain.evm_tokens USING (runtime, token_address)
LEFT JOIN token_holders USING (token_address)
LEFT JOIN chain.evm_contracts ON
chain.evm_contracts.runtime = chain.evm_tokens.runtime AND
chain.evm_contracts.contract_address = chain.evm_tokens.token_address
LEFT JOIN chain.address_preimages AS owner_preimage ON
owner_preimage.address = chain.evm_nfts.owner
WHERE
chain.evm_nfts.runtime = $1::runtime AND
chain.evm_nfts.token_address = $2::oasis_addr
($2::oasis_addr IS NULL OR chain.evm_nfts.token_address = $2::oasis_addr) AND
($3::oasis_addr IS NULL OR chain.evm_nfts.owner = $3::oasis_addr)
ORDER BY token_address, nft_id
LIMIT $3::bigint
OFFSET $4::bigint`
LIMIT $4::bigint
OFFSET $5::bigint`

AccountRuntimeSdkBalances = `
SELECT
Expand Down
2 changes: 2 additions & 0 deletions storage/migrations/21_evm_nfts.up.sql
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,7 @@ CREATE TABLE chain.evm_nfts (
image TEXT
);
CREATE INDEX ix_evm_nfts_stale ON chain.evm_nfts (runtime, token_address, nft_id) WHERE last_download_round IS NULL OR last_want_download_round > last_download_round;
-- Added in 22_evm_nfts_2.up.sql
-- CREATE INDEX ix_evm_nfts_owner ON chain.evm_nfts (runtime, owner, token_address, nft_id);

COMMIT;
2 changes: 2 additions & 0 deletions storage/migrations/22_evm_nfts.up.sql
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ ALTER TABLE chain.evm_nfts
ADD COLUMN owner oasis_addr,
ADD COLUMN num_transfers INT NOT NULL DEFAULT 0;

CREATE INDEX ix_evm_nfts_owner ON chain.evm_nfts (runtime, owner, token_address, nft_id);

-- Grant others read-only use.
GRANT SELECT ON ALL TABLES IN SCHEMA chain TO PUBLIC;
GRANT EXECUTE ON ALL FUNCTIONS IN SCHEMA chain TO PUBLIC;
Expand Down
Loading

0 comments on commit a73a548

Please sign in to comment.