-
Notifications
You must be signed in to change notification settings - Fork 2.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
KodaDot - Atomic Swap Indexer & API for AssetHub NFTs #2271
Conversation
Hey @vikiival , Sadly our recent changes to the PR template were a little late but, as we want to allow grantees to stake their vested DOT, you need to provide us with a native Polkadot (not AssetHub) address. Sorry for the inconvenience. |
Hello @PieWol I have Updated the links 👍 |
Hello @PieWol 👋, |
Ah yes, very well @vikiival |
Just one more thing. We usually name the different parts of a single application "Milestone" so it doesn't make a lot of sense to use this term in the title for an application itself. Would you be able to come up with a distinct but fitting name for the follow up work on the indexer? This would be a nice change before the committee looks at the application. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@vikiival I've taken a look your proposal and have the following questions:
- Can you elaborate on this? What do you mean by "function" here, could you make some examples maybe?
We need to obtain the data for the correct function of our indexer.
- I also have a couple of comments regarding the DB Model:
- It's rather odd to me that you'd add the Entity suffix to some of the entities (e.g.
NFTEntity
), but for some you'd skip it (e.g.Offer
). Is there any meaning to that? - Why does the NFTEntity have 2 relations with TokenEntity - one 1-to-many and on many-to-many?
- Not sure if that should be a question:
Next are Swap and Offer that will represent Atomic Swaps and Offers built on top of the Atomic Swaps?
- Wouldn't it be more straight-forward to skip the TokenEntity and index the DB accordingly to your needs? This would also dev to "perform search operations effectively". In case you disagree (e.g. if that is some new concept that I'm not aware of), please provide us with the detailed data structure for these entities.
TokenEntity represents a list of NFTEntity grouped by the same MetadataEntity.
-
Could you explain what you're trying to swap in particular? NFT to NFT? Or NFT to FT? Or both?
-
To stay on the topic of Swaps, have you looked into the asset_conversion pallet that is already live on AssetHub? How does it compare with that? If I understand correctly, your solution is not decentralised (while asset_conversion is). Is there any reason you decided to choose this route, rather than a more decentralised approach?
-
What are the exact trust assumptions for user using this centralised swap protocol?
E.g To make your car work, you need gas :) The data we will use are Events and Extrinsics defined in the nfts-pallet
The Therefore, for new entities we decided to drop that (Developer experience :)
To understand better what is a Imagine you have distributed more than 800 Poaps with the same picture This is cool to see on the collection page, but this would be annoying in the case of a "general" explore page. Please look on the generated TypeORM model @Entity_()
export class NFTEntity {
// Rest was skipped
@Index_()
@ManyToOne_(() => TokenEntity, {nullable: true})
token!: TokenEntity | undefined | null
}
@Entity_()
export class TokenEntity {
@OneToMany_(() => NFTEntity, e => e.token)
nfts!: NFTEntity[]
}
Please check the comment above
The logic is built on the top of the nfts-pallet deployed on the AssetHub chain. As we can observe in the link above, the nfts-pallet offers only swapping Non-fungible to non-fungible token (allowing surcharge in DOT.)
As core logic lies on the decentralized network (which Polkadot is) I do not see the point of centralization. Moreover, SubSquid is also a decentralized network, and because 100% of the data comes from the chain (which is replicable), there is also no point of centralization. Side noteThis project aims to bring an easy-to-use solution for projects that want to leverage the power of nft-pallet on the AssetHub. Hope I clarified all your questions @takahser and we can move forward 👍. |
cc @PieWol @keeganquigley 🥺 🙏 |
Hi @vikiival , |
In last 20 day we have served more than 500k+ queries via M1 indexer alone. It is a powering @TalismanSociety's NFT UI @novasamatech NFT section in their mobile wallet. Both of them has big amount of users ^-^ and we are very happy to make ecosystem awesome by providing them an infrastructure that is out of their capacity.
Must have slipped while I was shuffling with the files |
Hey @vikiival , |
@vikiival |
This milestone focuses on atomic swap functionality implemented in the nfts-pallet. I will chceck the pallet you have sent, I was not awarr of that one, thanks! |
Got it, thanks for clarifying. I have to say whoever decided on the terminology of the nfts pallet has made a questionable choice by calling a simple swap "atomic swap" instead. Anyway it doesn't change anything about my approval. Terminology listed here https://docs.rs/crate/pallet-nfts/latest |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@vikiival thx for your replies.
The data we will use are Events and Extrinsics defined in the nfts-pallet
Is there any meaning to that?
Wouldn't it be better practice to refactor the naming? It seems quite messy to me to mix the two terminologies (with and without Entity
suffix).
Why does the NFTEntity have 2 relations with TokenEntity - one 1-to-many and on many-to-many?
This is cool to see on the collection page, but this would be annoying in the case of a "general" explore page. Therefore, the idea is to "stack" the
NFTs
(with the same image) under one entity (TokenEntity
). It implies thatTokenEntity
holdsArray<NFTEntity>
whereNFTEntity
can be owned by just oneTokenEntity
So the only difference between a collection and a tokenentity is that the latter will display the img only once? If that's the case, I think there's no justification to duplicate the whole logic and you should let the UI handle it instead (and maybe add a binary attribute stackImages
or something similar).
Please look on the generated TypeORM model
@Entity_() export class NFTEntity { // Rest was skipped @Index_() @ManyToOne_(() => TokenEntity, {nullable: true}) token!: TokenEntity | undefined | null } @Entity_() export class TokenEntity { @OneToMany_(() => NFTEntity, e => e.token) nfts!: NFTEntity[] }
You're showing the same relation, just from different perspective: NFTEntity
's ManyToOne
relationship becomes a OneToMany
relationship when viewed from the TokenEntity
's PoV. But that doesn't explain why you have two different relationships in the diagram: 1-to-many and 1-to-1.
Also, I noticed the same holds true for the relations between CollectionEntity and NFTEntity.
Could you explain what you're trying to swap in particular? NFT to NFT? Or NFT to FT? Or both?
The logic is built on the top of the nfts-pallet deployed on the AssetHub chain.
As we can observe in the link above, the nfts-pallet offers only swapping Non-fungible to non-fungible token (allowing surcharge in DOT.)
What's "allowing surcharge in DOT"? Does it mean that if the NFTs vary in value, the missing value will be paid in DOT?
7c1c9f2
to
00b1bf8
Compare
Updated in 00b1bf8
why you have two different relationships in the diagram: 1-to-many and 1-to-1. Because that's how Subsquid handles that :).
Collection (CollectionEntity) Holds a list of Item (NFTEntity) What could happen is that The logic is not duplicated, it is our engineering approach of making things fast :)
We have tried that, but It does not work.
Let us derive a situation. My |
Co-authored-by: Sebastian Müller <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated in 00b1bf8
The diagram doesn't reflect that.
why you have two different relationships in the diagram: 1-to-many and 1-to-1.
Because that's how Subsquid handles that :).
Please take a look at the documentation
No, that's not how subsquid handles that. The link you've shared contains examples for the following relationships:
- One-to-one
- Many-to-one/One-to-many
- Many-to-many (using a joint table)
There is no example of two entities that have both 1-to-many AND 1-to-1 relationships because it doesn't make any sense.
Collection (CollectionEntity) Holds a list of Item (NFTEntity)
What could happen is that Item can share same ItemMetadata and it causes heavy performance and UI issues. That's why we have decided to "group" NFTEntity sharing the same MetadataEntity into one bag called TokenEntity.
The logic is not duplicated, it is our engineering approach of making things fast :)
Just to be clear: I don't think it's a problem to abstract away the MetaData as you do with MetadataEntity
. I was just questioning whether both CollectionEntity
and TokenEntity
are needed, if the only difference is that the TokenEntity
will display the img only once (which you didn't answer).
Let me use code to illustrate what I mean.
// TokenEntity contains an array of nfts
@Entity_()
export class TokenEntity {
@OneToMany_(() => NFTEntity, e => e.token)
nfts!: NFTEntity[]
}
// Similarly, CollectionEntity contains an array of nfts
@Entity_()
export class CollectionEntity {
@OneToMany_(() => NFTEntity, e => e.token)
nfts!: NFTEntity[]
}
// each nft contains metadata, no matter if it's part of a CollectionEntity or TokenEntity
@Entity_()
export class NFTEntity {
@OneToOne_(() => MetadataEntity, e => e.meta)
meta: MetaEntity
}
One solution would be to introduce an additional attribute to CollectionEntity
that contains the common metadata:
// Similarly, CollectionEntity contains an array of nfts
@Entity_()
export class CollectionEntity {
// the "meta" attribute in these nfts would be empty, but if not, it's ignored, if "commonMetaData" is populated
@OneToMany_(() => NFTEntity, e => e.token)
nfts!: NFTEntity[]
// we add this
@OneToOne_(() => MetadataEntity, e => e.meta)
commonMetaData?: MetaEntity
}
As far as I can see you already have that relationship in your diagram:
That way, the whole TokenEntity
would become obsolete. I'm not sure if it's the best solution, since the rule to ignore downstream meta infos within NFTEntity
is an ugly dependency as well, but at least you don't need two almost identical entities. I'm also not sure if TokenEntity
is a good name for an entity that contains a lot of NTFEntity
objects where "T" obviously stands for Token as well - kinda strange, if you ask me.
Fetch 12 NFTs per page with the same metadata. Group them on the front end; you are left with one item on the page. Additionally, what about other UIs using indexer? Should we tell them to implement it by themselves? Therefore, we have decided to use the approach: fix once - use everywhere.
Personally, I think having 2 almost identical entities is much more confusing. It's definitely possible to implement it in other UIs that way as well.
Probably cache? I will try to explain
This would not be doable for ERC-1155 tokens
TL;DR: Collection represents on-chain collection where as Token represents a grouping of Items with the same metadata - (you can have
If you have any questions please send me a message on telegram (same handle) Also @takahser can I please ask you for swiftier responses? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Probably cache?
I guess the only one that's not updated is Event
:
I will try to explain
CollectionEntity
has one-to-one connection toMetadataEntity
becauseCollectionEntity
has one-to-many connectionNFTEntity
because each NFT belongs to some connection
This still doesn't explain the 2 relationships between CollectionEntity
and NFTEntity
:
- We have learned the hard way
Please elaborate. Sorry for the delays here, but we currently have a very large backlog in both the W3F Grants program as well as the Decentralised Futures program. We're trying to be fair to all teams, and I've repeatedly asked you for an explanation on these things (e.g. the previous point), without having received a detailed explanation. Proving links is fine, as long as it's clear to what you're referring to, however, that's not the case here.
This would not be doable for ERC-1155 tokens
Also here: Feel free to elaborate.
TL;DR: Collection represents on-chain collection where as Token represents a grouping of Items with the same metadata - (you can have
n
different metadata for)
So Collection
is a representation of an on-chain concept, but Token
is just a view model, aggregated for the frontend?!
Collection (CollectionEntity) Holds a list of Item (NFTEntity)
Collection is therefore "representation of an on-chain entity" where as TokenEntity is very smart table for clients to get data in the better way, Let us take a look on the biggest NFT collection ever made in Polkadot Ecosystem select count(*) from nft_entity;
-- 719_296
select collection_id, count(*) from nft_entity group by collection_id order by count(*) desc ;
-- 90c6619c6b94fcfd34-EVRLOOT_RESOURCES, 186_083 To explain If we want to show now a collection detail database needs to go through 186 thousand NFTs to show you this: However if we scroll to next page UI will try to have a problem and shows you this: therefore we agreggate nfts by (image) or select image, count(*) from nft_entity where collection_id = '90c6619c6b94fcfd34-EVRLOOT_RESOURCES' group by image order by count(*) desc; [
{
"image": "ipfs://ipfs/QmfHxMyYpBsDCnL8VVkqyXNCkGZZ5d5v4W4NgKar455HZq/water.png",
"count": 82387
},
{
"image": "ipfs://ipfs/QmfYEsnN4T3gFgwQqkXZpbxZbLSTj11FMgGhEEfodfsUh7",
"count": 39428
},
{
"image": "ipfs://ipfs/QmfHxMyYpBsDCnL8VVkqyXNCkGZZ5d5v4W4NgKar455HZq/wood.png",
"count": 38691
},
{
"image": "ipfs://ipfs/QmfHxMyYpBsDCnL8VVkqyXNCkGZZ5d5v4W4NgKar455HZq/cooked_fish.png",
"count": 16430
},
{
"image": "ipfs://ipfs/QmPfg4v5Qx9iv4sJ6A1jZkjJrvAVbXfoTMZyBT6aeAxEMB/clam_bait.png",
"count": 2632
},
{
"image": "ipfs://ipfs/QmPfg4v5Qx9iv4sJ6A1jZkjJrvAVbXfoTMZyBT6aeAxEMB/palm_wood_2.png",
"count": 1235
},
{
"image": "ipfs://ipfs/QmPfg4v5Qx9iv4sJ6A1jZkjJrvAVbXfoTMZyBT6aeAxEMB/Hyena%20Bones.png",
"count": 816
},
{
"image": "ipfs://ipfs/QmPfg4v5Qx9iv4sJ6A1jZkjJrvAVbXfoTMZyBT6aeAxEMB/Old%20Rope.png",
"count": 740
},
{
"image": "ipfs://ipfs/QmPfg4v5Qx9iv4sJ6A1jZkjJrvAVbXfoTMZyBT6aeAxEMB/spicy%20soup.png",
"count": 720
},
{
"image": "ipfs://ipfs/QmPmMP6gN5SpNxkqn54ov8nJLmnmLRi8BVwwi7ok6MGU7w/bangar_fruit.png",
"count": 713
},
{
"image": "ipfs://ipfs/QmPfg4v5Qx9iv4sJ6A1jZkjJrvAVbXfoTMZyBT6aeAxEMB/wild_chilli.png",
"count": 713
},
{
"image": "ipfs://ipfs/QmPfg4v5Qx9iv4sJ6A1jZkjJrvAVbXfoTMZyBT6aeAxEMB/smoked%20fish.png",
"count": 493
},
{
"image": "ipfs://ipfs/QmTDNVHPg5Kuf2BhbFGej3SW3nkzMCPkFJd9p3npQydpKn",
"count": 394
},
{
"image": "ipfs://ipfs/QmPfg4v5Qx9iv4sJ6A1jZkjJrvAVbXfoTMZyBT6aeAxEMB/Palm%20Fibers.png",
"count": 277
},
{
"image": "ipfs://ipfs/QmPfg4v5Qx9iv4sJ6A1jZkjJrvAVbXfoTMZyBT6aeAxEMB/Palm%20Resin.png",
"count": 246
}
] As we can observe the proposed idea of What if we calculate this aggregation on demand? That is very good question but the database is not very ok with that. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
re-approving
Hi @vikiival as we are now requiring KYB for all grantees, could you submit verification if you haven't done so already? Thanks! |
^-^ |
Hi @vikiival I see you have personally completed KYC but not seeing that KYB has been passed yet for KodaLabs. Are you able to submit this as well? |
Congratulations and welcome to the Web3 Foundation Grants Program! Please refer to our Milestone Delivery repository for instructions on how to submit milestones and invoices, our FAQ for frequently asked questions and the support section of our README for more ways to find answers to your questions. |
Project Abstract
AssetHub Indexer is a GraphQL service that streamlines interaction with singles, non-fungible NFT assets and fungible assets on AssetHubs. The service was specifically designed to serve as a solid data layer for NFT-oriented dApps and leverages GraphQL and REST API simplicity.
In Milestone 2, we focus on significant improvements to the AssetHub indexer to streamline NFT transactions and improve the collection management of the Polkadot network. Our updates focus on the integration of Atomic Swaps, Offers, Architectural Upgrades, and overall improvement of the developer's experience.
This proposal is a follow-up of Proposal 1 for AssetHub NFT indexer
Grant level
Application Checklist
project_name.md
).@_______:matrix.org
(change the homeserver if you use a different one)