decentralized-identity / veramo

A JavaScript Framework for Verifiable Data
https://veramo.io
Apache License 2.0
432 stars 131 forks source link

`ethers` dependency missing on veramo modules #1295

Closed hylim-tech-lover closed 9 months ago

hylim-tech-lover commented 10 months ago

Bug severity 3

Describe the bug While using 5.5.4-next.25 veramo dependencies to implement coordinate mediation protocol in my application, apparently that some of the underlying child dependencies [will be elaborated below] has switched to use ethers as their dependency but are missing from their corresponding package.json configuration.

Therefore, it will fail if we attempt to use them separately as individual node modules.

To Reproduce Steps to reproduce the behaviour:

  1. Create empty folder with NodeJS installed (version stated below) and run npm init to create a package.json.

  2. Add the example dependencies to package.json:

    "dependencies": {
       "@veramo/core": "5.5.4-next.25",
       "@veramo/credential-eip712": "5.5.4-next.25",
       "@veramo/credential-w3c": "5.5.4-next.25",
       "@veramo/data-store": "5.5.4-next.25",
       "@veramo/did-comm": "5.5.4-next.25",
       "@veramo/did-manager": "5.5.4-next.25",
       "@veramo/did-provider-ethr": "5.5.4-next.25",
       "@veramo/did-resolver": "5.5.4-next.25",
       "@veramo/key-manager": "5.5.4-next.25",
       "@veramo/kms-local": "5.5.4-next.25",
       "@veramo/kv-store": "5.5.4-next.25",
       "@veramo/mediation-manager": "5.5.4-next.25",
       "@veramo/message-handler": "5.5.4-next.25",
    },
    "devDependencies": {
      "@digitak/esrun": "3.2.24",
      "sqlite3": "^5.1.6",
      "typescript": "^5.1.6"
    }
  3. Run npm install to install all dependencies

  4. Create tsconfig.json and insert the following:

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

    import {
     createAgent,
     IAgentPlugin,
     ICredentialIssuer,
     ICredentialPlugin,
     IDataStore,
     IDataStoreORM,
     IDIDManager,
     IIdentifier,
     IKeyManager,
     IResolver,
     MinimalImportableKey,
     TAgent,
    } from '@veramo/core';
    import { CredentialIssuerEIP712 } from '@veramo/credential-eip712';
    import { CredentialPlugin } from '@veramo/credential-w3c';
    import {
     DataStore,
     DataStoreORM,
     DIDStore,
     Entities,
     KeyStore,
     migrations,
     PrivateKeyStore,
    } from '@veramo/data-store';
    import {
     CoordinateMediationRecipientMessageHandler,
     DIDComm,
     DIDCommHttpTransport,
     DIDCommMessageHandler,
    } from '@veramo/did-comm';
    import { DIDManager } from '@veramo/did-manager';
    // Ethr did identity provider
    import { EthrDIDProvider } from '@veramo/did-provider-ethr';
    // Custom resolvers
    import { DIDResolverPlugin } from '@veramo/did-resolver';
    import { KeyManager } from '@veramo/key-manager';
    import { KeyManagementSystem, SecretBox } from '@veramo/kms-local';
    import { KeyValueStore, KeyValueTypeORMStoreAdapter } from '@veramo/kv-store';
    import {
     IMediationManager,
     MediationManagerPlugin,
     MediationResponse,
     PreMediationRequestPolicy,
     RequesterDid,
    } from '@veramo/mediation-manager';
    import { MessageHandler } from '@veramo/message-handler';
    // TypeORM is installed with '@veramo/data-store'
    import { DataSource } from 'typeorm';
    
    const dbConnection = new DataSource({
     type: 'sqlite',
     database: 'database.sqlite',
     synchronize: false,
     migrations,
     migrationsRun: true,
     logging: ['error', 'info', 'warn'],
     entities: Entities,
    }).initialize();
    
    const policyStore = new KeyValueStore<PreMediationRequestPolicy>({
     namespace: 'mediation_policy',
     store: new KeyValueTypeORMStoreAdapter({
       dbConnection,
       namespace: 'mediation_policy',
     }),
    });
    
    const mediationStore = new KeyValueStore<MediationResponse>({
     namespace: 'mediation_response',
     store: new KeyValueTypeORMStoreAdapter({
       dbConnection,
       namespace: 'mediation_response',
     }),
    });
    
    const recipientDidStore = new KeyValueStore<RequesterDid>({
     namespace: 'recipient_did',
     store: new KeyValueTypeORMStoreAdapter({
       dbConnection,
       namespace: 'recipient_did',
     }),
    });
    
    export const agent = createAgent<
     IDIDManager &
     IKeyManager &
     IDataStore &
     IDataStoreORM &
     IResolver &
     ICredentialPlugin &
     ICredentialIssuer &
     IMediationManager;
    >({
     plugins: [
       new KeyManager({
         store: new KeyStore(dbConnection),
         kms: {
           local: new KeyManagementSystem(
             new PrivateKeyStore(
               dbConnection,
               new SecretBox('...'),
             ),
           ),
         },
       }),
       new DIDManager({
         store: new DIDStore(dbConnection),
         defaultProvider: '...',
         providers: {
           'did:ethr': new EthrDIDProvider({
             defaultKms: 'local',
             network: '...',
             rpcUrl: `https://linea-goerli.infura.io/v3/'....'`,
           }),
         },
       }),
       new MessageHandler({
         messageHandlers: [
           new DIDCommMessageHandler(),
           new CoordinateMediationRecipientMessageHandler(),
         ],
       }),
       new DIDComm({ transports: [new DIDCommHttpTransport()] }),
       new DIDResolverPlugin({...}),
       new MediationManagerPlugin(
             false,
             policyStore,
             mediationStore,
             recipientDidStore,
           ),
       new CredentialPlugin(),
       new CredentialIssuerEIP712(),
       new DataStore(dbConnection),
       new DataStoreORM(dbConnection),
     ],
    });
  6. Create get-all-mediation.ts and insert the following:

    import { agent } from './setup';
    
    async function main() {
     try {
       // This is just an example of API call. It should fail if we use any of agent API call involving 'ethers'
       const mediations = await agent.mediationManagerGetAllMediations();
       console.log(mediations);
     } catch (e) {
       console.error(e);
     }
    }
    
    main().catch(console.log);
  7. Run npm run esrun get-all-mediation.ts at project root directory and fails with error shown in Observed behaviour

