Skip to content
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

Orchestration API: add support for NFTs #33

Open
5 of 7 tasks
Jorge-Lopes opened this issue May 23, 2024 · 5 comments
Open
5 of 7 tasks

Orchestration API: add support for NFTs #33

Jorge-Lopes opened this issue May 23, 2024 · 5 comments

Comments

@Jorge-Lopes
Copy link
Owner

Jorge-Lopes commented May 23, 2024

Objective

Extend the Agoric-sdk to support the NFT cosmos module while taking advantage of the Agoric Orchestration package.

Tasks

  • Research and document results
  • Build the application level implementation of the cosmos.nft.v1beta1 package
  • Define structure of ERTP representation
  • Plan how to handle remote NFT class and map with issuerKit
  • Plan an exo kit for features related to the x/nft module
  • Plan a test environment
  • Build example contract

Available Documentation

Relevant Agoric issues:

Relevant Agoric PR:

Relevant Agoric tests:

Agoric implementation of cosmos.nft.v1beta1

Similar to the protobuf spec of the cosmos.bank.v1beta1 package from the x/bank module, the current version of the agoric-sdk also the has the protobuf spec of the cosmos.nft.v1beta1 package from the x/nft module

agoric-sdk/packages/cosmic-proto/proto/cosmos/nft/v1beta1

Although, for the x/nft module there is NO implementation found on the application level, as we can confirm by the lack of this module on the codegen/cosmos/ directory

agoric-sdk/packages/cosmic-proto/src/codegen/cosmos

Structure of ERTP representation

When we query an NFT class, the response expected will be an QueryClassResponse , with the following structure:

export interface ClassSDKType {
  id: string;
  name: string;
  symbol: string;
  description: string;
  uri: string;
  uri_hash: string;
  data?: AnySDKType;
}

When we query an NFT, the response expected will be an QueryNFTResponse , with the following structure:

export interface NFT {
  classId: string;
  id: string;
  uri: string;
  uriHash: string;
  data?: Any;
}

We should be able to convert the structure above into an ERTP asset, that can be interacted with via the ERTP API.
This conversion should be done via a method similar to asAmount .

Each NFT will be described via an Amount , which has a Brand and Value .

Based on the QueryNFTResponse structure, it seems a possible approach would be to define:

  • Brand: classId
  • Value: { id, uri, uriHash, data }

Handle remote NFT class and map with issuerKit

Usually, a Brand as a relationship of 1 - 1 with Issuer and Mint .
Considering that the Assets we will interact with are created via a contract held on a host chain , it seem to me that it is not expected to have the Mint representation on the controller chain .

Although, for the Issuer the same may not be true, since the issuer has a relevant purpose, we can then rely on them as the authority to validate an Payment of that Brand

Question:How could we get a representation of an Issuer for this specific Brand?

One possible approach is based on the pattern implemented on the pegasus package, more specifically the pegRemote method.

The diagram bellow represent an high level view of how an issuer could be associated with a NFT class issued on the host chain.

sequenceDiagram
    participant c as contract
    participant ov as orchestration vat
    participant ic as icq controller
    participant ih as icq host

    c ->> ov: makeOrchestrationKit
    ov -->> c: orchestrationKit
    c ->> ov: getClass(classId)
    ov ->> ic: query(QueryClassesRequest)
    ic ->> ih: query packet
    ih -->> ic: ack
    ic -->> ov: QueryClassesResponse
    ov -->> c: class
    c ->> ov: registerClass(class)
    ov ->> ov: makeIssuerKit
    ov ->> ov: map(classId, IssuerKit)
    c ->> ov: getIssuerKit(classID)
    ov -->> c: {band, issuer}
Loading

Question: How should we record the Class data?
Two possible solutions that crossed my mind are:

  1. included in the NFT value itself.
  2. pass the data to the DisplayInfo parameter when calling makeIssuerKit

Question: how to handle ERTP Data Types such as AssetKind?
Based on the NFT class data, how can we infer if it should be declared as COPY_SET or COPY_BAG?

Plan exo kit for features related to the x/nft module

Based on the approach described above, the first step before interacting with a remote NFT is to create and register a local representation of NFT Class in the shape of an ERTP asset.
That Class should then be mapped with an Issuer and Brand in a durable storage.

Additionally, an NftKit should be created and imported by the OrchestrationKit, which would expose the required methods to:

  • query the NFTs held by an ICA
  • send NFT to other account on the remote chain
classDiagram
    LCAKit --* LocalchainAccount
    ICQConnectionKit --* Port
    ICQConnectionKit --* Connection
    ChainAccountKit --* Port
    ChainAccountKit --* Connection
    StakingAccountKit --* IcaAccount

    class ChainAccountKit {
      port: Port
      connection: Connection
      localAddress: LocalIbcAddress
      requestedRemoteAddress: string
      remoteAddress: RemoteIbcAddress
      chainAddress: ChainAddress
    }
    class ICQConnectionKit {
      port: Port
      connection: Connection
      localAddress: LocalIbcAddress
      remoteAddress: RemoteIbcAddress
    }
    class StakingAccountKit {
      chainAddress: ChainAddress 
      bondDenom: string 
      account: ICAAccount 
      timer: Timer
      topicKit: TopicKit
      makeTransferInvitation()
    }

    class LCAKit {
        account: LocalChainAccount
        address: ChainAddress
        topicKit: RecorderKit<LocalChainAccountNotification>
    }
    class LocalchainAccount {
        executeTx()
        deposit()
        withdraw()
    }
    class IcaAccount {
        executeTx()
        deposit()
        getPurse()
        close()
    }
    class NftKit {
        chainAddress: ChainAddress 
        account: ICAAccount 
        icqConnection: ICQConnection
        nftDenom?: string
        getBalance()
        getBalances()
        send()
    }
