// Copyright 2017-2026 @pezkuwi/app-referenda authors & contributors // SPDX-License-Identifier: Apache-2.0 /// import type { PezpalletReferendaCurve } from '@pezkuwi/types/lookup'; import type { BN } from '@pezkuwi/util'; import { BN_BILLION, BN_ZERO, bnToBn } from '@pezkuwi/util'; import { curveDelay, curveThreshold } from './util.js'; function curveLinear (ceil: BN | string | number, floor: BN | string | number, length: BN | string | number): PezpalletReferendaCurve { return { asLinearDecreasing: { ceil: bnToBn(ceil), floor: bnToBn(floor), length: bnToBn(length) }, isLinearDecreasing: true, isReciprocal: false, isSteppedDecreasing: false } as PezpalletReferendaCurve; } function curveReciprocal (factor: BN | string | number, xOffset: BN | string | number, yOffset: BN | string | number): PezpalletReferendaCurve { return { asReciprocal: { factor: bnToBn(factor), xOffset: bnToBn(xOffset), yOffset: bnToBn(yOffset) }, isLinearDecreasing: false, isReciprocal: true, isSteppedDecreasing: false } as PezpalletReferendaCurve; } // We don't currently have curves on Dicle for this, so needs a check // function curveStepped (begin: BN | string | number, end: BN | string | number, period: BN | string | number, step: BN | string | number): PezpalletReferendaCurve { // return { // asSteppedDecreasing: { // begin: bnToBn(begin), // end: bnToBn(end), // period: bnToBn(period), // step: bnToBn(step) // }, // isLinearDecreasing: false, // isReciprocal: false, // isSteppedDecreasing: true // } as PezpalletReferendaCurve; // } function percentValue (percent: number): BN { return BN_BILLION.muln(percent).divn(100); } describe('curveThreshold', (): void => { describe('LinearDecreasing', (): void => { // linear support curve from root track on Dicle const rootCurve = curveLinear(BN_BILLION.divn(2), BN_ZERO, BN_BILLION); it('has a correct starting point', (): void => { expect( curveThreshold(rootCurve, bnToBn(0), bnToBn(672)).toString() ).toEqual(percentValue(50).toString()); }); it('has the correct midpoint', (): void => { expect( curveThreshold(rootCurve, bnToBn(672 / 2), bnToBn(672)).toString() ).toEqual(percentValue(25).toString()); }); it('has a correct ending point', (): void => { expect( curveThreshold(rootCurve, bnToBn(672), bnToBn(672)).toString() ).toEqual(percentValue(0).toString()); }); }); describe('Reciprocal', (): void => { // linear approval curve from root track on Dicle const rootCurve = curveReciprocal(222_222_224, 333_333_335, 333_333_332); it('has a correct starting point', (): void => { expect( curveThreshold(rootCurve, bnToBn(0), bnToBn(672)).toString() ).toEqual(percentValue(100).toString()); }); it('has the correct midpoints', (): void => { expect( curveThreshold(rootCurve, bnToBn(12), bnToBn(672)).toString() ).toEqual('966101697'); // 96.61% expect( curveThreshold(rootCurve, bnToBn(336), bnToBn(672)).toString() ).toEqual(percentValue(60).toString()); }); it('has a correct ending point', (): void => { expect( curveThreshold(rootCurve, bnToBn(672), bnToBn(672)).toString() ).toEqual('499999999'); }); }); }); describe('curveDelay', (): void => { describe('LinearDecreasing', (): void => { // linear support curve from root track on Dicle const rootCurve = curveLinear(BN_BILLION.divn(2), BN_ZERO, BN_BILLION); it('has the correct result for 25%', (): void => { expect( curveDelay(rootCurve, bnToBn(25), bnToBn(100)).toString() ).toEqual('500000000'); // 50% through }); }); describe('Reciprocal', (): void => { // linear approval curve from root track on Dicle const rootCurve = curveReciprocal(222_222_224, 333_333_335, 333_333_332); it('has the correct result for 75%', (): void => { expect( curveDelay(rootCurve, bnToBn(75), bnToBn(100)).toString() ).toEqual('200000000'); // 20% through }); }); });