Observed behaviour image

Expected behaviour Success message without dependency error

Short term Fix / Remediation

  1. Upon identifying the root cause, run npm install ethers at project root directory. package.json should be updated as shown below:
    "dependencies": {
       "@veramo/core": "5.5.4-next.25",
       "@veramo/credential-eip712": "5.5.4-next.25",
       "@veramo/credential-w3c": "5.5.4-next.25",
       "@veramo/data-store": "5.5.4-next.25",
       "@veramo/did-comm": "5.5.4-next.25",
       "@veramo/did-manager": "5.5.4-next.25",
       "@veramo/did-provider-ethr": "5.5.4-next.25",
       "@veramo/did-resolver": "5.5.4-next.25",
       "@veramo/key-manager": "5.5.4-next.25",
       "@veramo/kms-local": "5.5.4-next.25",
       "@veramo/kv-store": "5.5.4-next.25",
       "@veramo/mediation-manager": "5.5.4-next.25",
       "@veramo/message-handler": "5.5.4-next.25",
    +   "ethers": "6.9.0",
    },
    "devDependencies": {
      "@digitak/esrun": "3.2.24",
      "sqlite3": "^5.1.6",
      "typescript": "^5.1.6"
    }
  2. After installed ethers as dependency, all veramo modules ran as expected. Despite solving this with the temporary workaround, however it is less than ideal as the ethers version might cause breaking changes.

Suggestion

  1. Since the error persist due to the missing dependency in each of the module, I would like to suggest to include the ethers into the impacted modules in packages folder. For example: @veramo/utils https://github.com/decentralized-identity/veramo/blob/462735d138bc4984c0fcf3f72ca7d49e3187ceb7/packages/utils/package.json#L12-L25

The following are the other modules that use ethers as dependency:

I would be gladly to make the necessary changes as PR if it is deemed acceptable. Of course would be more than happy to accept any feedbacks on such approach.

Additional context

  1. There is a relevant discussion here that might be point of interest on how to manage shared dependency across each modules in packages folder albeit no active updates recently.

Versions (please complete the following information):

mirceanis commented 10 months ago

This is indeed a bug and I'm surprised that pnpm didn't cause the build to break.

The fix should be easy, as you suggested. If you plan to propose a PR with the fix, please include the updated pnpm lock file.

P.S. Kudos for such a detailed issue 🚀!

hylim-tech-lover commented 10 months ago

Will make the PR ASAP.

Tqvm.