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

EthrDIDProvider networks[] for Linea config does not work for didManagerAddService with options: { metaIdentifierKeyId } #1288

Open
hylim-tech-lover opened this issue Nov 3, 2023 · 1 comment
Labels
bug Something isn't working pinned don't close this just for being stale triage

Comments

@hylim-tech-lover
Copy link
Contributor

hylim-tech-lover commented Nov 3, 2023

Bug severity
3

Describe the bug
It came to notice that we will need to use meta-transaction with options: { metaIdentifierKeyId } for didManagerAddService as it is encapsulated as eth_sendTransaction RPC call under the hood.

However, despite setting up the parameters accordingly in correspond to the discussion thread in Discord which will be elaborated in To Reproduce section, the didManagerAddService still failed with the error shown in Observed behaviour section.

The code example is derived from Veramo Node Tutorial Example

To Reproduce
Steps to reproduce the behaviour (Linux OS):

  1. Create empty folder with NodeJS installed (version stated below).

  2. Create .env file with following:

    INFURA_API_KEY=
    KMS_SECRET_KEY=  '< you can generate a key by running `npx @veramo/cli config create-secret-key` in a terminal>'
    WALLET_PRIVATE_KEY=
    
  3. Obtain the following environment variable as followed:

  4. The example of final .env file:

    INFURA_API_KEY=xxxx
    KMS_SECRET_KEY=xxxxx
    WALLET_PRIVATE_KEY=xxxxx
    
  5. Create package.json and insert the following:

        {
        "name": "veramo-meta-tx-testing",
        "engines": {
            "node": ">=21.0.0 <22.0.0"
        },
        "type": "module",
        "scripts": {
            "execute-with-env": "esrun --node-env-file=.env"
        },
        "dependencies": {
            "@veramo/core": "5.5.3",
            "@veramo/credential-w3c": "5.5.3",
            "@veramo/data-store": "5.5.3",
            "@veramo/did-manager": "5.5.3",
            "@veramo/did-provider-ethr": "5.5.3",
            "@veramo/did-resolver": "5.5.3",
            "@veramo/key-manager": "5.5.3",
            "@veramo/kms-local": "5.5.3"
        },
        "devDependencies": {
            "@digitak/esrun": "3.2.24",
            "sqlite3": "^5.1.6",
            "typescript": "^5.1.6"
        }
    }
  6. Run npm install to install all dependencies

  7. Create tsconfig.json and insert the following:

    {
        "compilerOptions": {
            "preserveConstEnums": true,
            "strict": true,
            "target": "esnext",
            "module": "esnext",
            "rootDir": "./",
            "moduleResolution": "node",
            "esModuleInterop": true,
            "downlevelIteration": true
        }
    }
  8. Create setup.ts and insert the following:

    // Core interfaces
    import {
        createAgent,
        IDIDManager,
        IResolver,
        IDataStore,
        IDataStoreORM,
        IKeyManager,
        ICredentialPlugin,
    } from '@veramo/core';
    
    // Core identity manager plugin
    import { DIDManager } from '@veramo/did-manager';
    
    // Ethr did identity provider
    import { EthrDIDProvider } from '@veramo/did-provider-ethr';
    
    // Core key manager plugin
    import { KeyManager } from '@veramo/key-manager';
    
    // Custom key management system
    import { KeyManagementSystem, SecretBox } from '@veramo/kms-local';
    
    // W3C Verifiable Credential plugin
    import { CredentialPlugin } from '@veramo/credential-w3c';
    
    // Custom resolvers
    import { DIDResolverPlugin } from '@veramo/did-resolver';
    import { Resolver } from 'did-resolver';
    import { getResolver as ethrDidResolver } from 'ethr-did-resolver';
    
    // Storage plugin using TypeOrm
    import {
        DIDStore,
        Entities,
        KeyStore,
        migrations,
        PrivateKeyStore,
    } from '@veramo/data-store';
    
    // TypeORM is installed with '@veramo/data-store'
    import { DataSource } from 'typeorm';
    
    
    // DB setup:
    const dbConnection = new DataSource({
        type: 'sqlite',
        database: 'database.sqlite',
        synchronize: false,
        migrations,
        migrationsRun: true,
        logging: ['error', 'info', 'warn'],
        entities: Entities,
    }).initialize();
    
    
    export const agent = createAgent<
        IDIDManager & IKeyManager & IDataStore & IDataStoreORM & IResolver & ICredentialPlugin
    >({
        plugins: [
            new KeyManager({
                store: new KeyStore(dbConnection),
                kms: {
                    local: new KeyManagementSystem(new PrivateKeyStore(dbConnection, new SecretBox(process.env.KMS_SECRET_KEY ?? ''))),
                },
            }),
            new DIDManager({
                store: new DIDStore(dbConnection),
                defaultProvider: 'did:ethr:linea:goerli',
                providers: {
                    'did:ethr': new EthrDIDProvider({
                        defaultKms: 'local',
                        networks: [
                            {
                                name: 'linea:goerli',
                                rpcUrl: `https://linea-goerli.infura.io/v3/${process.env.INFURA_API_KEY}`,
                                registry: '0x03d5003bf0e79c5f5223588f347eba39afbc3818',
                            },
                        ],
                    }),
                },
            }),
            new DIDResolverPlugin({
                resolver: new Resolver({
                    ...ethrDidResolver({
                        infuraProjectId: process.env.INFURA_API_KEY,
                        networks: [
                            {
                                name: 'linea:goerli',
                                rpcUrl: `https://linea-goerli.infura.io/v3/${process.env.INFURA_API_KEY}`,
                                registry: '0x03d5003bf0e79c5f5223588f347eba39afbc3818',
                            },
                        ],
                    }),
                }),
            }),
            new CredentialPlugin(),
        ],
    })
  9. Create add-service-endpoint.ts and insert the following:

    import { computePublicKey, SigningKey } from '@ethersproject/signing-key';
    import * as u8a from 'uint8arrays';
    import { MinimalImportableKey } from '@veramo/core';
    import { agent } from './setup';
    
    async function main() {
        try {
            // Helper function to find or create did if not found with default alias
            // Added for ease of test and reproduce
            const didToBeUpdated = await findOrCreateNewDid();
           
            if (didToBeUpdated) {
                // Helper function to create DID from private key that holds fund
                const importedIdentifier = await getMetaIdentifier();
                const res = await agent.didManagerAddService({
                    did: didToBeUpdated.did,
                    service: {
                        id: `${didToBeUpdated.did}#Test`,
                        type: 'Test',
                        serviceEndpoint: 'https://test.example.com',
                    },
                    options: { metaIdentifierKeyId: importedIdentifier.controllerKeyId },
                });
                console.log('success update DIDDoc of', didToBeUpdated.did ,"with txHash: " , res);
            }
        } catch (e) {
            console.error(e);
        }
    }
    
    main().catch(console.log);
    
    function importableKeyFromPrivateKey(
        privateKeyHex: string,
        kms: string,
    ): MinimalImportableKey {
        const privateBytes = u8a.fromString(privateKeyHex.toLowerCase(), 'base16');
        const keyPair = new SigningKey(privateBytes);
        const publicKeyHex = keyPair.publicKey.substring(2);
        return {
            type: 'Secp256k1',
            kid: publicKeyHex,
            privateKeyHex,
            publicKeyHex,
            kms,
            meta: {
                algorithms: [
                    'ES256K',
                    'ES256K-R',
                    'eth_signTransaction',
                    'eth_signTypedData',
                    'eth_signMessage',
                    'eth_rawSign',
                ],
            },
        };
    };
    
    async function getMetaIdentifier() {
        const privateKeyHex = process.env.WALLET_PRIVATE_KEY ?? '';
        const key = importableKeyFromPrivateKey(privateKeyHex, 'local');
        const compressedPublicKey = computePublicKey(`0x${key.publicKeyHex}`, true);
        const importedDid = `did:ethr:linea:goerli:${compressedPublicKey}`;
    
        return await agent.didManagerImport({
            did: importedDid,
            provider: 'did:ethr:linea:goerli',
            controllerKeyId: key.kid ?? `test`,
            keys: [key],
            services: [],
        });
    }
    
    async function findOrCreateNewDid() {
        const dids = await agent.didManagerFind({alias: 'linea-goerli-test'});
    
        console.log(`There are ${dids.length} identifiers`);
    
        if (dids.length > 0) {
            if (dids.length == 1) return dids[0];
        }
        else {
            const newDid = await agent.didManagerCreate({alias: 'linea-goerli-test'});
            console.log(`New did created:`);
            console.log(JSON.stringify(newDid, null, 2));
            return newDid;
        }
    }
  10. Should have the similar file structure upon the steps above:
    image

  11. Run npm run execute-with-env add-service-endpoint.ts at project root directory and fails with error shown in Observed behaviour

