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

Allow signed addKey/addService return type for later submission by other agent #1373

Open
radleylewis opened this issue Apr 9, 2024 · 1 comment
Labels
did-manager enhancement New feature or request

Comments

@radleylewis
Copy link
Contributor

radleylewis commented Apr 9, 2024

Is your feature request related to a problem? Please describe.
We need to invoke the below methods (using ethr-did-provider) which result in writes to the network:

  • didManagerAddKey (specifically X25519 and Ed25519 key types); and,
  • didManagerAddService (e.g. did-comm endpoint).
    As these calls invoke eth_sendTransaction which are listed as BLOCKED_RPC_METHODS within MetaMask Snaps (more information here) the calls to these methods fail (see bottom of issue for error example).

Describe the solution you'd like
I am open to suggestions on how best to approach this issue. One approach would be to allow an option/flag that would not submit the transaction to the network, but rather return the prepared (signed) transaction for submission in another context (i.e. via a Veramo agent instantiated in the DApp invoking). The addKey method looks like the below (did-ethr):

  async addKey(
    { identifier, key, options }: { identifier: IIdentifier; key: IKey; options?: TransactionOptions },
    context: IRequiredContext,
  ): Promise<any> {
    const ethrDid = await this.getEthrDidController(identifier, context)
    const usg = key.type === 'X25519' ? 'enc' : 'veriKey'
    const encoding = key.type === 'X25519' ? 'base58' : options?.encoding || 'hex'
    const attrName = `did/pub/${key.type}/${usg}/${encoding}`
    const attrValue = '0x' + key.publicKeyHex
    const ttl = options?.ttl || this.ttl || 86400
    const gasLimit = options?.gasLimit || this.gas || DEFAULT_GAS_LIMIT
    if (options?.metaIdentifierKeyId) {
      const metaHash = await ethrDid.createSetAttributeHash(attrName, attrValue, ttl)
      const canonicalSignature = await EthrDIDProvider.createMetaSignature(context, identifier, metaHash)

      const metaEthrDid = await this.getEthrDidController(identifier, context, options.metaIdentifierKeyId!)
      debug('ethrDid.addKeySigned %o', { attrName, attrValue, ttl, gasLimit })
      delete options.metaIdentifierKeyId
      const txHash = await metaEthrDid.setAttributeSigned(
        attrName,
        attrValue,
        ttl,
        { sigV: canonicalSignature.v, sigR: canonicalSignature.r, sigS: canonicalSignature.s },
        {
          ...options,
          gasLimit,
        },
      )
      debug(`ethrDid.addKeySigned tx = ${txHash}`)
      return txHash
    } else {
      debug('ethrDid.setAttribute %o', { attrName, attrValue, ttl, gasLimit })
      const txHash = await ethrDid.setAttribute(attrName, attrValue, ttl, undefined, {
        ...options,
        gasLimit,
      })
      debug(`ethrDid.addKey tx = ${txHash}`)
      return txHash
    }
  }

The returned (prepared and signed but not submitted) return type would look something like the below:

return {
  attrName,
  attrValue,
  ttl,
  gasLimit,
  { sigV: canonicalSignature.v, sigR: canonicalSignature.r, sigS: canonicalSignature.s },
  options,
}

Describe alternatives you've considered
The approach that I have outlined above would necessitate the implementation of a new function (e.g. submitAddKey) so I am keen to hear other approaches.

Additional context
Any method that invokes the eth_sendTransaction is going to result in this issue with errors corresponding broadly to the below example:

Error#1: could not coalesce error (error={ "code": -32601, "data": { "method": "eth_sendTransaction" }, "message": "The method does not exist / is not available." }, payload={ "id": 7, "jsonrpc": "2.0", "method": "eth_sendTransaction", "params": [ { "data": "0x7ad4b0a4000000000000000000000000ab0207f2084bafd9814fd0cf9a3736adf03f117b6469642f7075622f456432353531392f766572694b65792f686578000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000015180000000000000000000000000000000000000000000000000000000000000002007cf5bc93cc16d1559ac91b05e444bc59b554cb39d9f7cc6d1f7f2c6ddde2bd9", "from": "0xab0207f2084bafd9814fd0cf9a3736adf03f117b", "gas": "0x186a0", "to": "0x03d5003bf0e79c5f5223588f347eba39afbc3818" } ] }, code=UNKNOWN_ERROR, version=6.10.0)
@radleylewis radleylewis added the enhancement New feature or request label Apr 9, 2024
@radleylewis
Copy link
Contributor Author

Building on the above, the amended addKey method would take an option (on the existing options object of signOnly: boolean. If set to true, then the didManagerAddKey (via the provider addKey method would return an object that looks like the following TypeScript tuple type (which conforms to the function parameters of metaEthrDid.setAttributeSigned):

type TxnParams = [
    attrName: string,
    attrValue: string,
    ttl: number,
    signature: { sigV: number; sigR: string; sigS: string },
    options: Record<string, any>,
];

In the introduced didManagerSubmitTransaction the function signature would then look like the following:

async didManagerSubmitTransaction(args: TxnParams, context: IAgentContext<IKeyManager>): Promise<unknown>;

This method (didManagerSubmitTransaction) can then be called from another context (in an agent not constrained by the snap environment) referencing the options.metaIdentifierKeyId for submission to the network.

async didManagerSubmitTransaction(args: TxnParams, context: IAgentContext<IKeyManager>): Promise<any> {
  // this method invokes a new provider method, which means that the calling agent calls `metaEthrDid.setAttributeSigned`
  // with the provided txnParams (that were returned from the agent call in the first invocation within the MM Snap. 
  return provider.submitTransaction(args, context); // additional function made available on `did-ethr-provider`
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
did-manager enhancement New feature or request
Projects
None yet
2 participants