/* eslint-disable camelcase */
import {
getDidNonce,
getStateChange,
} from '../utils/misc';
import WithParamsAndPublicKeys from './WithParamsAndPublicKeys';
import { createDidSig, typedHexDID } from '../utils/did';
const STATE_CHANGES = {
AddParams: 'AddOffchainSignatureParams',
RemoveParams: 'RemoveOffchainSignatureParams',
AddPublicKey: 'AddOffchainSignaturePublicKey',
RemovePublicKey: 'RemoveOffchainSignaturePublicKey',
};
const METHODS = {
Params: 'signatureParams',
PublicKeys: 'publicKeys',
};
/** Class to write offchain signature parameters and keys on chain */
export default class OffchainSignaturesModule extends WithParamsAndPublicKeys {
/**
* sets the dock api for this module
* @constructor
* @param {object} api - PolkadotJS API Reference
* @param {Function} signAndSend - Callback signing and sending
*/
constructor(api, signAndSend) {
super();
this.api = api;
this.moduleName = 'offchainSignatures';
this.stateChanges = STATE_CHANGES;
this.methods = METHODS;
this.module = api.tx[this.moduleName];
this.signAndSend = signAndSend;
}
/**
* Builds module-specific public key from the provided value.
*/
static buildPublicKey(publicKey) {
return publicKey;
}
/**
* Get last params written by this DID
* @param did
* @returns {Promise<{bytes: string}|null>}
*/
async getLastParamsWritten(did) {
const hexId = typedHexDID(this.api, did);
const counter = await this.api.query[this.moduleName].paramsCounter(hexId);
if (counter > 0) {
const resp = await this.queryParamsFromChain(hexId, counter);
if (resp) {
return this.createParamsObjFromChainResponse(resp);
}
}
return null;
}
/**
* Get all params written by a DID
* @param did
* @returns {Promise<object[]>}
*/
async getAllParamsByDid(did) {
const hexId = typedHexDID(this.api, did);
const params = [];
const counter = await this.api.query[this.moduleName].paramsCounter(hexId);
if (counter > 0) {
for (let i = 1; i <= counter; i++) {
// eslint-disable-next-line no-await-in-loop
const param = await this.getParamsByHexDid(hexId, i);
if (param != null) {
params.push(param);
}
}
}
return params;
}
async queryParamsFromChain(hexDid, counter) {
const params = await this.api.query[this.moduleName][this.methods.Params](
hexDid,
counter,
);
if (params.isSome) {
return params.unwrap();
} else {
return null;
}
}
async queryPublicKeyFromChain(hexDid, keyId) {
const key = await this.api.query[this.moduleName][this.methods.PublicKeys](
hexDid.asDid,
keyId,
);
if (key.isSome) {
return key.unwrap();
} else {
return null;
}
}
/**
* Create transaction to add a public key
* @param publicKey - public key to add.
* @param targetDid - The DID to which key is being added
* @param signerDid - The DID that is adding the key by signing the payload because it controls `targetDid`
* @param signingKeyRef - Signer's signingKeyRef
* @param nonce - The nonce to be used for sending this transaction. If not provided then `didModule` must be provided.
* @param didModule - Reference to the DID module. If nonce is not provided then the next nonce for the DID is fetched by
* using this
* @returns {Promise<*>}
*/
async createAddPublicKeyTx(
publicKey,
targetDid,
signerDid,
signingKeyRef,
{ nonce = undefined, didModule = undefined },
) {
const offchainPublicKey = this.constructor.buildPublicKey(publicKey);
const targetHexDid = typedHexDID(this.api, targetDid).asDid;
const signerHexDid = typedHexDID(this.api, signerDid);
const [addPk, signature] = await this.createSignedAddPublicKey(
offchainPublicKey,
targetHexDid,
signerHexDid,
signingKeyRef,
{ nonce, didModule },
);
return this.module.addPublicKey(addPk, signature);
}
/**
* Create transaction to remove public key
* @param removeKeyId - The key index for key to remove.
* @param targetDid - The DID from which key is being removed
* @param signerDid - The DID that is removing the key by signing the payload because it controls `targetDid`
* @param signingKeyRef - Signer's signingKeyRef
* @param nonce - The nonce to be used for sending this transaction. If not provided then `didModule` must be provided.
* @param didModule - Reference to the DID module. If nonce is not provided then the next nonce for the DID is fetched by
* using this
* @returns {Promise<*>}
*/
async createRemovePublicKeyTx(
removeKeyId,
targetDid,
signerDid,
signingKeyRef,
{ nonce = undefined, didModule = undefined },
) {
const targetHexDid = typedHexDID(this.api, targetDid).asDid;
const signerHexDid = typedHexDID(this.api, signerDid);
const [removePk, signature] = await this.createSignedRemovePublicKey(
removeKeyId,
targetHexDid,
signerHexDid,
signingKeyRef,
{ nonce, didModule },
);
return this.module.removePublicKey(removePk, signature);
}
/**
* Add a public key
* @param publicKey - public key to add.
* @param targetDid - The DID to which key is being added
* @param signerDid - The DID that is adding the key by signing the payload because it controls `targetDid`
* @param signingKeyRef - Signer's signingKeyRef
* @param nonce - The nonce to be used for sending this transaction. If not provided then `didModule` must be provided.
* @param didModule - Reference to the DID module. If nonce is not provided then the next nonce for the DID is fetched by
* using this
* @param waitForFinalization
* @param params
* @returns {Promise<*>}
*/
async addPublicKey(
publicKey,
targetDid,
signerDid,
signingKeyRef,
{ nonce = undefined, didModule = undefined },
waitForFinalization = true,
params = {},
) {
const tx = await this.createAddPublicKeyTx(
publicKey,
targetDid,
signerDid,
signingKeyRef,
{ nonce, didModule },
);
return this.signAndSend(tx, waitForFinalization, params);
}
/**
* Remove public key
* @param removeKeyId - The key index for key to remove.
* @param targetDid - The DID from which key is being removed
* @param signerDid - The DID that is removing the key by signing the payload because it controls `targetDid`
* @param signingKeyRef - Signer's signing key reference
* @param nonce - The nonce to be used for sending this transaction. If not provided then `didModule` must be provided.
* @param didModule - Reference to the DID module. If nonce is not provided then the next nonce for the DID is fetched by
* using this
* @param waitForFinalization
* @param params
* @returns {Promise<*>}
*/
async removePublicKey(
removeKeyId,
targetDid,
signerDid,
signingKeyRef,
{ nonce = undefined, didModule = undefined },
waitForFinalization = true,
params = {},
) {
const tx = await this.createRemovePublicKeyTx(
removeKeyId,
targetDid,
signerDid,
signingKeyRef,
{ nonce, didModule },
);
return this.signAndSend(tx, waitForFinalization, params);
}
async createSignedAddPublicKey(
publicKey,
targetHexDid,
signerHexDid,
signingKeyRef,
{ nonce = undefined, didModule = undefined },
) {
// eslint-disable-next-line no-param-reassign
nonce = await getDidNonce(signerHexDid, nonce, didModule);
const addPk = { key: publicKey, did: targetHexDid, nonce };
const signature = this.signAddPublicKey(signingKeyRef, addPk);
const didSig = createDidSig(signerHexDid, signingKeyRef, signature);
return [addPk, didSig];
}
async createSignedRemovePublicKey(
removeKeyId,
targetHexDid,
signerHexDid,
signingKeyRef,
{ nonce = undefined, didModule = undefined },
) {
// eslint-disable-next-line no-param-reassign
nonce = await getDidNonce(signerHexDid, nonce, didModule);
const removeKey = {
keyRef: [targetHexDid, removeKeyId],
did: targetHexDid,
nonce,
};
const signature = this.signRemovePublicKey(signingKeyRef, removeKey);
const didSig = createDidSig(signerHexDid, signingKeyRef, signature);
return [removeKey, didSig];
}
/**
*
* @param signingKeyRef
* @param params
* @returns {Signature}
*/
signAddParams(signingKeyRef, params) {
const serialized = getStateChange(
this.api,
this.stateChanges.AddParams,
params,
);
return signingKeyRef.sign(serialized);
}
/**
*
* @param signingKeyRef
* @param pk
* @returns {Signature}
*/
signAddPublicKey(signingKeyRef, pk) {
const serialized = getStateChange(
this.api,
this.stateChanges.AddPublicKey,
pk,
);
return signingKeyRef.sign(serialized);
}
/**
*
* @param signingKeyRef
* @param ref
* @returns {Signature}
*/
signRemoveParams(signingKeyRef, ref) {
const serialized = getStateChange(
this.api,
this.stateChanges.RemoveParams,
ref,
);
return signingKeyRef.sign(serialized);
}
/**
*
* @param signingKeyRef
* @param ref
* @returns {Signature}
*/
signRemovePublicKey(signingKeyRef, ref) {
const serialized = getStateChange(
this.api,
this.stateChanges.RemovePublicKey,
ref,
);
return signingKeyRef.sign(serialized);
}
}