Observed behaviour

Error: missing provider (operation="sendTransaction", code=UNSUPPORTED_OPERATION, version=abstract-signer/5.7.0)
    at Logger.Logger.makeError (<home-path>/veramo-meta-tx-issue/node_modules/@ethersproject/logger/src.ts/index.ts:269:28)
    at Logger.Logger.throwError (<home-path>/veramo-meta-tx-issue/node_modules/@ethersproject/logger/src.ts/index.ts:281:20)
    at KmsEthereumSigner.Signer._checkProvider (<home-path>/veramo-meta-tx-issue/node_modules/@ethersproject/abstract-signer/src.ts/index.ts:330:38)
    at KmsEthereumSigner.<anonymous> (<home-path>/veramo-meta-tx-issue/node_modules/@ethersproject/abstract-signer/src.ts/index.ts:123:14)
    at step (<home-path>/veramo-meta-tx-issue/node_modules/@ethersproject/abstract-signer/src.ts/index.ts:1:14)
    at Object.next (<home-path>/veramo-meta-tx-issue/node_modules/@ethersproject/abstract-signer/src.ts/index.ts:1:14)
    at <anonymous> (<home-path>/veramo-meta-tx-issue/node_modules/@ethersproject/abstract-signer/src.ts/index.ts:1:14)
    at new Promise (<anonymous>)
    at __awaiter (<home-path>/veramo-meta-tx-issue/node_modules/@ethersproject/abstract-signer/src.ts/index.ts:1:14)
    at KmsEthereumSigner.Signer.sendTransaction (<home-path>/veramo-meta-tx-issue/node_modules/@ethersproject/abstract-signer/src.ts/index.ts:122:70) {
  reason: 'missing provider',
  code: 'UNSUPPORTED_OPERATION',
  operation: 'sendTransaction'
}

