From fc999624534d067e294169a4a0574b37a98fd489 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lloren=C3=A7?= Date: Wed, 12 Jul 2023 10:23:25 +0200 Subject: [PATCH] 20230712: SNS Set Dissolve Timestamp --- .../20230712-sns-set-dissolve-timestamp.ts | 128 ++++++++++++++++++ scripts/test-vectors/date-utils.ts | 60 ++++++++ 2 files changed, 188 insertions(+) create mode 100644 scripts/test-vectors/20230712-sns-set-dissolve-timestamp.ts create mode 100644 scripts/test-vectors/date-utils.ts diff --git a/scripts/test-vectors/20230712-sns-set-dissolve-timestamp.ts b/scripts/test-vectors/20230712-sns-set-dissolve-timestamp.ts new file mode 100644 index 000000000..1c6d59d10 --- /dev/null +++ b/scripts/test-vectors/20230712-sns-set-dissolve-timestamp.ts @@ -0,0 +1,128 @@ +import { IDL } from "@dfinity/candid"; +import { Principal } from "@dfinity/principal"; +import { SnsSetDissolveTimestampParams } from "@dfinity/sns/src"; +import { toSetDissolveTimestampRequest } from "@dfinity/sns/src/converters/governance.converters"; +import { arrayOfNumberToUint8Array } from "@dfinity/utils"; +import { + secondsToDissolveDelayDuration, + SECONDS_IN_DAY, + SECONDS_IN_MONTH, + SECONDS_IN_YEAR, +} from "./date-utils"; +import { ManageNeuronFn } from "./sns-governance.idl"; +import { bytesToHexString, createBlob, writeToJson } from "./utils"; + +/** + * Issue: https://github.com/Zondax/ledger-icp/issues/212 + */ + +interface Params extends SnsSetDissolveTimestampParams { + canisterId: Principal; +} +const nowInSeconds = Math.round(Date.now() / 1000); + +const createTestVector = (params: Params) => { + const rawRequestBody = toSetDissolveTimestampRequest(params); + const neuronIdString = bytesToHexString(Array.from(params.neuronId.id)); + const timestampLabel = secondsToDissolveDelayDuration( + params.dissolveTimestampSeconds - BigInt(nowInSeconds) + ); + console.log("in da test vector", params.dissolveTimestampSeconds); + return { + blob_candid: createBlob({ + arg: IDL.encode(ManageNeuronFn.argTypes, [rawRequestBody]), + methodName: "manage_neuron", + canisterId: params.canisterId, + }), + nowInSeconds, + timestampLabel, + neuronIdString: neuronIdString, + name: "Set Dissolve Delay Timestamp", + canisterId: params.canisterId.toText(), + candid_request: rawRequestBody, + }; +}; + +const main = () => { + try { + const id1 = arrayOfNumberToUint8Array([ + 215, 232, 81, 101, 44, 208, 50, 186, 94, 215, 107, 23, 246, 38, 170, 71, + 130, 159, 6, 229, 35, 90, 13, 88, 14, 150, 211, 114, 119, 41, 234, 36, + ]); + const id2 = arrayOfNumberToUint8Array([ + 163, 110, 20, 60, 134, 231, 228, 113, 231, 199, 25, 80, 100, 135, 207, + 122, 108, 244, 13, 167, 99, 97, 174, 175, 238, 81, 51, 225, 217, 172, 234, + 61, + ]); + const canisterId1 = Principal.fromText("ppmzm-3aaaa-aaaaa-aacpq-cai"); + const canisterId2 = Principal.fromText("s24we-diaaa-aaaaa-aaaka-cai"); + const inOneYear = BigInt(nowInSeconds + SECONDS_IN_YEAR); + const nextYearAndAHalf = BigInt( + Math.round(nowInSeconds + SECONDS_IN_YEAR + SECONDS_IN_MONTH * 6) + ); + const inOneYearMonthsAndDays = BigInt( + Math.round( + nowInSeconds + + SECONDS_IN_YEAR + + SECONDS_IN_MONTH * 3 + + SECONDS_IN_DAY * 18 + ) + ); + const inSixMonths = BigInt(Math.round(nowInSeconds + SECONDS_IN_MONTH * 6)); + const inEightYears = BigInt(Math.round(nowInSeconds + SECONDS_IN_YEAR * 8)); + + const vectors = [ + createTestVector({ + neuronId: { id: id1 }, + dissolveTimestampSeconds: inOneYear, + canisterId: canisterId1, + }), + createTestVector({ + neuronId: { id: id1 }, + dissolveTimestampSeconds: inSixMonths, + canisterId: canisterId1, + }), + createTestVector({ + neuronId: { id: id1 }, + dissolveTimestampSeconds: inOneYearMonthsAndDays, + canisterId: canisterId2, + }), + createTestVector({ + neuronId: { id: id1 }, + dissolveTimestampSeconds: nextYearAndAHalf, + canisterId: canisterId2, + }), + createTestVector({ + neuronId: { id: id2 }, + dissolveTimestampSeconds: inOneYearMonthsAndDays, + canisterId: canisterId2, + }), + createTestVector({ + neuronId: { id: id2 }, + dissolveTimestampSeconds: inSixMonths, + canisterId: canisterId2, + }), + createTestVector({ + neuronId: { id: id2 }, + dissolveTimestampSeconds: inEightYears, + canisterId: canisterId1, + }), + createTestVector({ + neuronId: { id: id2 }, + dissolveTimestampSeconds: nextYearAndAHalf, + canisterId: canisterId1, + }), + ]; + + writeToJson({ + data: vectors, + fileName: "sns-set-dissolve-delay-timestamp.json", + }); + console.log("File created successfully"); + } catch (error) { + console.log("There was an error"); + console.log(error); + } +}; + +main(); diff --git a/scripts/test-vectors/date-utils.ts b/scripts/test-vectors/date-utils.ts new file mode 100644 index 000000000..9df55b1ea --- /dev/null +++ b/scripts/test-vectors/date-utils.ts @@ -0,0 +1,60 @@ +const SECONDS_IN_MINUTE = 60; +const SECONDS_IN_HOUR = SECONDS_IN_MINUTE * 60; +export const SECONDS_IN_DAY = SECONDS_IN_HOUR * 24; +// Taking into account 1/4 of leap year +export const SECONDS_IN_YEAR = ((4 * 365 + 1) * SECONDS_IN_DAY) / 4; +export const SECONDS_IN_MONTH = SECONDS_IN_YEAR / 12; + +type LabelKey = "year" | "month" | "day" | "hour" | "minute" | "second"; +type LabelInfo = { + labelKey: LabelKey; + amount: number; +}; +const createLabel = (labelKey: LabelKey, amount: bigint): LabelInfo => ({ + labelKey, + amount: Number(amount), +}); + +const labels: { [key: string]: string } = { + year: "year", + year_plural: "years", + month: "month", + month_plural: "months", + day: "day", + day_plural: "days", +}; + +/** + * Displays years, months and days. + * + * Uses constants for `year` and `month`: + * - a year = 365.25 * 24 * 60 * 60 + * - a month = 1 year / 12 + * - rounds up days + * + * @param seconds + */ +export const secondsToDissolveDelayDuration = (seconds: bigint): string => { + const years = seconds / BigInt(SECONDS_IN_YEAR); + const months = (seconds % BigInt(SECONDS_IN_YEAR)) / BigInt(SECONDS_IN_MONTH); + const days = BigInt( + Math.ceil((Number(seconds) % SECONDS_IN_MONTH) / SECONDS_IN_DAY) + ); + const periods = [ + createLabel("year", years), + createLabel("month", months), + createLabel("day", days), + ]; + + return periods + .filter(({ amount }) => amount > 0) + .map( + (labelInfo) => + `${labelInfo.amount} ${ + labelInfo.amount === 1 + ? labels[labelInfo.labelKey] + : labels[`${labelInfo.labelKey}_plural`] + }` + ) + .join(", "); +};