Skip to content

Commit

Permalink
chore(types): codegen with useEnhancedDecimal
Browse files Browse the repository at this point in the history
Not really "enhanced". See hyperweb-io/telescope#652
  • Loading branch information
turadg committed Jan 21, 2025
1 parent afba9ea commit 0155e10
Show file tree
Hide file tree
Showing 14 changed files with 176 additions and 151 deletions.
3 changes: 3 additions & 0 deletions packages/cosmic-proto/scripts/codegen.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,9 @@ telescope({
// customTypes: {
// useCosmosSDKDec: true,
// },
customTypes: {
useEnhancedDecimal: true,
},
},
},
aminoEncoding: {
Expand Down
3 changes: 2 additions & 1 deletion packages/cosmic-proto/src/codegen/agoric/vbank/vbank.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
//@ts-nocheck
import { Coin, type CoinSDKType } from '../../cosmos/base/v1beta1/coin.js';
import { BinaryReader, BinaryWriter } from '../../binary.js';
import { Decimal, isSet } from '../../helpers.js';
import { Decimal } from '../../decimals.js';
import { isSet } from '../../helpers.js';
import { type JsonSafe } from '../../json-safe.js';
/** The module governance/configuration parameters. */
export interface Params {
Expand Down
2 changes: 1 addition & 1 deletion packages/cosmic-proto/src/codegen/binary.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//@ts-nocheck
/**
* This file and any referenced files were automatically generated by @cosmology/telescope@1.8.3
* This file and any referenced files were automatically generated by @cosmology/telescope@1.11.9
* DO NOT MODIFY BY HAND. Instead, download the latest proto files for your chain
* and run the transpile command or npm scripts command that is used to regenerate this bundle.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ import {
type CoinSDKType,
} from '../../base/v1beta1/coin.js';
import { BinaryReader, BinaryWriter } from '../../../binary.js';
import { Decimal, isSet } from '../../../helpers.js';
import { Decimal } from '../../../decimals.js';
import { isSet } from '../../../helpers.js';
import { type JsonSafe } from '../../../json-safe.js';
/** Params defines the set of params for the distribution module. */
export interface Params {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ import {
type DurationSDKType,
} from '../../../google/protobuf/duration.js';
import { BinaryReader, BinaryWriter } from '../../../binary.js';
import { Decimal } from '../../../decimals.js';
import {
Decimal,
isSet,
fromJsonTimestamp,
fromTimestamp,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
//@ts-nocheck
import { BinaryReader, BinaryWriter } from '../../../binary.js';
import { Decimal, isSet } from '../../../helpers.js';
import { Decimal } from '../../../decimals.js';
import { isSet } from '../../../helpers.js';
import { type JsonSafe } from '../../../json-safe.js';
/** Minter represents the minting state. */
export interface Minter {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,9 @@ import {
} from '../../../google/protobuf/duration.js';
import { Coin, type CoinSDKType } from '../../base/v1beta1/coin.js';
import { BinaryReader, BinaryWriter } from '../../../binary.js';
import {
isSet,
Decimal,
fromJsonTimestamp,
fromTimestamp,
} from '../../../helpers.js';
import { isSet, fromJsonTimestamp, fromTimestamp } from '../../../helpers.js';
import { type JsonSafe } from '../../../json-safe.js';
import { Decimal } from '../../../decimals.js';
/** BondStatus is the status of a validator. */
export enum BondStatus {
/** BOND_STATUS_UNSPECIFIED - UNSPECIFIED defines an invalid validator status. */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,9 @@ import {
type TimestampSDKType,
} from '../../../google/protobuf/timestamp.js';
import { BinaryReader, BinaryWriter } from '../../../binary.js';
import {
isSet,
Decimal,
fromJsonTimestamp,
fromTimestamp,
} from '../../../helpers.js';
import { isSet, fromJsonTimestamp, fromTimestamp } from '../../../helpers.js';
import { type JsonSafe } from '../../../json-safe.js';
import { Decimal } from '../../../decimals.js';
/** MsgCreateValidator defines a SDK message for creating a new validator. */
export interface MsgCreateValidator {
description: Description;
Expand Down
113 changes: 113 additions & 0 deletions packages/cosmic-proto/src/codegen/decimals.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
//@ts-nocheck
/**
* This file and any referenced files were automatically generated by @cosmology/[email protected]
* DO NOT MODIFY BY HAND. Instead, download the latest proto files for your chain
* and run the transpile command or npm scripts command that is used to regenerate this bundle.
*/

// The largest value we need is 18 (Ether).
const maxFractionalDigits = 30;
/**
* A type for arbitrary precision, non-negative decimals.
*
* Instances of this class are immutable.
*/
export class Decimal {
public static fromUserInput(
input: string,
fractionalDigits: number,
): Decimal {
Decimal.verifyFractionalDigits(fractionalDigits);
const badCharacter = input.match(/[^0-9.]/);
if (badCharacter) {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
throw new Error(
`Invalid character at position ${badCharacter.index! + 1}`,
);
}
let whole: string;
let fractional: string;
if (input === '') {
whole = '0';
fractional = '';
} else if (input.search(/\./) === -1) {
// integer format, no separator
whole = input;
fractional = '';
} else {
const parts = input.split('.');
switch (parts.length) {
case 0:
case 1:
throw new Error(
'Fewer than two elements in split result. This must not happen here.',
);
case 2:
if (!parts[1]) throw new Error('Fractional part missing');
whole = parts[0];
fractional = parts[1].replace(/0+$/, '');
break;
default:
throw new Error('More than one separator found');
}
}
if (fractional.length > fractionalDigits) {
throw new Error('Got more fractional digits than supported');
}
const quantity = `${whole}${fractional.padEnd(fractionalDigits, '0')}`;
return new Decimal(quantity, fractionalDigits);
}
public static fromAtomics(
atomics: string,
fractionalDigits: number,
): Decimal {
Decimal.verifyFractionalDigits(fractionalDigits);
return new Decimal(atomics, fractionalDigits);
}
private static verifyFractionalDigits(fractionalDigits: number): void {
if (!Number.isInteger(fractionalDigits))
throw new Error('Fractional digits is not an integer');
if (fractionalDigits < 0)
throw new Error('Fractional digits must not be negative');
if (fractionalDigits > maxFractionalDigits) {
throw new Error(
`Fractional digits must not exceed ${maxFractionalDigits}`,
);
}
}
public get atomics(): string {
return this.data.atomics.toString();
}
public get fractionalDigits(): number {
return this.data.fractionalDigits;
}
private readonly data: {
readonly atomics: bigint;
readonly fractionalDigits: number;
};
private constructor(atomics: string, fractionalDigits: number) {
if (!atomics.match(/^[0-9]+$/)) {
throw new Error(
'Invalid string format. Only non-negative integers in decimal representation supported.',
);
}
this.data = {
atomics: BigInt(atomics),
fractionalDigits: fractionalDigits,
};
}
public toString(): string {
const factor = BigInt(10) ** BigInt(this.data.fractionalDigits);
const whole = this.data.atomics / factor;
const fractional = this.data.atomics % factor;
if (fractional === 0n) {
return whole.toString();
} else {
const fullFractionalPart = fractional
.toString()
.padStart(this.data.fractionalDigits, '0');
const trimmedFractionalPart = fullFractionalPart.replace(/0+$/, '');
return `${whole.toString()}.${trimmedFractionalPart}`;
}
}
}
173 changes: 43 additions & 130 deletions packages/cosmic-proto/src/codegen/helpers.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,45 @@
//@ts-nocheck
/**
* This file and any referenced files were automatically generated by @cosmology/telescope@1.8.3
* This file and any referenced files were automatically generated by @cosmology/telescope@1.11.9
* DO NOT MODIFY BY HAND. Instead, download the latest proto files for your chain
* and run the transpile command or npm scripts command that is used to regenerate this bundle.
*/

import { encodeBase64, decodeBase64 } from '@endo/base64';
declare var self: any | undefined;
declare var window: any | undefined;
declare var global: any | undefined;
var globalThis: any = (() => {
if (typeof globalThis !== 'undefined') return globalThis;
if (typeof self !== 'undefined') return self;
if (typeof window !== 'undefined') return window;
if (typeof global !== 'undefined') return global;
throw 'Unable to locate global object';
})();

const atob: (b64: string) => string =
globalThis.atob ||
(b64 => globalThis.Buffer.from(b64, 'base64').toString('binary'));

export function bytesFromBase64(b64: string): Uint8Array {
const bin = atob(b64);
const arr = new Uint8Array(bin.length);
for (let i = 0; i < bin.length; ++i) {
arr[i] = bin.charCodeAt(i);
}
return arr;
}

// use Endo for broader compatibility
export const bytesFromBase64: (input: string) => Uint8Array = decodeBase64;
export const base64FromBytes: (input: Uint8Array) => string = encodeBase64;
const btoa: (bin: string) => string =
globalThis.btoa ||
(bin => globalThis.Buffer.from(bin, 'binary').toString('base64'));

export function base64FromBytes(arr: Uint8Array): string {
const bin: string[] = [];
arr.forEach(byte => {
bin.push(String.fromCharCode(byte));
});
return btoa(bin.join(''));
}

export interface AminoHeight {
readonly revision_number?: string;
Expand Down Expand Up @@ -168,6 +198,14 @@ export interface Rpc {
): Promise<Uint8Array>;
}

export function isRpc(rpc: unknown): rpc is Rpc {
return (
rpc !== null &&
rpc !== undefined &&
typeof (rpc as Rpc).request === 'function'
);
}

interface Timestamp {
/**
* Represents seconds of UTC time since Unix epoch
Expand Down Expand Up @@ -222,128 +260,3 @@ export function fromJsonTimestamp(o: any): Timestamp {
function numberToLong(number: number) {
return BigInt(Math.trunc(number));
}

// START agoric-sdk patch
// The largest value we need is 18 (Ether).
const maxFractionalDigits = 30;

/**
* A type for arbitrary precision, non-negative decimals.
*
* Instances of this class are immutable.
*/
export class Decimal {
public static fromUserInput(
input: string,
fractionalDigits: number,
): Decimal {
Decimal.verifyFractionalDigits(fractionalDigits);

const badCharacter = input.match(/[^0-9.]/);
if (badCharacter) {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
throw new Error(
`Invalid character at position ${badCharacter.index! + 1}`,
);
}

let whole: string;
let fractional: string;

if (input === '') {
whole = '0';
fractional = '';
} else if (input.search(/\./) === -1) {
// integer format, no separator
whole = input;
fractional = '';
} else {
const parts = input.split('.');
switch (parts.length) {
case 0:
case 1:
throw new Error(
'Fewer than two elements in split result. This must not happen here.',
);
case 2:
if (!parts[1]) throw new Error('Fractional part missing');
whole = parts[0];
fractional = parts[1].replace(/0+$/, '');
break;
default:
throw new Error('More than one separator found');
}
}

if (fractional.length > fractionalDigits) {
throw new Error('Got more fractional digits than supported');
}

const quantity = `${whole}${fractional.padEnd(fractionalDigits, '0')}`;

return new Decimal(quantity, fractionalDigits);
}

public static fromAtomics(
atomics: string,
fractionalDigits: number,
): Decimal {
Decimal.verifyFractionalDigits(fractionalDigits);
return new Decimal(atomics, fractionalDigits);
}

private static verifyFractionalDigits(fractionalDigits: number): void {
if (!Number.isInteger(fractionalDigits))
throw new Error('Fractional digits is not an integer');
if (fractionalDigits < 0)
throw new Error('Fractional digits must not be negative');
if (fractionalDigits > maxFractionalDigits) {
throw new Error(
`Fractional digits must not exceed ${maxFractionalDigits}`,
);
}
}

public get atomics(): string {
return this.data.atomics.toString();
}

public get fractionalDigits(): number {
return this.data.fractionalDigits;
}

private readonly data: {
readonly atomics: bigint;
readonly fractionalDigits: number;
};

private constructor(atomics: string, fractionalDigits: number) {
if (!atomics.match(/^[0-9]+$/)) {
throw new Error(
'Invalid string format. Only non-negative integers in decimal representation supported.',
);
}

this.data = {
atomics: BigInt(atomics),
fractionalDigits: fractionalDigits,
};
}

public toString(): string {
const factor = BigInt(10) ** BigInt(this.data.fractionalDigits);
const whole = this.data.atomics / factor;
const fractional = this.data.atomics % factor;

if (fractional === 0n) {
return whole.toString();
} else {
const fullFractionalPart = fractional
.toString()
.padStart(this.data.fractionalDigits, '0');
const trimmedFractionalPart = fullFractionalPart.replace(/0+$/, '');
return `${whole.toString()}.${trimmedFractionalPart}`;
}
}
}
// END agoric-sdk patch
Loading

0 comments on commit 0155e10

Please sign in to comment.