---
# System prepended metadata

title: NFT-Twitter

---

# NFT-Twitter

# Taskslist
- NFT-Webapp Single-Page UI (Simonas)
    - List Tweets (all Tweets, no filter)
    - List NFTs
    - Select active NFT
    - Tweet with (active) NFT
    - New: "Send private Message" to NFT
    - New: "Receive private Message" on Agent
- Agent/API:
    - Expose VCs: /dataStoreGetVerifiableCredential :heavy_check_mark: 
    - Expose Msg Endpoint to receive credentials :heavy_check_mark:
    - DID:NFT resolver must be working Server-Side :heavy_check_mark:
    - "Find/Read all NFTs" for Ethereum Address (via opensea) :heavy_check_mark:
    - MessageHandler-Chain to verif and unwrap Metamask-signed Messages (Mircea, Oliver, Martin) :heavy_check_mark:
        - No JSON-LD dependency. Special MM-JWT credential & Message Handler. @Martin @ @Oliver
    - Expose Opensea API calls in own backend with Opensea API Key :exclamation: 
- Metamask / Veramo Integration
    - KMS-Veramo Integration :heavy_check_mark:
        - MemoryDIDStore :heavy_check_mark:
        - MemoryKeyStore :heavy_check_mark:
        - Web3KeyManagementSystem (Sign) :heavy_check_mark:
    - Metamask cannot sign our Secp256k1 JWT representation
        - No JSON-LD dependency. Special MM-JWT credential & Message Handler. @Mircea
    - MetaMask Credential Signing with EIP-712 support. (Simonas): (may, for FRI) :heavy_check_mark:

- Architecture Diagram (Oliver) :heavy_check_mark:
- Demo Flow Design and Presentation (Rouven, Martin) :heavy_check_mark:  
    - Demo transfer of NFT? (not part of friday demo)
    - Where does Veramo come in?
    - Where to go from here?
    - Break it down to "base components"
        - Central Hosted Accumulator (did:web agent)
        - Metamask KMS Integration
        - DID:NFT resolver
        - Credential Proof Format
- :hammer: Migrate solution from JWT to JSON-LD Credentials (Martin) - Maybe in context with Metamask-Sig
- "Web3-Veramo-Kit" should be separate from agent explorer codebase. - Out of scope for friday's demo

# Outcome / Learning
- Backend / Frontend Code Sharing within Projects like Pulsar
- Wrap outcome into dApp Library for web3 frontend signing. (Preconfigured Web3 provider that is automatically provided to KeyManager, DIDManager and Messaging) -> Greg, Simonas
- Web3 / Metamask Handling (e.g. Connect, Disconnect) is out-of-scope of Veramo.
- "Profile Credential" for name and profile pic for any DID.
- Prepare Deployment Infrastructure to dynamically handle bigger loads (e.g. provide Credit Card information)

# Discussion Points
- How to resolve messaging endpoints for `did:nfts?`
    - Martin: Is that relevant for MVP? 
    - Client -> Twitter NFT Agent Hard-coded for demo?
    - Twitter NFT Agent -> Client: No communication
- did:ethr as controller of did:nft:
    - ERC721 specifies an ethereum address as owner, not a did:ethr. Key rotations in did:ethr are not represented in ERC721.
    - Owner addresses of various NFTs are NOT necessarily DID compliant
