Update registry SDK record methods to use cosmjs #2
@ -13,8 +13,6 @@ import { ethToEthermint } from '@tharsis/address-converter';
|
|||||||
import { encodeSecp256k1Pubkey } from '@cosmjs/amino';
|
import { encodeSecp256k1Pubkey } from '@cosmjs/amino';
|
||||||
import { DirectSecp256k1Wallet } from '@cosmjs/proto-signing';
|
import { DirectSecp256k1Wallet } from '@cosmjs/proto-signing';
|
||||||
|
|
||||||
import { Payload, Record as RegistryRecord, Signature } from './types';
|
|
||||||
|
|
||||||
const AMINO_PREFIX = 'EB5AE98721';
|
const AMINO_PREFIX = 'EB5AE98721';
|
||||||
const HDPATH = "m/44'/60'/0'/0";
|
const HDPATH = "m/44'/60'/0'/0";
|
||||||
const ACCOUNT_PREFIX = 'laconic';
|
const ACCOUNT_PREFIX = 'laconic';
|
||||||
@ -42,7 +40,6 @@ export class Account {
|
|||||||
_ethAddress!: string;
|
_ethAddress!: string;
|
||||||
_wallet!: DirectSecp256k1Wallet;
|
_wallet!: DirectSecp256k1Wallet;
|
||||||
_address!: string;
|
_address!: string;
|
||||||
_publicKeyLaconic2!: string;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate bip39 mnemonic.
|
* Generate bip39 mnemonic.
|
||||||
@ -98,10 +95,6 @@ export class Account {
|
|||||||
return this._address;
|
return this._address;
|
||||||
}
|
}
|
||||||
|
|
||||||
get publicKeyLaconic2 () {
|
|
||||||
return this._publicKeyLaconic2;
|
|
||||||
}
|
|
||||||
|
|
||||||
get wallet () {
|
get wallet () {
|
||||||
return this._wallet;
|
return this._wallet;
|
||||||
}
|
}
|
||||||
@ -114,7 +107,6 @@ export class Account {
|
|||||||
|
|
||||||
const [account] = await this._wallet.getAccounts();
|
const [account] = await this._wallet.getAccounts();
|
||||||
this._address = account.address;
|
this._address = account.address;
|
||||||
this._publicKeyLaconic2 = Buffer.from(AMINO_PREFIX + toHex(account.pubkey), 'hex').toString('base64');
|
|
||||||
|
|
||||||
// Generate public key.
|
// Generate public key.
|
||||||
this._publicKey = secp256k1.publicKeyCreate(this._privateKey);
|
this._publicKey = secp256k1.publicKeyCreate(this._privateKey);
|
||||||
@ -127,7 +119,7 @@ export class Account {
|
|||||||
this._formattedCosmosAddress = ethToEthermint(this._ethAddress);
|
this._formattedCosmosAddress = ethToEthermint(this._ethAddress);
|
||||||
|
|
||||||
// 4. Generate registry formatted public key.
|
// 4. Generate registry formatted public key.
|
||||||
const publicKeyInHex = AMINO_PREFIX + toHex(this._publicKey);
|
const publicKeyInHex = AMINO_PREFIX + toHex(account.pubkey);
|
||||||
this._registryPublicKey = Buffer.from(publicKeyInHex, 'hex').toString('base64');
|
this._registryPublicKey = Buffer.from(publicKeyInHex, 'hex').toString('base64');
|
||||||
|
|
||||||
// 5. Generate registry formatted address.
|
// 5. Generate registry formatted address.
|
||||||
@ -169,20 +161,6 @@ export class Account {
|
|||||||
return Buffer.from(sigObj.signature);
|
return Buffer.from(sigObj.signature);
|
||||||
}
|
}
|
||||||
|
|
||||||
async signPayload (payload: Payload) {
|
|
||||||
assert(payload);
|
|
||||||
|
|
||||||
const { record } = payload;
|
|
||||||
const messageToSign = RegistryRecord.getMessageToSign(record);
|
|
||||||
|
|
||||||
const sig = await this.signRecord(messageToSign);
|
|
||||||
assert(this.registryPublicKey);
|
|
||||||
const signature = new Signature(this.registryPublicKey, sig.toString('base64'));
|
|
||||||
payload.addSignature(signature);
|
|
||||||
|
|
||||||
return signature;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sign message.
|
* Sign message.
|
||||||
*/
|
*/
|
||||||
|
69
src/index.ts
69
src/index.ts
@ -4,25 +4,19 @@ import {
|
|||||||
Chain,
|
Chain,
|
||||||
Sender,
|
Sender,
|
||||||
Fee,
|
Fee,
|
||||||
createMessageSend,
|
|
||||||
MessageSendParams
|
MessageSendParams
|
||||||
} from '@tharsis/transactions';
|
} from '@tharsis/transactions';
|
||||||
import { DeliverTxResponse, GasPrice, StdFee } from '@cosmjs/stargate';
|
import { DeliverTxResponse, StdFee } from '@cosmjs/stargate';
|
||||||
|
|
||||||
import { RegistryClient } from './registry-client';
|
import { RegistryClient } from './registry-client';
|
||||||
import { Account } from './account';
|
import { Account } from './account';
|
||||||
import { createTransaction } from './txbuilder';
|
import { createTransaction } from './txbuilder';
|
||||||
import { Payload, Record } from './types';
|
|
||||||
import { Util } from './util';
|
import { Util } from './util';
|
||||||
import {
|
import {
|
||||||
createTxMsgAssociateBond,
|
createTxMsgAssociateBond,
|
||||||
createTxMsgCancelBond,
|
|
||||||
createTxMsgCreateBond,
|
|
||||||
createTxMsgDissociateBond,
|
createTxMsgDissociateBond,
|
||||||
createTxMsgDissociateRecords,
|
createTxMsgDissociateRecords,
|
||||||
createTxMsgReAssociateRecords,
|
createTxMsgReAssociateRecords,
|
||||||
createTxMsgRefillBond,
|
|
||||||
createTxMsgWithdrawBond,
|
|
||||||
MessageMsgAssociateBond,
|
MessageMsgAssociateBond,
|
||||||
MessageMsgCancelBond,
|
MessageMsgCancelBond,
|
||||||
MessageMsgCreateBond,
|
MessageMsgCreateBond,
|
||||||
@ -33,22 +27,12 @@ import {
|
|||||||
MessageMsgWithdrawBond
|
MessageMsgWithdrawBond
|
||||||
} from './messages/bond';
|
} from './messages/bond';
|
||||||
import {
|
import {
|
||||||
createTxMsgDeleteName,
|
|
||||||
createTxMsgReserveAuthority,
|
|
||||||
createTxMsgSetAuthorityBond,
|
|
||||||
createTxMsgSetName,
|
|
||||||
createTxMsgSetRecord,
|
|
||||||
MessageMsgDeleteName,
|
MessageMsgDeleteName,
|
||||||
MessageMsgReserveAuthority,
|
|
||||||
MessageMsgSetAuthorityBond,
|
MessageMsgSetAuthorityBond,
|
||||||
MessageMsgSetName,
|
MessageMsgSetName,
|
||||||
MessageMsgSetRecord,
|
NAMESERVICE_ERRORS
|
||||||
NAMESERVICE_ERRORS,
|
|
||||||
parseMsgSetRecordResponse
|
|
||||||
} from './messages/registry';
|
} from './messages/registry';
|
||||||
import {
|
import {
|
||||||
createTxMsgCommitBid,
|
|
||||||
createTxMsgRevealBid,
|
|
||||||
MessageMsgCommitBid,
|
MessageMsgCommitBid,
|
||||||
MessageMsgRevealBid
|
MessageMsgRevealBid
|
||||||
} from './messages/auction';
|
} from './messages/auction';
|
||||||
@ -487,7 +471,7 @@ export class Registry {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// TODO: Parse error response
|
// TODO: Parse error response
|
||||||
return response;
|
return laconicClient.registry.decode(response.msgResponses[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -511,52 +495,7 @@ export class Registry {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// TODO: Parse error response form delete name
|
// TODO: Parse error response form delete name
|
||||||
return response;
|
return laconicClient.registry.decode(response.msgResponses[0]);
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Submit record transaction.
|
|
||||||
* @param privateKey - private key in HEX to sign message.
|
|
||||||
* @param txPrivateKey - private key in HEX to sign transaction.
|
|
||||||
*/
|
|
||||||
async _submitRecordTx (
|
|
||||||
{ privateKey, record, bondId }: { privateKey: string, record: any, bondId: string },
|
|
||||||
txPrivateKey: string,
|
|
||||||
fee: Fee
|
|
||||||
) {
|
|
||||||
if (!isKeyValid(privateKey)) {
|
|
||||||
throw new Error('Registry privateKey should be a hex string.');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isKeyValid(bondId)) {
|
|
||||||
throw new Error(`Invalid bondId: ${bondId}.`);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sign record.
|
|
||||||
const recordSignerAccount = new Account(Buffer.from(privateKey, 'hex'));
|
|
||||||
const registryRecord = new Record(record);
|
|
||||||
const payload = new Payload(registryRecord);
|
|
||||||
await recordSignerAccount.signPayload(payload);
|
|
||||||
|
|
||||||
// Send record payload Tx.
|
|
||||||
txPrivateKey = txPrivateKey || recordSignerAccount.getPrivateKey();
|
|
||||||
return this._submitRecordPayloadTx({ payload, bondId }, txPrivateKey, fee);
|
|
||||||
}
|
|
||||||
|
|
||||||
async _submitRecordPayloadTx (params: MessageMsgSetRecord, privateKey: string, fee: Fee) {
|
|
||||||
if (!isKeyValid(privateKey)) {
|
|
||||||
throw new Error('Registry privateKey should be a hex string.');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isKeyValid(params.bondId)) {
|
|
||||||
throw new Error(`Invalid bondId: ${params.bondId}.`);
|
|
||||||
}
|
|
||||||
|
|
||||||
const account = new Account(Buffer.from(privateKey, 'hex'));
|
|
||||||
const sender = await this._getSender(account);
|
|
||||||
|
|
||||||
const msg = createTxMsgSetRecord(this._chain, sender, fee, '', params);
|
|
||||||
return this._submitTx(msg, privateKey, sender);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -16,7 +16,7 @@ import { MsgCommitBidEncodeObject, MsgRevealBidEncodeObject, auctionTypes, typeU
|
|||||||
import { Payload } from './proto2/cerc/registry/v1/tx';
|
import { Payload } from './proto2/cerc/registry/v1/tx';
|
||||||
import { Record, Signature } from './proto2/cerc/registry/v1/registry';
|
import { Record, Signature } from './proto2/cerc/registry/v1/registry';
|
||||||
import { Account } from './account';
|
import { Account } from './account';
|
||||||
import { Record as RegistryRecord } from './types';
|
import { Util } from './util';
|
||||||
|
|
||||||
export const laconicDefaultRegistryTypes: ReadonlyArray<[string, GeneratedType]> = [
|
export const laconicDefaultRegistryTypes: ReadonlyArray<[string, GeneratedType]> = [
|
||||||
...defaultRegistryTypes,
|
...defaultRegistryTypes,
|
||||||
@ -200,10 +200,10 @@ export class LaconicClient extends SigningStargateClient {
|
|||||||
// Sign record.
|
// Sign record.
|
||||||
const recordSignerAccount = new Account(Buffer.from(params.privateKey, 'hex'));
|
const recordSignerAccount = new Account(Buffer.from(params.privateKey, 'hex'));
|
||||||
await recordSignerAccount.init();
|
await recordSignerAccount.init();
|
||||||
const messageToSign = RegistryRecord.getMessageToSign(params.record);
|
const messageToSign = Util.sortJSON(params.record);
|
||||||
const sig = await recordSignerAccount.signRecord(messageToSign);
|
const sig = await recordSignerAccount.signRecord(messageToSign);
|
||||||
|
|
||||||
const signature = Signature.fromJSON({ sig: sig.toString('base64'), pubKey: recordSignerAccount.publicKeyLaconic2 });
|
const signature = Signature.fromJSON({ sig: sig.toString('base64'), pubKey: recordSignerAccount.registryPublicKey });
|
||||||
|
|
||||||
const payload = Payload.fromJSON({ record: registryRecord, signatures: [signature] });
|
const payload = Payload.fromJSON({ record: registryRecord, signatures: [signature] });
|
||||||
|
|
||||||
|
@ -8,9 +8,7 @@ import {
|
|||||||
} from '@tharsis/transactions';
|
} from '@tharsis/transactions';
|
||||||
|
|
||||||
import * as registryTx from '../proto/vulcanize/registry/v1beta1/tx';
|
import * as registryTx from '../proto/vulcanize/registry/v1beta1/tx';
|
||||||
import * as registry from '../proto/vulcanize/registry/v1beta1/registry';
|
|
||||||
import { createTx } from './util';
|
import { createTx } from './util';
|
||||||
import { Payload } from '../types';
|
|
||||||
|
|
||||||
const MSG_RESERVE_AUTHORITY_TYPES = {
|
const MSG_RESERVE_AUTHORITY_TYPES = {
|
||||||
MsgValue: [
|
MsgValue: [
|
||||||
@ -97,11 +95,6 @@ export interface MessageMsgSetName {
|
|||||||
cid: string
|
cid: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface MessageMsgSetRecord {
|
|
||||||
bondId: string
|
|
||||||
payload: Payload
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface MessageMsgSetAuthorityBond {
|
export interface MessageMsgSetAuthorityBond {
|
||||||
name: string
|
name: string
|
||||||
bondId: string
|
bondId: string
|
||||||
@ -159,30 +152,6 @@ export function createTxMsgSetName (
|
|||||||
return createTx(chain, sender, fee, memo, types, msg, msgCosmos);
|
return createTx(chain, sender, fee, memo, types, msg, msgCosmos);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function createTxMsgSetRecord (
|
|
||||||
chain: Chain,
|
|
||||||
sender: Sender,
|
|
||||||
fee: Fee,
|
|
||||||
memo: string,
|
|
||||||
params: MessageMsgSetRecord
|
|
||||||
) {
|
|
||||||
const types = generateTypes(MSG_SET_RECORD_TYPES);
|
|
||||||
|
|
||||||
const msg = createMsgSetRecord(
|
|
||||||
params.bondId,
|
|
||||||
params.payload,
|
|
||||||
sender.accountAddress
|
|
||||||
);
|
|
||||||
|
|
||||||
const msgCosmos = protoCreateMsgSetRecord(
|
|
||||||
params.bondId,
|
|
||||||
params.payload,
|
|
||||||
sender.accountAddress
|
|
||||||
);
|
|
||||||
|
|
||||||
return createTx(chain, sender, fee, memo, types, msg, msgCosmos);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function createTxMsgSetAuthorityBond (
|
export function createTxMsgSetAuthorityBond (
|
||||||
chain: Chain,
|
chain: Chain,
|
||||||
sender: Sender,
|
sender: Sender,
|
||||||
@ -293,51 +262,6 @@ const protoCreateMsgSetName = (
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
function createMsgSetRecord (
|
|
||||||
bondId: string,
|
|
||||||
payload: Payload,
|
|
||||||
signer: string
|
|
||||||
) {
|
|
||||||
return {
|
|
||||||
type: 'registry/SetRecord',
|
|
||||||
value: {
|
|
||||||
bond_id: bondId,
|
|
||||||
signer,
|
|
||||||
payload: payload.serialize()
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
const protoCreateMsgSetRecord = (
|
|
||||||
bondId: string,
|
|
||||||
payloadData: Payload,
|
|
||||||
signer: string
|
|
||||||
) => {
|
|
||||||
const record = new registry.vulcanize.registry.v1beta1.Record(payloadData.record.serialize());
|
|
||||||
|
|
||||||
const signatures = payloadData.signatures.map(
|
|
||||||
signature => new registry.vulcanize.registry.v1beta1.Signature(
|
|
||||||
signature.serialize()
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
const payload = new registryTx.vulcanize.registry.v1beta1.Payload({
|
|
||||||
record,
|
|
||||||
signatures
|
|
||||||
});
|
|
||||||
|
|
||||||
const setNameMessage = new registryTx.vulcanize.registry.v1beta1.MsgSetRecord({
|
|
||||||
bond_id: bondId,
|
|
||||||
signer,
|
|
||||||
payload
|
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
|
||||||
message: setNameMessage,
|
|
||||||
path: 'vulcanize.registry.v1beta1.MsgSetRecord'
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
function createMsgSetAuthorityBond (
|
function createMsgSetAuthorityBond (
|
||||||
name: string,
|
name: string,
|
||||||
bondId: string,
|
bondId: string,
|
||||||
|
@ -95,7 +95,6 @@ const nameserviceExpiryTests = () => {
|
|||||||
expect(records).toHaveLength(0);
|
expect(records).toHaveLength(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
// TODO: Check authority not expiring
|
|
||||||
test('Check authority expired without bond balance', async () => {
|
test('Check authority expired without bond balance', async () => {
|
||||||
const [authority] = await registry.lookupAuthorities([authorityName]);
|
const [authority] = await registry.lookupAuthorities([authorityName]);
|
||||||
expect(authority.status).toBe('expired');
|
expect(authority.status).toBe('expired');
|
||||||
|
132
src/types.ts
132
src/types.ts
@ -1,132 +0,0 @@
|
|||||||
import assert from 'assert';
|
|
||||||
import { Validator } from 'jsonschema';
|
|
||||||
|
|
||||||
import RecordSchema from './schema/record.json';
|
|
||||||
import { Util } from './util';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Record.
|
|
||||||
*/
|
|
||||||
export class Record {
|
|
||||||
_record: any;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* New Record.
|
|
||||||
*/
|
|
||||||
constructor (record: any) {
|
|
||||||
assert(record);
|
|
||||||
|
|
||||||
const validator = new Validator();
|
|
||||||
const result = validator.validate(record, RecordSchema);
|
|
||||||
if (!result.valid) {
|
|
||||||
result.errors.map(console.error);
|
|
||||||
throw new Error('Invalid record input.');
|
|
||||||
}
|
|
||||||
|
|
||||||
this._record = record;
|
|
||||||
}
|
|
||||||
|
|
||||||
get attributes () {
|
|
||||||
return Buffer.from(JSON.stringify(this._record), 'binary');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Serialize record.
|
|
||||||
*/
|
|
||||||
serialize () {
|
|
||||||
return {
|
|
||||||
id: '_',
|
|
||||||
bond_id: '_',
|
|
||||||
create_time: '_',
|
|
||||||
expiry_time: '_',
|
|
||||||
// Setting deleted as false (zero value) throws error in EIP712 signature verification.
|
|
||||||
deleted: true,
|
|
||||||
attributes: this.attributes
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get message to calculate record signature.
|
|
||||||
*/
|
|
||||||
|
|
||||||
// TODO: Replace any type for record
|
|
||||||
static getMessageToSign (record: any) {
|
|
||||||
return Util.sortJSON(record);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Record Signature.
|
|
||||||
*/
|
|
||||||
export class Signature {
|
|
||||||
_pubKey: string;
|
|
||||||
_sig: string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* New Signature.
|
|
||||||
*/
|
|
||||||
constructor (pubKey: string, sig: string) {
|
|
||||||
assert(pubKey);
|
|
||||||
assert(sig);
|
|
||||||
|
|
||||||
this._pubKey = pubKey;
|
|
||||||
this._sig = sig;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Serialize Signature.
|
|
||||||
*/
|
|
||||||
serialize () {
|
|
||||||
return Util.sortJSON({
|
|
||||||
pub_key: this._pubKey,
|
|
||||||
sig: this._sig
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Message Payload.
|
|
||||||
*/
|
|
||||||
export class Payload {
|
|
||||||
_record: Record;
|
|
||||||
_signatures: Signature[];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* New Payload.
|
|
||||||
*/
|
|
||||||
constructor (record: Record, ...signatures: Signature[]) {
|
|
||||||
assert(record);
|
|
||||||
|
|
||||||
this._record = record;
|
|
||||||
this._signatures = signatures;
|
|
||||||
}
|
|
||||||
|
|
||||||
get record () {
|
|
||||||
return this._record;
|
|
||||||
}
|
|
||||||
|
|
||||||
get signatures () {
|
|
||||||
return this._signatures;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add message signature to payload.
|
|
||||||
*/
|
|
||||||
addSignature (signature: any) {
|
|
||||||
assert(signature);
|
|
||||||
|
|
||||||
this._signatures.push(signature);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Serialize Payload.
|
|
||||||
*/
|
|
||||||
serialize () {
|
|
||||||
// return Util.sortJSON({
|
|
||||||
// });
|
|
||||||
return {
|
|
||||||
record: this._record.serialize(),
|
|
||||||
signatures: this._signatures.map(s => s.serialize())
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user