diff --git a/packages/types/src/primitive/Generic/Vote.spec.ts b/packages/types/src/primitive/Generic/Vote.spec.ts index cd5c82d1f4..174f7a6f21 100644 --- a/packages/types/src/primitive/Generic/Vote.spec.ts +++ b/packages/types/src/primitive/Generic/Vote.spec.ts @@ -7,104 +7,115 @@ import '../../injector'; import Vote from './Vote'; describe('Vote', (): void => { - it('constructs via boolean true', (): void => { - expect(new Vote(true).toU8a()).toEqual(new Uint8Array([128])); - expect(new Vote(true).isAye).toBe(true); - expect(new Vote(true).isNay).toBe(false); + describe('construction', (): void => { + it('constructs via boolean true', (): void => { + expect(new Vote(true).toU8a()).toEqual(new Uint8Array([128])); + expect(new Vote(true).isAye).toBe(true); + expect(new Vote(true).isNay).toBe(false); + }); + + it('constructs via boolean false', (): void => { + expect(new Vote(false).toU8a()).toEqual(new Uint8Array([0])); + expect(new Vote(false).isNay).toBe(true); + expect(new Vote(false).isAye).toBe(false); + }); + + it('has isYay for positive', (): void => { + // eslint-disable-next-line no-new-wrappers + expect(new Vote(true).isAye).toBe(true); + }); + + it('has isNay for negative', (): void => { + // eslint-disable-next-line no-new-wrappers + expect(new Vote(false).isNay).toBe(true); + }); + + it('is Aye for negative numbers', (): void => { + expect(new Vote(-128).isAye).toBe(true); + }); + + it('is Nay for positive numbers', (): void => { + expect(new Vote(127).isNay).toBe(true); + }); + + it('is Nay for 0', (): void => { + expect(new Vote(0).isNay).toBe(true); + }); }); - it('constructs via boolean false', (): void => { - expect(new Vote(false).toU8a()).toEqual(new Uint8Array([0])); - expect(new Vote(false).isNay).toBe(true); - expect(new Vote(false).isAye).toBe(false); + describe('Vote with conviction', (): void => { + it('constructs Vote with raw boolean', (): void => { + expect( + new Vote({ + aye: true, + conviction: 'Locked1x' + }).toU8a() + ).toEqual(new Uint8Array([0b10000001])); + }); + + it('constructs with Vote aye is false, conviction is None', (): void => { + expect( + new Vote({ + aye: false, + conviction: 'None' + }).toU8a() + ).toEqual(new Uint8Array([0b00000000])); + }); + + it('constructs with Vote aye is true, conviction is Locked4x', (): void => { + expect( + new Vote({ + aye: true, + conviction: 'Locked4x' + }).toU8a() + ).toEqual(new Uint8Array([0b10000100])); + }); }); - it('has isYay for positive', (): void => { - // eslint-disable-next-line no-new-wrappers - expect(new Vote(true).isAye).toBe(true); - }); + describe('getters', (): void => { + it('Conviction getter works', (): void => { + expect( + new Vote({ + aye: true, + conviction: 'Locked2x' + }).conviction.toString() + ).toEqual('Locked2x'); + }); - it('has isNay for negative', (): void => { - // eslint-disable-next-line no-new-wrappers - expect(new Vote(false).isNay).toBe(true); - }); + it('Conviction getter works with raw boolean and string conviction', (): void => { + expect( + new Vote({ + aye: true, + conviction: 'Locked2x' + }).conviction.toString() + ).toEqual('Locked2x'); + }); - it('is Aye for negative numbers', (): void => { - expect(new Vote(-128).isAye).toBe(true); - }); + it('Conviction getter works with raw boolean and conviction index', (): void => { + expect( + new Vote({ + aye: true, + conviction: 2 + }).conviction.toString() + ).toEqual('Locked2x'); + }); - it('is Nay for positive numbers', (): void => { - expect(new Vote(127).isNay).toBe(true); - }); + it('isAye getter works', (): void => { + expect( + new Vote({ + aye: true, + conviction: 'None' + }).isAye) + .toEqual(true); + }); - it('constructs V2 Vote with raw boolean', (): void => { - expect( - new Vote({ - aye: true, - conviction: 'Locked1x' - }).toU8a() - ).toEqual(new Uint8Array([0b10000001])); - }); - - it('constructs with V2 Vote aye is false, conviction is None', (): void => { - expect( - new Vote({ - aye: false, - conviction: 'None' - }).toU8a() - ).toEqual(new Uint8Array([0b00000000])); - }); - - it('constructs with Vote aye is true, conviction is Locked4x', (): void => { - expect( - new Vote({ - aye: true, - conviction: 'Locked4x' - }).toU8a() - ).toEqual(new Uint8Array([0b10000100])); - }); - - it('Conviction getter works', (): void => { - expect( - new Vote({ - aye: true, - conviction: 'Locked2x' - }).conviction.toString() - ).toEqual('Locked2x'); - }); - - it('Conviction getter works with raw boolean and string conviction', (): void => { - expect( - new Vote({ - aye: true, - conviction: 'Locked2x' - }).conviction.toString() - ).toEqual('Locked2x'); - }); - it('Conviction getter works with raw boolean and conviction index', (): void => { - expect( - new Vote({ - aye: true, - conviction: 2 - }).conviction.toString() - ).toEqual('Locked2x'); - }); - - it('isAye getter works', (): void => { - expect( - new Vote({ - aye: true, - conviction: 'None' - }).isAye) - .toEqual(true); - }); - - it('isNay getter works', (): void => { - expect( - new Vote({ - aye: true, - conviction: 'None' - }).isNay) - .toEqual(false); + it('isNay getter works', (): void => { + expect( + new Vote({ + aye: true, + conviction: 'None' + }).isNay) + .toEqual(false); + }); }); }); diff --git a/packages/types/src/primitive/Generic/Vote.ts b/packages/types/src/primitive/Generic/Vote.ts index dca9f6e132..d4abd67f85 100644 --- a/packages/types/src/primitive/Generic/Vote.ts +++ b/packages/types/src/primitive/Generic/Vote.ts @@ -7,18 +7,24 @@ import { Conviction } from '../../interfaces/democracy'; import { isBoolean, isNumber, isObject, isU8a, isUndefined } from '@polkadot/util'; import createType from '../../codec/createType'; -import U8a from '../../codec/U8a'; +import U8aFixed from '../../codec/U8aFixed'; import Bool from '../Bool'; +// For votes, the topmost bit indicated aye/nay, the lower bits indicate the conviction +const AYE_BITS = 0b10000000; +const NAY_BITS = 0b00000000; +const CON_MASK = 0b01111111; +const DEF_CONV = 0b00000000; // the default conviction, None + /** * @name Vote * @description * A number of lock periods, plus a vote, one way or the other. */ -export default class Vote extends U8a { - private _aye: Bool; +export default class Vote extends U8aFixed { + private _aye: boolean; - private _conviction: Conviction; // for V1, default to None + private _conviction: Conviction; public constructor (value?: any) { // decoded is just 1 byte @@ -26,39 +32,34 @@ export default class Vote extends U8a { // Conviction: 0000 - 0101 const decoded = Vote.decodeVote(value); - super(decoded); + super(decoded, 8); - const msb = decoded[0] >> 7; - const conviction = decoded[0] & 0b01111111; - - this._aye = new Bool(msb); - this._conviction = createType('Conviction', conviction); + this._aye = (decoded[0] & AYE_BITS) === AYE_BITS; + this._conviction = createType('Conviction', decoded[0] & CON_MASK); } private static decodeVote (value?: any): Uint8Array { if (isUndefined(value)) { - return new Uint8Array([0]); + return new Uint8Array([NAY_BITS]); } else if (isBoolean(value)) { return value - ? new Uint8Array([0b10000000]) - : new Uint8Array([0b0]); - } else if (value instanceof Bool) { + ? new Uint8Array([AYE_BITS | DEF_CONV]) + : new Uint8Array([NAY_BITS]); + } else if (value instanceof Boolean) { return Vote.decodeVote(value.valueOf()); } else if (isNumber(value)) { return value < 0 - ? new Uint8Array([0b10000000]) - : new Uint8Array([0b0]); - } else if (isObject(value) && !isUndefined(value.aye) && !isUndefined(value.conviction)) { - const aye = new Bool(value.aye); - const convictionIndex = createType('Conviction', value.conviction).index; - - const result = convictionIndex | (aye.eq(true) ? 0b1 << 7 : 0b0); - - return new Uint8Array([result]); + ? new Uint8Array([AYE_BITS | DEF_CONV]) + : new Uint8Array([NAY_BITS]); } else if (isU8a(value)) { return value.length - ? value - : new Uint8Array([0]); + ? value.subarray(0, 1) + : new Uint8Array([NAY_BITS]); + } else if (isObject(value)) { + const vote = new Bool(value.aye).eq(true) ? AYE_BITS : NAY_BITS; + const conviction = createType('Conviction', isUndefined(value.conviction) ? DEF_CONV : value.conviction); + + return new Uint8Array([vote | conviction.index]); } throw new Error(`Unable to convert input ${value} to Vote`); @@ -75,7 +76,7 @@ export default class Vote extends U8a { * @description true if the wrapped value is a positive vote */ public get isAye (): boolean { - return this._aye.eq(true); + return this._aye; } /** @@ -84,4 +85,11 @@ export default class Vote extends U8a { public get isNay (): boolean { return !this.isAye; } + + /** + * @description Returns the base runtime type name for this instance + */ + public toRawType (): string { + return 'Vote'; + } }