updating staking datastructures

datastructure-update
Ganesha Upadhyaya 5 years ago
parent 8148f89f3e
commit b7852bb9c5
  1. 163
      packages/harmony-staking/src/stakingTransaction.ts
  2. 114
      packages/harmony-staking/test/testSign.test.ts
  3. 55
      packages/harmony-staking/test/transactions.json

@ -1,36 +1,37 @@
// tslint:disable: max-classes-per-file
import {
encode,
arrayify,
BN,
encode,
hexlify,
stripZeros,
Signature,
splitSignature,
keccak256,
sign,
BN,
Signature,
splitSignature,
stripZeros,
} from '@harmony-js/crypto';
import { TextEncoder } from 'text-encoding';
import { Unit, numberToHex } from '@harmony-js/utils';
import { Messenger, RPCMethod } from '@harmony-js/network';
import { defaultMessenger, TxStatus, TransactionBase } from '@harmony-js/transaction';
import { defaultMessenger, TransactionBase, TxStatus } from '@harmony-js/transaction';
import { numberToHex, Unit } from '@harmony-js/utils';
import { TextEncoder } from 'text-encoding';
export class StakingSettings {
public static PRECISION = 18;
public static MAX_DECIMAL = 1000000000000000000;
}
export const enum Directive {
DirectiveNewValidator,
DirectiveCreateValidator,
DirectiveEditValidator,
DirectiveDelegate,
DirectiveRedelegate,
DirectiveUndelegate,
DirectiveCollectRewards,
}
export class StakingTransaction extends TransactionBase {
private directive: Directive;
private stakeMsg: NewValidator | EditValidator | Delegate | Redelegate | Undelegate;
private stakeMsg: CreateValidator | EditValidator | Delegate | Undelegate | CollectRewards;
private nonce: number | string;
private gasLimit: number | string;
private gasPrice: number | string;
@ -42,7 +43,7 @@ export class StakingTransaction extends TransactionBase {
constructor(
directive: Directive,
stakeMsg: NewValidator | EditValidator | Delegate | Redelegate | Undelegate,
stakeMsg: CreateValidator | EditValidator | Delegate | Undelegate | CollectRewards,
nonce: number | string,
gasPrice: number | string,
gasLimit: number | string,
@ -234,16 +235,53 @@ export class Description {
export class Decimal {
value: BN;
constructor(value: number, precision: number) {
if (precision > StakingSettings.PRECISION) {
constructor(value: string) {
if (value.length == 0) {
throw new Error(`decimal string is empty`);
}
var value1 = value;
if (value[0] == '-') {
throw new Error(`decimal fraction should be be between [0, 1]`);
}
if (value[0] == '+') {
value1 = value.substr(1);
}
if (value1.length == 0) {
throw new Error(`decimal string is empty`);
}
const spaced = value1.split(' ');
if (spaced.length > 1) {
throw new Error(`bad decimal string`);
}
const splitted = value1.split('.');
var len = 0;
var combinedStr = splitted[0];
if (splitted.length == 2) {
len = splitted[1].length;
if (len == 0 || combinedStr.length == 0) {
throw new Error(`bad decimal length`);
}
if (splitted[1][0] == '-') {
throw new Error(`bad decimal string`);
}
combinedStr += splitted[1];
} else if (splitted.length > 2) {
throw new Error(`too many periods to be a decimal string`);
}
if (len > StakingSettings.PRECISION) {
throw new Error(
`too much precision: ${precision}, should be less than ${StakingSettings.PRECISION}`,
`too much precision: precision should be less than ${StakingSettings.PRECISION}`,
);
}
const zerosToAdd = StakingSettings.PRECISION - precision;
const multiplier = Math.pow(10, zerosToAdd);
// (value * multiplier).toString();
this.value = new Unit((value * multiplier).toString()).asWei().toWei();
const zerosToAdd = StakingSettings.PRECISION - len;
combinedStr += '0'.repeat(zerosToAdd);
combinedStr = combinedStr.replace(/^0+/, '');
const val = new Unit(combinedStr).asWei().toWei();
if (val.gt(new Unit(StakingSettings.MAX_DECIMAL.toString()).asWei().toWei())) {
throw new Error(`too large decimal fraction`);
}
this.value = val;
}
encode(): any[] {
@ -268,68 +306,91 @@ export class CommissionRate {
raw.push(this.rate.encode());
raw.push(this.maxRate.encode());
raw.push(this.maxChangeRate.encode());
// console.log(decode(encode(raw)));
return raw;
}
}
export class NewValidator {
export class CreateValidator {
validatorAddress: string;
description: Description;
commission: CommissionRate;
commissionRates: CommissionRate;
minSelfDelegation: number;
stakingAddress: string;
pubKey: string;
maxTotalDelegation: number;
slotPubKeys: string[];
amount: number;
constructor(
validatorAddress: string,
description: Description,
commission: CommissionRate,
commissionRates: CommissionRate,
minSelfDelegation: number,
stakingAddress: string,
pubKey: string,
maxTotalDelegation: number,
slotPubKeys: string[],
amount: number,
) {
this.validatorAddress = validatorAddress;
this.description = description;
this.commission = commission;
this.commissionRates = commissionRates;
this.minSelfDelegation = minSelfDelegation;
this.stakingAddress = stakingAddress;
this.pubKey = pubKey;
this.maxTotalDelegation = maxTotalDelegation;
this.slotPubKeys = slotPubKeys;
this.amount = amount;
}
encode(): any[] {
const raw: Array<string | Uint8Array | Array<string | Uint8Array>> = [];
raw.push(hexlify(TransactionBase.normalizeAddress(this.validatorAddress)));
raw.push(this.description.encode());
raw.push(this.commission.encode());
raw.push(this.commissionRates.encode());
raw.push(hexlify(this.minSelfDelegation));
raw.push(hexlify(TransactionBase.normalizeAddress(this.stakingAddress)));
raw.push(this.pubKey);
raw.push(hexlify(this.maxTotalDelegation));
raw.push(this.encodeArr());
raw.push(hexlify(this.amount));
return raw;
}
encodeArr(): any[] {
var raw: Array<string | Uint8Array | Array<string | Uint8Array>> = [];
this.slotPubKeys.forEach((pubKey) => {
raw.push(pubKey);
});
return raw;
}
}
export class EditValidator {
validatorAddress: string;
description: Description;
stakingAddress: string;
commissionRate: Decimal;
minSelfDelegation: number;
maxTotalDelegation: number;
slotKeyToRemove: string;
slotKeyToAdd: string;
constructor(
validatorAddress: string,
description: Description,
stakingAddress: string,
commissionRate: Decimal,
minSelfDelegation: number,
maxTotalDelegation: number,
slotKeyToRemove: string,
slotKeyToAdd: string,
) {
this.validatorAddress = validatorAddress;
this.description = description;
this.stakingAddress = stakingAddress;
this.commissionRate = commissionRate;
this.minSelfDelegation = minSelfDelegation;
this.maxTotalDelegation = maxTotalDelegation;
this.slotKeyToRemove = slotKeyToRemove;
this.slotKeyToAdd = slotKeyToAdd;
}
encode(): any[] {
const raw: Array<string | Uint8Array | Array<string | Uint8Array>> = [];
raw.push(hexlify(TransactionBase.normalizeAddress(this.validatorAddress)));
raw.push(this.description.encode());
raw.push(hexlify(TransactionBase.normalizeAddress(this.stakingAddress)));
raw.push(this.commissionRate.encode());
raw.push(hexlify(this.minSelfDelegation));
raw.push(hexlify(this.maxTotalDelegation));
raw.push(this.slotKeyToRemove);
raw.push(this.slotKeyToAdd);
return raw;
}
}
@ -352,46 +413,32 @@ export class Delegate {
}
}
export class Redelegate {
export class Undelegate {
delegatorAddress: string;
validatorSrcAddress: string;
validatorDstAddress: string;
validatorAddress: string;
amount: number;
constructor(
delegatorAddress: string,
validatorSrcAddress: string,
validatorDstAddress: string,
amount: number,
) {
constructor(delegatorAddress: string, validatorAddress: string, amount: number) {
this.delegatorAddress = delegatorAddress;
this.validatorSrcAddress = validatorSrcAddress;
this.validatorDstAddress = validatorDstAddress;
this.validatorAddress = validatorAddress;
this.amount = amount;
}
encode(): any[] {
const raw: Array<string | Uint8Array> = [];
raw.push(hexlify(TransactionBase.normalizeAddress(this.delegatorAddress)));
raw.push(hexlify(TransactionBase.normalizeAddress(this.validatorSrcAddress)));
raw.push(hexlify(TransactionBase.normalizeAddress(this.validatorDstAddress)));
raw.push(hexlify(TransactionBase.normalizeAddress(this.validatorAddress)));
raw.push(hexlify(this.amount));
return raw;
}
}
export class Undelegate {
export class CollectRewards {
delegatorAddress: string;
validatorAddress: string;
amount: number;
constructor(delegatorAddress: string, validatorAddress: string, amount: number) {
constructor(delegatorAddress: string) {
this.delegatorAddress = delegatorAddress;
this.validatorAddress = validatorAddress;
this.amount = amount;
}
encode(): any[] {
const raw: Array<string | Uint8Array> = [];
raw.push(hexlify(TransactionBase.normalizeAddress(this.delegatorAddress)));
raw.push(hexlify(TransactionBase.normalizeAddress(this.validatorAddress)));
raw.push(hexlify(this.amount));
return raw;
}
}

@ -1,10 +1,8 @@
import { getAddressFromPrivateKey } from '@harmony-js/crypto';
import { isValidAddress, ChainType, ChainID } from '@harmony-js/utils';
// tslint:disable-next-line: no-implicit-dependencies
import { Wallet } from '@harmony-js/account';
import { getAddressFromPrivateKey } from '@harmony-js/crypto';
import { HttpProvider, Messenger } from '@harmony-js/network';
import { ChainID, ChainType, isValidAddress } from '@harmony-js/utils';
// tslint:disable-next-line: no-implicit-dependencies
import fetch from 'jest-fetch-mock';
@ -17,11 +15,11 @@ const msgHttp = new Messenger(http, ChainType.Harmony, ChainID.HmyLocal);
const walletHttp = new Wallet(msgHttp);
import {
NewValidator,
CreateValidator,
EditValidator,
Delegate,
Redelegate,
Undelegate,
CollectRewards,
Directive,
StakingTransaction,
Description,
@ -36,7 +34,7 @@ describe('test sign staking transaction', () => {
fetch.resetMocks();
// jest.clearAllTimers();
});
it('should test sign new validator staking transaction', () => {
it('should test sign create validator staking transaction', () => {
const testTx: any = testTransactions[0];
const address = getAddressFromPrivateKey(testTx.privateKey);
expect(isValidAddress(address)).toEqual(true);
@ -47,21 +45,22 @@ describe('test sign staking transaction', () => {
testTx.description.securityContact,
testTx.description.details,
);
const commission: CommissionRate = new CommissionRate(
new Decimal(testTx.commission.rate, 0),
new Decimal(testTx.commission.maxRate, 0),
new Decimal(testTx.commission.maxChangeRate, 0),
const commissionRates: CommissionRate = new CommissionRate(
new Decimal(testTx.commissionRates.rate),
new Decimal(testTx.commissionRates.maxRate),
new Decimal(testTx.commissionRates.maxChangeRate),
);
const stakeMsg: NewValidator = new NewValidator(
const stakeMsg: CreateValidator = new CreateValidator(
testTx.validatorAddress,
desc,
commission,
commissionRates,
testTx.minSelfDelegation,
testTx.stakingAddress,
testTx.pubKey,
testTx.maxTotalDelegation,
testTx.slotPubKeys,
testTx.amount,
);
const stakingTx: StakingTransaction = new StakingTransaction(
Directive.DirectiveNewValidator,
Directive.DirectiveCreateValidator,
stakeMsg,
testTx.nonce,
testTx.gasPrice,
@ -86,10 +85,13 @@ describe('test sign staking transaction', () => {
testTx.description.details,
);
const stakeMsg: EditValidator = new EditValidator(
testTx.validatorAddress,
desc,
testTx.stakingAddress,
new Decimal(testTx.commissionRate, 0),
new Decimal(testTx.commissionRate),
testTx.minSelfDelegation,
testTx.maxTotalDelegation,
testTx.slotKeyToRemove,
testTx.slotKeyToAdd,
);
const stakingTx: StakingTransaction = new StakingTransaction(
Directive.DirectiveEditValidator,
@ -129,19 +131,18 @@ describe('test sign staking transaction', () => {
const signed = stakingTx.rlpSign(testTx.privateKey);
expect(signed[1]).toEqual(testTx.encoded);
});
it('should test sign redelegate staking transaction', () => {
it('should test sign undelegate staking transaction', () => {
const testTx: any = testTransactions[3];
const address = getAddressFromPrivateKey(testTx.privateKey);
expect(isValidAddress(address)).toEqual(true);
const stakeMsg: Redelegate = new Redelegate(
const stakeMsg: Undelegate = new Undelegate(
testTx.delegatorAddress,
testTx.validatorSrcAddress,
testTx.validatorDstAddress,
testTx.validatorAddress,
testTx.amount,
);
const stakingTx: StakingTransaction = new StakingTransaction(
Directive.DirectiveRedelegate,
Directive.DirectiveUndelegate,
stakeMsg,
testTx.nonce,
testTx.gasPrice,
@ -154,18 +155,14 @@ describe('test sign staking transaction', () => {
const signed = stakingTx.rlpSign(testTx.privateKey);
expect(signed[1]).toEqual(testTx.encoded);
});
it('should test sign undelegate staking transaction', () => {
it('should test sign collect rewards staking transaction', () => {
const testTx: any = testTransactions[4];
const address = getAddressFromPrivateKey(testTx.privateKey);
expect(isValidAddress(address)).toEqual(true);
const stakeMsg: Undelegate = new Undelegate(
testTx.delegatorAddress,
testTx.validatorAddress,
testTx.amount,
);
const stakeMsg: CollectRewards = new CollectRewards(testTx.delegatorAddress);
const stakingTx: StakingTransaction = new StakingTransaction(
Directive.DirectiveUndelegate,
Directive.DirectiveCollectRewards,
stakeMsg,
testTx.nonce,
testTx.gasPrice,
@ -178,7 +175,7 @@ describe('test sign staking transaction', () => {
const signed = stakingTx.rlpSign(testTx.privateKey);
expect(signed[1]).toEqual(testTx.encoded);
});
it('should test sign new validator staking transaction using wallet', async () => {
it('should test sign create validator staking transaction using wallet', async () => {
const testTx: any = testTransactions[0];
const responses = [
{
@ -202,21 +199,22 @@ describe('test sign staking transaction', () => {
testTx.description.securityContact,
testTx.description.details,
);
const commission: CommissionRate = new CommissionRate(
new Decimal(testTx.commission.rate, 0),
new Decimal(testTx.commission.maxRate, 0),
new Decimal(testTx.commission.maxChangeRate, 0),
const commissionRates: CommissionRate = new CommissionRate(
new Decimal(testTx.commissionRates.rate),
new Decimal(testTx.commissionRates.maxRate),
new Decimal(testTx.commissionRates.maxChangeRate),
);
const stakeMsg: NewValidator = new NewValidator(
const stakeMsg: CreateValidator = new CreateValidator(
testTx.validatorAddress,
desc,
commission,
commissionRates,
testTx.minSelfDelegation,
testTx.stakingAddress,
testTx.pubKey,
testTx.maxTotalDelegation,
testTx.slotPubKeys,
testTx.amount,
);
const stakingTx: StakingTransaction = new StakingTransaction(
Directive.DirectiveNewValidator,
Directive.DirectiveCreateValidator,
stakeMsg,
0,
testTx.gasPrice,
@ -255,10 +253,13 @@ describe('test sign staking transaction', () => {
testTx.description.details,
);
const stakeMsg: EditValidator = new EditValidator(
testTx.validatorAddress,
desc,
testTx.stakingAddress,
new Decimal(testTx.commissionRate, 0),
new Decimal(testTx.commissionRate),
testTx.minSelfDelegation,
testTx.maxTotalDelegation,
testTx.slotKeyToRemove,
testTx.slotKeyToAdd,
);
const stakingTx: StakingTransaction = new StakingTransaction(
Directive.DirectiveEditValidator,
@ -313,8 +314,9 @@ describe('test sign staking transaction', () => {
const signedStaking: StakingTransaction = await account.signStaking(stakingTx);
expect(signedStaking.getRawTransaction()).toEqual(testTx.encoded);
});
it('should test sign redelegate staking transaction using wallet', async () => {
it('should test sign undelegate staking transaction using wallet', async () => {
const testTx: any = testTransactions[3];
const responses = [
{
jsonrpc: '2.0',
@ -329,16 +331,14 @@ describe('test sign staking transaction', () => {
].map((res) => [JSON.stringify(res)] as [string]);
fetch.mockResponses(...responses);
const stakeMsg: Redelegate = new Redelegate(
const stakeMsg: Undelegate = new Undelegate(
testTx.delegatorAddress,
testTx.validatorSrcAddress,
testTx.validatorDstAddress,
testTx.validatorAddress,
testTx.amount,
);
const stakingTx: StakingTransaction = new StakingTransaction(
Directive.DirectiveRedelegate,
Directive.DirectiveUndelegate,
stakeMsg,
0,
testTx.gasPrice,
@ -350,11 +350,13 @@ describe('test sign staking transaction', () => {
);
const account: any = walletHttp.addByPrivateKey(testTx.privateKey);
const signedStaking: StakingTransaction = await account.signStaking(stakingTx);
expect(signedStaking.getFromAddress()).toEqual(account.bech32Address);
expect(signedStaking.getSignature()).toBeTruthy();
expect(signedStaking.getUnsignedRawTransaction()).toBeTruthy();
expect(signedStaking.getRawTransaction()).toEqual(testTx.encoded);
});
it('should test sign undelegate staking transaction using wallet', async () => {
it('should test sign collect rewards staking transaction using wallet', async () => {
const testTx: any = testTransactions[4];
const responses = [
{
jsonrpc: '2.0',
@ -369,14 +371,11 @@ describe('test sign staking transaction', () => {
].map((res) => [JSON.stringify(res)] as [string]);
fetch.mockResponses(...responses);
const stakeMsg: Undelegate = new Undelegate(
testTx.delegatorAddress,
testTx.validatorAddress,
testTx.amount,
);
const stakeMsg: CollectRewards = new CollectRewards(testTx.delegatorAddress);
const stakingTx: StakingTransaction = new StakingTransaction(
Directive.DirectiveUndelegate,
Directive.DirectiveCollectRewards,
stakeMsg,
0,
testTx.gasPrice,
@ -388,9 +387,6 @@ describe('test sign staking transaction', () => {
);
const account: any = walletHttp.addByPrivateKey(testTx.privateKey);
const signedStaking: StakingTransaction = await account.signStaking(stakingTx);
expect(signedStaking.getFromAddress()).toEqual(account.bech32Address);
expect(signedStaking.getSignature()).toBeTruthy();
expect(signedStaking.getUnsignedRawTransaction()).toBeTruthy();
expect(signedStaking.getRawTransaction()).toEqual(testTx.encoded);
});
});

@ -2,6 +2,7 @@
{
"privateKey": "4edef2c24995d15b0e25cbd152fb0e2c05d3b79b9c2afd134e6f59f91bf99e48",
"chainID": "0x2",
"validatorAddress": "one1a0x3d6xpmr6f8wsyaxd9v36pytvp48zckswvv9",
"description": {
"name": "Alice",
"identity": "alice",
@ -9,26 +10,29 @@
"securityContact": "Bob",
"details": "Don't mess with me!!!"
},
"commission": {
"rate": "100",
"maxRate": "150",
"maxChangeRate": "5"
"commissionRates": {
"rate": "0.1",
"maxRate": "0.9",
"maxChangeRate": "0.05"
},
"minSelfDelegation": "0xa",
"stakingAddress": "one1a0x3d6xpmr6f8wsyaxd9v36pytvp48zckswvv9",
"pubKey": "0xb9486167ab9087ab818dc4ce026edb5bf216863364c32e42df2af03c5ced1ad181e7d12f0e6dd5307a73b62247608611",
"maxTotalDelegation": "0x0bb8",
"slotPubKeys": [
"0xb9486167ab9087ab818dc4ce026edb5bf216863364c32e42df2af03c5ced1ad181e7d12f0e6dd5307a73b62247608611"
],
"amount": "0x64",
"nonce": "0x2",
"gasPrice": "0x",
"gasLimit": "0x64",
"encoded": "0xf8ec80f8a3f83885416c69636585616c69636591616c6963652e6861726d6f6e792e6f6e6583426f6295446f6e2774206d6573732077697468206d65212121e0ca89056bc75e2d63100000ca890821ab0d4414980000c9884563918244f400000a94ebcd16e8c1d8f493ba04e99a56474122d81a9c58b0b9486167ab9087ab818dc4ce026edb5bf216863364c32e42df2af03c5ced1ad181e7d12f0e6dd5307a73b622476086116402806428a00b1a797d11f7b0dad42abd66c542fab8af0f028b7159bb70e44fe68b2e4d9f2ca07b223662bdb4e1a084f8c506095886a1f5eda051927fab3516ab9258efc34cd7",
"encoded": "0xf8ed80f8a494ebcd16e8c1d8f493ba04e99a56474122d81a9c58f83885416c69636585616c69636591616c6963652e6861726d6f6e792e6f6e6583426f6295446f6e2774206d6573732077697468206d65212121ddc988016345785d8a0000c9880c7d713b49da0000c887b1a2bc2ec500000a820bb8f1b0b9486167ab9087ab818dc4ce026edb5bf216863364c32e42df2af03c5ced1ad181e7d12f0e6dd5307a73b622476086116402806428a0476e8a0fe478e0d03ff10222d4d590bca8cee3ec51b830f4fc4a8bee5d0e9d28a03b2be18e73b2f99d7e2691485a0e166f28e62815079c126e68f876dc97339f8f",
"v": "28",
"r": "0x0b1a797d11f7b0dad42abd66c542fab8af0f028b7159bb70e44fe68b2e4d9f2c",
"s": "0x7b223662bdb4e1a084f8c506095886a1f5eda051927fab3516ab9258efc34cd7"
"r": "0x476e8a0fe478e0d03ff10222d4d590bca8cee3ec51b830f4fc4a8bee5d0e9d28",
"s": "0x3b2be18e73b2f99d7e2691485a0e166f28e62815079c126e68f876dc97339f8f"
},
{
"privateKey": "4edef2c24995d15b0e25cbd152fb0e2c05d3b79b9c2afd134e6f59f91bf99e48",
"chainID": "0x2",
"validatorAddress": "one1a0x3d6xpmr6f8wsyaxd9v36pytvp48zckswvv9",
"description": {
"name": "Alice",
"identity": "alice",
@ -36,16 +40,18 @@
"securityContact": "Bob",
"details": "Don't mess with me!!!"
},
"stakingAddress": "one1a0x3d6xpmr6f8wsyaxd9v36pytvp48zckswvv9",
"commissionRate": "100",
"commissionRate": "0.1",
"minSelfDelegation": "0xa",
"maxTotalDelegation": "0x0bb8",
"slotKeyToRemove": "0xb9486167ab9087ab818dc4ce026edb5bf216863364c32e42df2af03c5ced1ad181e7d12f0e6dd5307a73b62247608611",
"slotKeyToAdd": "0xb9486167ab9087ab818dc4ce026edb5bf216863364c32e42df2af03c5ced1ad181e7d12f0e6dd5307a73b62247608611",
"nonce": "0x2",
"gasPrice": "0x",
"gasLimit": "0x64",
"encoded": "0xf8a401f85bf83885416c69636585616c69636591616c6963652e6861726d6f6e792e6f6e6583426f6295446f6e2774206d6573732077697468206d6521212194ebcd16e8c1d8f493ba04e99a56474122d81a9c58ca89056bc75e2d631000000a02806428a071b68b38864e75af60bf05e52b53278e864dbf2eb4a33adeacaa6e1b31f21e59a01ee06acb4d2bc22105454a79ef089fc0794ddba6e2849d9e4236180b47e973ed",
"v": "28",
"r": "0x71b68b38864e75af60bf05e52b53278e864dbf2eb4a33adeacaa6e1b31f21e59",
"s": "0x1ee06acb4d2bc22105454a79ef089fc0794ddba6e2849d9e4236180b47e973ed"
"encoded": "0xf9010801f8bf94ebcd16e8c1d8f493ba04e99a56474122d81a9c58f83885416c69636585616c69636591616c6963652e6861726d6f6e792e6f6e6583426f6295446f6e2774206d6573732077697468206d65212121c988016345785d8a00000a820bb8b0b9486167ab9087ab818dc4ce026edb5bf216863364c32e42df2af03c5ced1ad181e7d12f0e6dd5307a73b62247608611b0b9486167ab9087ab818dc4ce026edb5bf216863364c32e42df2af03c5ced1ad181e7d12f0e6dd5307a73b6224760861102806427a05e54b55272f6bf5ffeca10d85976749d6b844cc9f30ba3285b9ab8a82d53e3e3a03ce04d9a9f834e20b22aa918ead346c84a04b1504fe3ff9e38f21c5e5712f013",
"v": "27",
"r": "0x5e54b55272f6bf5ffeca10d85976749d6b844cc9f30ba3285b9ab8a82d53e3e3",
"s": "0x3ce04d9a9f834e20b22aa918ead346c84a04b1504fe3ff9e38f21c5e5712f013"
},
{
"privateKey": "4edef2c24995d15b0e25cbd152fb0e2c05d3b79b9c2afd134e6f59f91bf99e48",
@ -65,29 +71,26 @@
"privateKey": "4edef2c24995d15b0e25cbd152fb0e2c05d3b79b9c2afd134e6f59f91bf99e48",
"chainID": "0x2",
"delegatorAddress": "one1a0x3d6xpmr6f8wsyaxd9v36pytvp48zckswvv9",
"validatorSrcAddress": "one1a0x3d6xpmr6f8wsyaxd9v36pytvp48zckswvv9",
"validatorDstAddress": "one1a0x3d6xpmr6f8wsyaxd9v36pytvp48zckswvv9",
"validatorAddress": "one1a0x3d6xpmr6f8wsyaxd9v36pytvp48zckswvv9",
"amount": "0xa",
"nonce": "0x2",
"gasPrice": "0x",
"gasLimit": "0x64",
"encoded": "0xf88903f84094ebcd16e8c1d8f493ba04e99a56474122d81a9c5894ebcd16e8c1d8f493ba04e99a56474122d81a9c5894ebcd16e8c1d8f493ba04e99a56474122d81a9c580a02806428a0c479121bf1ea02fa1052a4d54743703fa6eeb16e50ff002d34fcfde736c21d75a07a1b9dac1761ab9fb38cadcdd4b0b28aafc39d1707e913f6b758e05e09b1e517",
"encoded": "0xf87303eb94ebcd16e8c1d8f493ba04e99a56474122d81a9c5894ebcd16e8c1d8f493ba04e99a56474122d81a9c580a02806428a05bf8c653567defe2c3728732bc9d67dd099a977df91c740a883fd89e03abb6e2a05202c4b51652d5144c6a30d14d1a7a316b5a4a6b49be985b4bc6980e49f7acb7",
"v": "28",
"r": "0xc479121bf1ea02fa1052a4d54743703fa6eeb16e50ff002d34fcfde736c21d75",
"s": "0x7a1b9dac1761ab9fb38cadcdd4b0b28aafc39d1707e913f6b758e05e09b1e517"
"r": "0x5bf8c653567defe2c3728732bc9d67dd099a977df91c740a883fd89e03abb6e2",
"s": "0x5202c4b51652d5144c6a30d14d1a7a316b5a4a6b49be985b4bc6980e49f7acb7"
},
{
"privateKey": "4edef2c24995d15b0e25cbd152fb0e2c05d3b79b9c2afd134e6f59f91bf99e48",
"chainID": "0x2",
"delegatorAddress": "one1a0x3d6xpmr6f8wsyaxd9v36pytvp48zckswvv9",
"validatorAddress": "one1a0x3d6xpmr6f8wsyaxd9v36pytvp48zckswvv9",
"amount": "0xa",
"nonce": "0x2",
"gasPrice": "0x",
"gasLimit": "0x64",
"encoded": "0xf87304eb94ebcd16e8c1d8f493ba04e99a56474122d81a9c5894ebcd16e8c1d8f493ba04e99a56474122d81a9c580a02806427a0d6af2488d3b45658f37ff6bb89f7eaa86f7c1dfce19a68697e778be28efd2320a05b9837bd5c7041318859f9fb444a255f32f4d7e7b49f18830ba75abecdc02390",
"v": "27",
"r": "0xd6af2488d3b45658f37ff6bb89f7eaa86f7c1dfce19a68697e778be28efd2320",
"s": "0x5b9837bd5c7041318859f9fb444a255f32f4d7e7b49f18830ba75abecdc02390"
"encoded": "0xf85d04d594ebcd16e8c1d8f493ba04e99a56474122d81a9c5802806428a04c15c72f42577001083a9c7ff9d9724077aec704a524e53dc7c9afe97ca4e625a055c13ea17c3efd1cd91f2988c7e7673950bac5a08c174f2d0af27a82039f1e3d",
"v": "28",
"r": "0x4c15c72f42577001083a9c7ff9d9724077aec704a524e53dc7c9afe97ca4e625",
"s": "0x55c13ea17c3efd1cd91f2988c7e7673950bac5a08c174f2d0af27a82039f1e3d"
}
]

Loading…
Cancel
Save