Loading

How to make a local representation of the remote NFT Class on Agoric chain

Two different approaches are being discussed:

The representation bellow follows the same approach as the vat-bank handles new assets.
One remaining question is in what Vat should the NftManager live? Would it make sense in the long term to include it in the Orchestration-Vat?

sequenceDiagram
    participant C as Contract
    participant NM as NftManager
    participant NameAdmin
    participant Z as Zone


    NM ->> Z: mapStore('brandToAssetRecord')
    create participant bar as brandToAssetRecord
    Z ->> bar: 
    bar -->> NM: brandToAssetRecord

    NM ->> Z: mapStore('brandToAssetDescriptor')
    create participant bad as brandToAssetDescriptor
    Z ->> bad: 
    bad -->> NM: brandToAssetDescriptor

    C ->> NM: addAsset(nftDenom, issuerName, proposedName)
    NM ->> NM: zcfMint = zcf.makeZCFMint(issuerName, AssetKind.COPY_BAG)
    NM ->> NM: {brand, issuer} = zcfMint.getIssuerRecord()

    NM ->> bar: init(brand, PrivateAssetRecord)
    NM ->> bad: init(brand, ToPublish)
    NM ->> NameAdmin: update(denom, AssetInfo)
Loading
Jorge-Lopes added a commit that referenced this issue May 23, 2024
@Jorge-Lopes Jorge-Lopes changed the title Orchestration API: implement support for x/nft Orchestration API: add support for NFTs May 23, 2024
Jorge-Lopes added a commit that referenced this issue Jun 3, 2024
@Jorge-Lopes
Copy link
Owner Author

Jorge-Lopes commented Jun 4, 2024

Open Questions

  • How to structure and record the x/nft Class on Agoric chain? ERTP representation?
  • How to identify the ERTP Data Types such as AssetKind based on the NFT class data? How can we infer if it should be declared as COPY_SET or COPY_BAG?
  • How to set up a test environment that allow us to:
    • execute queries to cosmos chain that holds x/nft

@anilhelvaci
Copy link
Collaborator

Based on the approach described above, the first step before interacting with a remote NFT is to create and register a local record in the shape of an ERTP asset.
With that in mind, an NFT Vat or Contract (ToDo: establish which is the best option) will be created in order to make a remote peg of an NFT Class and expose its Issuer and Brand.

Maybe we can take a look at how vbank handles this. And even extend vbank to be the source of truth for x/nft representations, if makes sense.

classDiagram

    nft --> nft-kit
    orchestration --> nft-kit

    class nft
      nft: -classesPeg Map
      nft: +pegRemote(nftClass)
      nft: +getIssuerKit(nftClassId) {brand, issuer}

    class orchestration
        orchestration: + provideICQConnection() icqConnection
        orchestration: + makeAccount() account

    class nft-kit
        nft-kit: +getBalance(ownerAddr) int
        nft-kit: +getNFTs(brand, ownerAddr) NFT []
        nft-kit: +getNFT(brand, id) NFT
        nft-kit: +getClass(brand) Class
        nft-kit: +send(ica, receiverAddr, brand, id)
Loading

I thought we were going to extend orchestrationKit to have NFT related methods.

@anilhelvaci
Copy link
Collaborator

Is there a specific reason we're not working on https://github.com/agoric-labs/orchestration-api-spec ? Are we sure the @agoric/orchestration has the correct type spec?

@Jorge-Lopes
Copy link
Owner Author

Jorge-Lopes commented Jun 4, 2024

I thought we were going to extend orchestrationKit to have NFT related methods.

Yes, that's correct. The diagram was not updated accordingly (will do it today).
Although the api specs and the exo-kit in development follows the design agreed upon

Is there a specific reason we're not working on https://github.com/agoric-labs/orchestration-api-spec ? Are we sure the @agoric/orchestration has the correct type spec?

As you can see from that repo, it was an early drafting environment for the API specification that was not updated in 2 months.
For that reason I choose to use a latest version of the agoric-sdk 35d20eb to generate the api specs

@Jorge-Lopes
Copy link
Owner Author

Jorge-Lopes commented Jun 4, 2024

To build the updated Orchestration API spec, checkout to the branch jorge/orchestration-x/nft.

Then run:

yarn install && yarn build
cd packages/orchestration
yarn typedoc
open docs/index.html

For more detail, see updates implemented on commit f7470aa.

Note: required to update packages/cosmic-proto/dist/helpers.d.ts file
toRequestQueryJson: (msg: QueryBalanceRequestProtoMsg | QueryNFTsRequestProtoMsg, ...

Jorge-Lopes added a commit that referenced this issue Jun 5, 2024
Ref: #33

Note: update /packages/cosmic-proto/dist/helpers.d.ts to the following:

export declare const toRequestQueryJson: (msg: QueryBalanceRequestProtoMsg | QueryNFTsRequestProtoMsg, opts?: RequestQueryOpts) => JsonSafe<RequestQuery>;
Jorge-Lopes added a commit that referenced this issue Jun 7, 2024
Ref: #33
Note: required to update packages/cosmic-proto/dist/helpers.d.ts file
` toRequestQueryJson: (msg: QueryBalanceRequestProtoMsg | QueryNFTsRequestProtoMsg, ...`
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants