Skip to content

Commit

Permalink
Merge pull request #1 from nohkwak/202406-support-kaia-units
Browse files Browse the repository at this point in the history
Support Kaia Units
  • Loading branch information
Nohyun Kwak (Nehemiah) authored Jun 24, 2024
2 parents 535ec9e + e025db2 commit 4f5811c
Show file tree
Hide file tree
Showing 5 changed files with 174 additions and 31 deletions.
72 changes: 45 additions & 27 deletions js-ext-core/src/util/units.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,41 +5,42 @@ import { parseUnits as parseEthUnits, formatUnits as formatEthUnits } from "@eth
import _ from "lodash";

// All in lowercase. The ambiguity between mKLAY and MKLAY is resolved in getKlayDecimals.
const names = [
"peb", // 0
"kpeb", // 3
"mpeb", // 6
"ston", // 9, alias to Gpeb
"uklay", // 12
"mklay", // 15
"klay", // 18
"kklay", // 21
"mklay", // 24
"gklay", // 27
"tklay", // 30
];
const names: { [key: string]: number } = {
// Klaytn units
peb: 0,
kpeb: 3,
mpeb: 6,
ston: 9,
gpeb: 9,
uklay: 12,
mklay: 15,
klay: 18,
kklay: 21,
Mklay: 24,
gklay: 27,
tklay: 30,

// Kaia units
kei: 0,
gkei: 9,
kaia: 18
};

