owned this note
owned this note
Published
Linked with GitHub
# Unity SDK: high-level API
## Input
* https://github.com/trilitech/tezos-unity-sdk/issues/15 (get token balances)
* https://opentezos.com/gaming/unity-sdk/api-documentation/ (read balance, read view)
* https://github.com/aag-lara/Unity-TzKT-API-call (get token balances)
## References
* https://docs.alchemy.com/reference/nft-api-endpoints
* https://docs.moralis.io/web3-data-api/evm/reference
* https://docs.x.immutable.com/reference/#/
## Interface
Extends https://github.com/trilitech/tezos-unity-sdk/blob/e8a863f1315554e541e44b9be5959d8d35ed81eb/Assets/Scripts/TezosAPI/ITezosAPI.cs#L7
```csharp=
interface ITezosAPI
{
// Gets all tokens currently owned by a given address.
public IEnumerable<TokenBalance> GetTokensForOwner(
string owner,
// string[] contract_addresses, --> will add later
bool with_metadata,
long max_items,
TokensForOwnerOrder order_by,
);
// Gets all token contracts held by an owner address.
// public IEnumerable<TokenContract> GetContractsForOwner(
// string owner,
// bool with_metadata,
// long max_items,
// ContractOrder order_by,
// );
// Get the owner(s) for a token.
public IEnumerable<TokenBalance> GetOwnersForToken(
string contract_address,
string token_id,
long max_items,
OwnersForTokenOrder order_by,
);
// Gets all owners for a given token contract.
public IEnumerable<TokenBalance> GetOwnersForContract(
string contract_address,
long max_items,
OwnersForContractOrder order_by,
);
// Checks whether a wallet holds a token in a given contract.
public bool IsHolderOfContract(
string wallet,
string contract_address
);
// Checks whether a wallet holds a particular token.
public bool IsHolderOfToken(
string wallet,
string contract_address,
string token_id,
);
// Gets the metadata associated with a given token (fallback to token metadata link?).
public TokenMetadata GetTokenMetadata(
string contract_address,
string token_id,
);
// Batched version for multiple tokens? Can do in next iteration
// Queries token high-level collection/contract level information.
public ContractMetadata GetContractMetadata(
string contract_address,
);
// Also batched version for multiple contracts? Can do in next iteration
// Gets all tokens for a given token contract.
public IEnumerable<Token> GetTokensForContract(
string contract_address,
bool with_metadata,
long max_items,
TokensForContractOrder order_by,
);
}
```
## Implementation details
Note that test contracts/tokens with large number of tokens/holders were intentionally picked.
TzKT models given as reference, I propose more flat ones and without TzKT-specific fields (e.g. internal IDs) — use `select` filter to manage that.
We should also not include TzKT profiles as it's implementation-specific info.
Wherever possible use `balance.ne=0` to reduce unnecessary load. Note that if there are edge cases where it's necessary we should introduce additional parameter to specify so.
**Do not forget to add docstrings and comments**
### GetTokensForOwner
Response model (ref): https://github.com/baking-bad/tzkt/blob/master/Tzkt.Api/Models/Tokens/TokenBalance.cs
API query: https://api.tzkt.io/v1/tokens/balances?account=KT18p94vjkkHYY3nPmernmgVR7HdZFzE7NAk&balance.ne=0&select=account.address%20as%20owner,balance,token.contract.address%20as%20tokenContract,token.tokenId%20as%20tokenId,token.metadata%20as%20tokenMetadata,lastTime,id&limit=10
#### Order
Default
`sort.asc=id&offset.cr=<last_id>`
By lastTime
`sort.desc=lastTime&offset.pg=<page>`
```csharp=
public abstract record TokensForOwnerOrder()
{
public record Default(long last_id) : TokensForOwnerOrder;
public record ByLastTimeAsc(long page) : TokensForOwnerOrder;
public record ByLastTimeDesc(long page) : TokensForOwnerOrder;
}
GetTokensForOwner(
"KT18p94vjkkHYY3nPmernmgVR7HdZFzE7NAk",
false,
10,
new TokensForOwnerOrder.Default(0), // last id from previous response
)
```
Allow null?
ref https://www.reddit.com/r/csharp/comments/kghp18/rust_enum_style/
### GetContractsForOwner (skip in this iteration)
Note: this is not an optimal solution rn, might need an optimisation on TzKT side.
In short:
- we need to query all token balances for owner
- group by token contract
- query contract metadata for each contract (if necessary, now only TzKT aliases are provided)
API query: https://api.tzkt.io/v1/tokens/balances?account=KT18p94vjkkHYY3nPmernmgVR7HdZFzE7NAk&select=token.contract%20as%20tokenContract
Metadata: see [GetContractMetadata](#GetContractMetadata)
> Need a more scalable approach here
### GetOwnersForToken
Response model (ref): https://github.com/baking-bad/tzkt/blob/master/Tzkt.Api/Models/Tokens/TokenBalance.cs
Metadata not included.
API query: https://api.tzkt.io/v1/tokens/balances?token.contract=KT1BRADdqGk2eLmMqvyWzqVmPQ1RCBCbW5dY&token.tokenId=1&balance.ne=0&select=account.address%20as%20owner,balance,token.contract%20as%20tokenContract,token.tokenId%20as%20tokenId,lastTime,id&limit=10
#### Order
Default
`sort.asc=id&offset.cr=<last_id>`
By balance
`sort.desc=balance&offset.pg=<page>`
By lastTime
`sort.desc=lastTime&offset.pg=<page>`
```csharp=
public abstract record OwnersForTokenOrder()
{
public record Default(long last_id) : OwnersForTokenOrder;
public record ByBalanceAsc(long page) : OwnersForTokenOrder;
public record ByBalanceDesc(long page) : OwnersForTokenOrder;
public record ByLastTimeAsc(long page) : OwnersForTokenOrder;
public record ByLastTimeDesc(long page) : OwnersForTokenOrder;
}
GetOwnersForToken(
"KT1BRADdqGk2eLmMqvyWzqVmPQ1RCBCbW5dY",
"1",
10,
new OwnersForTokenOrder.ByBalanceDesc(2), // page id
)
```
### GetOwnersForContract
Response model (ref): https://github.com/baking-bad/tzkt/blob/master/Tzkt.Api/Models/Tokens/TokenBalance.cs
Metadata not included.
API query: https://api.tzkt.io/v1/tokens/balances?token.contract=KT1BRADdqGk2eLmMqvyWzqVmPQ1RCBCbW5dY&balance.ne=0&select=account%20as%20owner,balance,token.contract%20as%20tokenContract,token.tokenId%20as%20tokenId,id&limit=10
#### Order
Default
`sort.asc=id&offset.cr=<last_id>`
By lastTime
`sort.desc=lastTime&offset.pg=<page>`
```csharp=
public abstract record OwnersForContractOrder()
{
public record Default(long last_id) : OwnersForContractOrder;
public record ByLastTimeAsc(long page) : OwnersForContractOrder;
public record ByLastTimeDesc(long page) : OwnersForContractOrder;
}
GetOwnersForContract(
"KT1BRADdqGk2eLmMqvyWzqVmPQ1RCBCbW5dY",
false,
10,
new OwnersForContractOrder.ByLastTimeDesc(3), // page id
)
```
### IsHolderOfContract
API query: https://api.tzkt.io/v1/tokens/balances?account=tz1TiZ74DtsT74VyWfbAuSis5KcncH1WvNB9&token.contract=KT1BRADdqGk2eLmMqvyWzqVmPQ1RCBCbW5dY&balance.ne=0&select=id (just need to check that the list is non-empty)
### IsHolderOfToken
https://api.tzkt.io/v1/tokens?contract=KT1BRADdqGk2eLmMqvyWzqVmPQ1RCBCbW5dY&tokenId=1&select=metadata
API query: https://api.tzkt.io/v1/tokens/balances?account=tz1TiZ74DtsT74VyWfbAuSis5KcncH1WvNB9&token.contract=KT1BRADdqGk2eLmMqvyWzqVmPQ1RCBCbW5dY&token.tokenId=123&balance.ne=0&select=id (just need to check that the list is non-empty)
### GetTokenMetadata
Raw JSON? @257byte
API query: https://api.tzkt.io/v1/tokens?contract=KT1BRADdqGk2eLmMqvyWzqVmPQ1RCBCbW5dY&tokenId=1&select=metadata
### GetContractMetadata
Raw JSON? @257byte
API query: https://api.tzkt.io/v1/contracts/KT1BRADdqGk2eLmMqvyWzqVmPQ1RCBCbW5dY?legacy=false (and read metadata field)
### GetTokensForContract
Response model (ref): https://github.com/baking-bad/tzkt/blob/master/Tzkt.Api/Models/Tokens/Token.cs
API query: https://api.tzkt.io/v1/tokens?contract=KT1RJ6PbjHpwc3M5rw5s2Nbmefwbuwbdxton&select=contract.address%20as%20tokenContract,tokenId,holdersCount,metadata%20as%20tokenMetadata,id,lastTime&limit=10
#### Order
Default
`sort.asc=id&offset.cr=<last_id>`
By holdersCount
`sort.desc=holdersCount&offset.pg=<page>`
By lastTime
`sort.desc=lastTime&offset.pg=<page>`
```csharp=
public abstract record TokensForContractOrder()
{
public record Default(long last_id) : TokensForContractOrder;
public record ByHoldersCountAsc(long page) : TokensForContractOrder;
public record ByHoldersCountDesc(long page) : TokensForContractOrder;
public record ByLastTimeAsc(long page) : TokensForContractOrder;
public record ByLastTimeDesc(long page) : TokensForContractOrder;
}
GetTokensForContract(
"KT1RJ6PbjHpwc3M5rw5s2Nbmefwbuwbdxton",
false,
10,
new TokensForContractOrder.ByHoldersCountDesc(4), // page id
)
```
## TzKT configuration
TzKT should be optionally configurable via builder interface when instantiating `ITezos`. If TzKT is not configured — throw a special exception `TzktProviderNotConfigured`
```csharp=
class TzktProviderConfig {
string endpoint;
// TBD: auth creds
}
class Tezos : ITezosAPI {
public Tezos WithTzktProvider(TzktProviderConfig config)
{
// TODO
return this;
}
}
```
## Follow-up discussion
* Accessing on-chain attributes of in-game assets (expose big maps specific endpoints?)
* Filter by metadata tags (access internal metadata structure tzip-21)
* Filtering tokens for owner by list of contracts: most scalable approach? Better use custom API for that?