- [did:nft](https://github.com/ceramicnetwork/CIP/blob/main/CIPs/CIP-94/CIP-94.md) method by Ceramic
    - Relies heavily on chain-agnostic CAIP specs.
    - Faces the same problem as stated above. Existing NFTs do not present owner as DIDs
    - Mircea: We would have a different view of a did:nft method. On Friday start conversation with Ceramic.
- Serto: https://serto.medium.com/verifiable-authorship-for-the-150-million-nft-art-market-8a7affe90186
- "Web3-Veramo-Kit" should be separate from agent explorer codebase.
- EIP-1056 on Matic: not prioritized

# Resources
- [Olivers Whimsical](https://whimsical.com/nft-demo-J1vEefJnSqp4XVCU91g95t)
- Original Design Notes on [Whimsical](https://whimsical.com/twitter-for-nfts-TLJBMoYBGaKLXfgK7Vx1r1)

# Grooming Meeting 3/15/2021
## Agenda:
- Wednesday Meeting: What to show:
    - Rouven: Updated presentation / messaging
    - Demos?
- DID:NFT Method
- Veramo Client-side Metamask demo (NFT-Twitter)
- DID-Chat (NFT-Chat): A->B hosted on Server C

## Protocol
- Internal Consensys Meeting on 3/17 with Consensys Leadership Team
- Extended Demo Ideas:
- Simonas: Include Messaging Part in Same Demo.
- Include "private Messaging" in Twitter NFT Demo
- Be able to send messages to the messaging endpoint of the did:nft
- Every client would need an endpoint to receive private messages.
- Public "Messaging Instance" of Veramo: How would that work?
    - Message must be encrypted for receipient
    - Message must be able to integrity checked on server side
    - Retrieving (encrypted) messages should only be possible for receipient.
- For Wednesday Demo:
    - Restrict to Demo to send private messages to personal endpoints.
    - Challenges: Where does the endpoint information live?
- Rouven: Use different Skins for NFT-Twitter and Personal Message portal, so that audience understand the different 
- Simonas: Contact Form for NFTs?
- Simonas: VC can be NFTs that are not in the Blockchain yet.

YOU own -> VCs
YOU own -> NFTs

connection via (YOU). I don't see UC VC->NFT
- Should VC (like Ethr) have a possibility to point to a on-chain transfer?
- CredentialStatus with "Transfer" support. e.g. credentialSubject changed from DID1 to DID2.
- Assigned new Tasks until Wednesday

# Metamask Credential EIP712 Example:
```
    const credential = {
      "@context": [
        "https://www.w3.org/2018/credentials/v1",
        "https://www.w3id.org/veramolabs/socialmedia/context/v1"
      ],
      "type": [
        "VerifiableCredential",
        "VerifableSocialMediaPosting"
      ],
      "id": "https://example.org/post/1234",
      "issuer": "did:example:aadsfewfweasdfsfad",
      "issuanceDate": "2010-01-01T19:23:24Z",
      "credentialSubject": {
        // might contain reply tweet URL
        "id": "https://example.org/post/1234",
        "type": "SocialMediaPosting",
        "author": {
          "id": "did:nft:ebfeb1f712ebc6f1c276e12ec21",
          "type": "Person",
          "thumbnail": "https://google.com",
          "image": "https://google.com",
          "name": "cryptopunk"
        },
        "headline": "punks are aliens",
        "articleBody": "waffles for zoomers"
      },
      "credentialSchema": {
        "id": "https://www.w3id.org/veramolabs/socialmedia/context/v1/eip712.json",
        "type": "Eip712SchemaValidator2021"
      }
    };
    // TODO: normally one should get eip712 schema from credentialSchema URI
    const eip712Schema = {
      VerifiableCredential: [
        { name: '@context', type: 'string[]' },
        { name: 'type', type: 'string[]' },
        { name: 'id', type: 'string' },
        { name: 'issuer', type: 'string' },
        { name: 'issuanceDate', type: 'string' },
        { name: 'credentialSubject', type: 'CredentialSubject' },
        { name: 'credentialSchema', type: 'CredentialSchema' }
      ],
      CredentialSchema: [
        { name: 'id', type: 'string' },
        { name: 'type', type: 'string' },
      ],
      CredentialSubject: [
        { name: 'type', type: 'string' },
        { name: 'id', type: 'string' },
        { name: 'headline', type: 'string' },
        { name: 'articleBody', type: 'string' },          
        { name: 'author', type: 'Person' }
      ],
      Person: [
        { name: 'type', type: 'string' },
        { name: 'id', type: 'string' },
        { name: 'thumbnail', type: 'string' },
        { name: 'image', type: 'string' },
        { name: 'name', type: 'string' }
      ]
    };
    // TODO: normalize credential using JCS
    const data = JSON.stringify({
      types: {
        EIP712Domain: [
          { name: 'name', type: 'string' },
          { name: 'version', type: 'string' },
          { name: 'chainId', type: 'uint256' },
          { name: 'salt', type: 'bytes32' },
        ],
        ... eip712Schema
      },
      domain: {
        name: 'Sign Tweet',
        version: '2',
        chainId: 4,
        salt: '0xf2d857f4a3edcb9b78b4d503bfe733db1e3f6cdc2b7971ee739626c97e86a558',
      },
      primaryType: 'VerifiableCredential',
      message: {
        ... credential
      }
    });
    const signer = walletAddress;
    const params = [signer, data];
    web3.currentProvider.sendAsync(
      {
        method: 'eth_signTypedData_v4',
        params,
        from: signer,
        jsonrpc: '2.0',
        id: new Date().getTime(),
      },
      (error, response) => {
        if (error) {
          return setErrorMsg(error.message);
        } else if (response && response.error) {
          const errMsg = response.error.message.substring(0, 70).concat('...');
          return setErrorMsg(errMsg);
        } else {
          const result = response && response.result;
          const signature = result && result.substring(2);
          const r = signature && '0x' + signature.substring(0, 64);
          const s = signature && '0x' + signature.substring(64, 128);
          const v = signature && parseInt(signature.substring(128, 130), 16);
          const signatures = {
            signature,
            r,
            s,
            v,
          };
          setSuccessMsg(`Successfully signed data!! ${signature}`);
          setData({ signatures, ...JSON.parse(data) });
        }
      }
    );
  };
```

Resulting Proof:
```
"proof": {
    "type": "EthereumEip712Signature2021",
    "verificationMethod": "did:ethr:0xabc#...",
    "proofPurpose": "assertionMethod",
    "domain": {
      "name": 'Sign Tweet',
      "version": '2',
      "chainId": 4,
      "salt": '0xf2d857f4a3edcb9b78b4d503bfe733db1e3f6cdc2b7971ee739626c97e86a558',
    },
    "signature": "a5976468abf6b39242bd892c19047e4f83454f31c073b3d6e87954fbef259e156a3fbe2ae401054e6efaa1097647b2236cd11fdc322680405a1e840614d2ac601c"
}
```