// Returns the decimal corresponding the unitName.
// If not found, returns undefined.
function getKlayDecimals(unitName?: string | BigNumberish): number | undefined {
if (_.isString(unitName)) {
const lower = unitName.toLowerCase();

// Tricky special cases.
// Gpeb is alias to ston, thus 9 decimals
if (lower == "gpeb") {
return 9;
}
// mKLAY and MKLAY are different
if (lower == "mklay" && unitName[0] == "m") {
return 15;
} else if (lower == "mklay" && unitName[0] == "M") {
return 24;
}

const index = names.indexOf(lower);
if (index !== -1) {
return index * 3;
} else if (lower in names) {
return names[lower];
} else {
return undefined;
}
}
return undefined;
Expand Down Expand Up @@ -87,19 +88,36 @@ export function parseKlay(klay: string): BigNumber {
return parseKlayUnits(klay, 18);
}

// Equivalent to web3.utils.fromWei.
// Convert [value]peb to [unit].
export function fromPeb(value: BigNumberish, unitName?: string | BigNumberish): string {
return formatKlayUnits(value, unitName);
}

// Equivalent to web3.utils.toWei.
// Convert [value][unit] to peb.
export function toPeb(value: string, unitName?: string | BigNumberish): string {
return parseKlayUnits(value, unitName).toString();
}

// Shadow ethers functions because klay functions deals with both.
export const formatUnits = formatKlayUnits;
export const parseUnits = parseKlayUnits;

// Shadow kaia functions because klay functions supports same function.
export const formatKaiaUnits = formatKlayUnits;
export const parseKaiaUnits = parseKlayUnits;
export const formatKaia = formatKlay;
export const parseKaia = parseKlay;

// Equivalent to web3.utils.fromWei.
// Convert [value]peb to [unit].
export function fromPeb(value: BigNumberish, unitName?: string | BigNumberish): string {
// Convert [value]kei to [unit].
export function fromKei(value: BigNumberish, unitName?: string | BigNumberish): string {
return formatKlayUnits(value, unitName);
}

// Equivalent to web3.utils.toWei.
// Convert [value][unit] to peb.
export function toPeb(value: string, unitName?: string | BigNumberish): string {
// Convert [value][unit] to kei.
export function toKei(value: string, unitName?: string | BigNumberish): string {
return parseKlayUnits(value, unitName).toString();
}
94 changes: 94 additions & 0 deletions js-ext-core/test/util.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,17 @@ import {
getSignatureTuple,
getRpcTxObject,
formatKlayUnits,
formatKaiaUnits,
formatKlay,
formatKaia,
parseKlayUnits,
parseKaiaUnits,
parseKlay,
parseKaia,
toPeb,
toKei,
fromPeb,
fromKei,
asyncOpenApi,
HexStr,
isKIP3Json,
Expand Down Expand Up @@ -282,6 +288,94 @@ describe("util", () => {
});
});

describe("kei to unit (formatKaiaUnits, formatKaia, fromKei)", () => {
it("kaia units", () => {
// unit names are case-insensitive.
const kei = BigNumber.from("1000000000000000000"); // 1e18 kei

assert.equal(formatKaiaUnits(kei, "Gkei"), "1000000000.0"); // = 1e9 Gkei
assert.equal(fromKei(kei, "Gkei"), "1000000000.0");

assert.equal(formatKaiaUnits(kei, "KAIA"), "1.0"); // = 1 KAIA
assert.equal(fromKei(kei, "KAIA"), "1.0");

assert.equal(formatKaia(kei), "1.0"); // unit=KAIA by default
assert.equal(fromKei(kei), "1.0");
});

// Make sure {formatKaiaUnits, formatKaia} can safely replace {formatUnits, formatEther}.
it("for eth units, equivalent to ethers.utils.formatUnits", () => {
{
const wei = BigNumber.from("1000000000000000000"); // 1e18 wei in BigNumber
assert.equal(formatKaiaUnits(wei, "gwei"), formatEthUnits(wei, "gwei"));
assert.equal(formatKaiaUnits(wei, "ether"), formatEthUnits(wei, "ether"));
assert.equal(formatKaia(wei), formatEther(wei));
}
{
const wei = "25000000000"; // 25e9 wei in String
assert.equal(formatKaiaUnits(wei, "gwei"), formatEthUnits(wei, "gwei"));
assert.equal(formatKaiaUnits(wei, "ether"), formatEthUnits(wei, "ether"));
assert.equal(formatKaia(wei), formatEther(wei));
}
});

// Make sure {fromKei} can safely replace {fromWei}.
it("for eth units, equivalent to web3.utils.fromWei", () => {
// fromWei and fromKei are slightly different in decimal representation
// but the number is the same.
{
const wei = "1000000000000000000"; // 1e18 wei

assert.equal(fromWei(wei, "gwei"), "1000000000");
assert.equal(fromKei(wei, "gwei"), "1000000000.0");

assert.equal(fromWei(wei, "ether"), "1");
assert.equal(fromKei(wei, "ether"), "1.0");
assert.equal(fromKei(wei), "1.0");
}
{
const wei = "25000000000"; // 25e9 wei

assert.equal(fromWei(wei, "gwei"), "25");
assert.equal(fromKei(wei, "gwei"), "25.0");

assert.equal(fromWei(wei, "ether"), "0.000000025");
assert.equal(fromKei(wei, "ether"), "0.000000025");
assert.equal(fromKei(wei), "0.000000025");
}
});
});

describe("unit to kei (parseKaiaUnits, parseUnits, toKei)", () => {
it("kaia units", () => {
assert.equal(parseKaiaUnits("25.0", "Gkei").toString(), "25000000000"); // 25 Gkei = 25e9 kei
assert.equal(toKei("25.0", "Gkei"), "25000000000");

assert.equal(parseKaiaUnits("123.456", "kaia").toString(), "123456000000000000000"); // 123.456 kaia = 123.456e18 kei
assert.equal(parseKaiaUnits("123.456", "KAIA").toString(), "123456000000000000000"); // 123.456 KAIA = 123.456e18 kei
assert.equal(toKei("123.456", "kaia"), "123456000000000000000");

assert.equal(parseKaia("123.456").toString(), "123456000000000000000");// unit=KAIA by default
assert.equal(toKei("123.456"), "123456000000000000000");
});

it("for eth units, equivalent to ethers.utils.parseUnits", () => {
const eth = "123.456";
assert.equal(parseKaiaUnits(eth, "gwei").toString(), parseEthUnits(eth, "gwei").toString());
assert.equal(parseKaiaUnits(eth, "ether").toString(), parseEthUnits(eth, "ether").toString());
assert.equal(parseKaia(eth).toString(), parseEther(eth).toString());
assert.equal(parseKaiaUnits(eth).toString(), "123456000000000000000");
});

it("for eth units, equivalent to web3.utils.toPeb", () => {
const eth = "123.456";
assert.equal(toKei(eth, "gwei"), toWei(eth, "gwei"));
assert.equal(toKei(eth, "ether"), toWei(eth, "ether"));
assert.equal(toKei(eth), toWei(eth, "ether"));
assert.equal(toKei(eth), "123456000000000000000");
});
});

it("keystore", () => {
// Does not crash with non-JSON.
let json = "asdfasdf";
Expand Down
24 changes: 20 additions & 4 deletions web3j-ext/web3j-ext/src/main/java/org/web3j/utils/KlayConvert.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,35 @@

public class KlayConvert {
private KlayConvert() { }

// Klaytn units
public static BigDecimal fromPeb(String number, Unit unit) {
return fromPeb(new BigDecimal(number), unit);
}

public static BigDecimal fromPeb(BigDecimal number, Unit unit) {
return number.divide(unit.getpebFactor());
}

public static BigDecimal toPeb(String number, Unit unit) {
return toPeb(new BigDecimal(number), unit);
}

public static BigDecimal toPeb(BigDecimal number, Unit unit) {
return number.multiply(unit.getpebFactor());
}

// KAIA units
public static BigDecimal fromKei(String number, Unit unit) {
return fromKei(new BigDecimal(number), unit);
}
public static BigDecimal fromKei(BigDecimal number, Unit unit) {
return number.divide(unit.getpebFactor());
}
public static BigDecimal toKei(String number, Unit unit) {
return toKei(new BigDecimal(number), unit);
}
public static BigDecimal toKei(BigDecimal number, Unit unit) {
return number.multiply(unit.getpebFactor());
}

public enum Unit {
PEB("peb", 0),
KPEB("kpeb", 3),
Expand All @@ -31,7 +44,10 @@ public enum Unit {
KLAY("KLAY", 18),
KKLAY("kKLAY", 21),
MKLAY("MKLAY", 24),
GKLAY("GKLAY", 27);
GKLAY("GKLAY", 27),
KEI("kei", 0),
GKEI("Gkei", 9),
KAIA("KAIA", 18);

private String name;
private BigDecimal pebFactor;
Expand Down
8 changes: 8 additions & 0 deletions web3py-ext/web3py_ext/extend.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,14 @@ def from_key_pair(self, address, key):
BaseWeb3.to_peb = types.MethodType(to_peb, BaseWeb3)
BaseWeb3.from_peb = types.MethodType(from_peb, BaseWeb3)

# kaia units
units.units['kei'] = decimal.Decimal('1')
units.units['Gkei'] = decimal.Decimal('1000000000')
units.units['kaia'] = decimal.Decimal('1000000000000000000')
units.units['KAIA'] = decimal.Decimal('1000000000000000000')
BaseWeb3.to_kei = types.MethodType(to_kei, BaseWeb3)
BaseWeb3.from_kei = types.MethodType(from_kei, BaseWeb3)

# APIs
from web3.eth.eth import Eth
from web3.eth.async_eth import AsyncEth
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -260,4 +260,11 @@ def to_peb(self, number: Union[int, float, str, decimal.Decimal], unit: str) ->
return cast(Ston, to_wei(number, unit))

def from_peb(self, number: int, unit: str) -> Union[int, decimal.Decimal]:
return from_wei(number, unit)

Gkei = NewType("gkei", int)
def to_kei(self, number: Union[int, float, str, decimal.Decimal], unit: str) -> Gkei:
return cast(Gkei, to_wei(number, unit))

def from_kei(self, number: int, unit: str) -> Union[int, decimal.Decimal]:
return from_wei(number, unit)

0 comments on commit 4f5811c

Please sign in to comment.