Expected behaviour
It show success with txHashfrom didManagerAddService

success update DIDDoc of: did:ethr:linea:goerli:0x01g6..8t7p  with txHash: <txHash generated from the transaction sent to provider>

Example of success behavior will be illustrated in Details section with further elaboration

Details

  1. Upon encountered with the Observed behaviour, I have tried to utilize the deprecated attributes in setup.ts:
    ...
    export const agent = createAgent<
       IDIDManager & IKeyManager & IDataStore & IDataStoreORM & IResolver & ICredentialPlugin
    >({
       plugins: [
           ...
           new DIDManager({
               store: new DIDStore(dbConnection),
               defaultProvider: 'did:ethr:linea:goerli',
               providers: {
                   'did:ethr': new EthrDIDProvider({
                       defaultKms: 'local',
    +                    network: 'linea:goerli',
    +                    rpcUrl: `https://linea-goerli.infura.io/v3/${process.env.INFURA_API_KEY}`,
    +                    registry: '0x03d5003bf0e79c5f5223588f347eba39afbc3818',
    -                    networks: [
    -                        {
    -                            name: 'linea:goerli',
    -                            rpcUrl: `https://linea-goerli.infura.io/v3/${process.env.INFURA_API_KEY}`,
    -                            registry: '0x03d5003bf0e79c5f5223588f347eba39afbc3818',
    -                        },
    -                    ],
                   }),
               },
           }),
           new DIDResolverPlugin({
               resolver: new Resolver({
                   ...ethrDidResolver({
                       infuraProjectId: process.env.INFURA_API_KEY,
                       networks: [
                           {
                               name: 'linea:goerli',
                               rpcUrl: `https://linea-goerli.infura.io/v3/${process.env.INFURA_API_KEY}`,
                               registry: '0x03d5003bf0e79c5f5223588f347eba39afbc3818',
                           },
                       ],
                   }),
               }),
           }),
           new CredentialPlugin(),
       ],
    })
  2. Run npm run execute-with-env add-service-endpoint.ts at project root directory and it will success as shown below:
    success update DIDDoc of: did:ethr:linea:goerli:0x01g6..8t7p  with txHash:  0x56548..fe5f
  3. To verify the updated DID, create list-did.ts and insert the following:
    import { agent } from './setup'
    
    async function main() {
    const identifiers = await agent.didManagerFind({alias: 'linea-goerli-test'});
    
    console.log(`There are ${identifiers.length} identifiers`)
    
    if (identifiers.length > 0) {
        identifiers.map((id) => {
        console.log(id)
        console.log('..................')
        })
    }
    }
    
    main().catch(console.log)
  4. Run npm run execute-with-env list-did.ts and we could see that service is added as shown below:
Identifier {
  did: 'did:ethr:linea:goerli:0x...',
  provider: 'did:ethr:linea:goerli',
  alias: 'linea-goerli-test',
  controllerKeyId: '04...',
  keys: [
    Key {
      kid: '...',
      kms: 'local',
      type: 'Secp256k1',
    }
  ],
  services: [
    Service {
      id: 'did:ethr:linea:goerli:0x0...#Test',
      type: 'Test',
      serviceEndpoint: 'https://test.example.com',
      description: null,
      identifier: undefined
    }
  ],
  ...
}

Additional context

  • Just wonder is this didManagerAddService with options: { metaIdentifierKeyId } function supported yet in CLI tool
  • Apparently the local integration test does not cover for such use case yet on testnet network hence it is probably overlooked while doing the migration from deprecated attributes to networks[].

Versions:

  • Veramo: 5.5.3
  • Browser : N/A
  • Node Version: v21.1.0
@hylim-tech-lover hylim-tech-lover added the bug Something isn't working label Nov 3, 2023
Copy link

stale bot commented Jan 2, 2024

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

@stale stale bot added the wontfix This will not be worked on label Jan 2, 2024
@stale stale bot closed this as completed Jan 10, 2024
@mirceanis mirceanis reopened this Jan 11, 2024
@mirceanis mirceanis added pinned don't close this just for being stale triage and removed wontfix This will not be worked on labels Jan 11, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working pinned don't close this just for being stale triage
Projects
None yet
Development

No branches or pull requests

2 participants