Skip to content

Commit

Permalink
Merge pull request #491 from casper-ecosystem/motesToCSPR
Browse files Browse the repository at this point in the history
Motes to cspr
  • Loading branch information
Comp0te authored Jan 22, 2025
2 parents 3ea58a6 + cef2a37 commit f04b49d
Show file tree
Hide file tree
Showing 4 changed files with 152 additions and 17 deletions.
42 changes: 42 additions & 0 deletions src/types/Conversions.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { expect } from 'chai';

import { Conversions } from "./Conversions";

describe('Conversions', () => {
it('should convert CSPR to motes correctly', function() {
const bal1 = Conversions.csprToMotes(1).toString();
const bal2 = Conversions.csprToMotes('123400047000').toString();
const bal3 = Conversions.csprToMotes('1000000040234023040234023040234023042040230420402000000.4022').toString();
const bal4 = Conversions.csprToMotes('0').toString();
const bal5 = Conversions.csprToMotes('0.111').toString();
const bal6 = Conversions.csprToMotes('0.000000001').toString();
const bal7 = Conversions.csprToMotes('0.000000000001').toString();

expect(bal1).to.deep.equal('1000000000');
expect(bal2).to.deep.equal('123400047000000000000');
expect(bal3).to.deep.equal('1000000040234023040234023040234023042040230420402000000402200000');
expect(bal4).to.deep.equal('0');
expect(bal5).to.deep.equal('111000000');
expect(bal6).to.deep.equal('1');
expect(bal7).to.deep.equal('0');
expect(() => Conversions.csprToMotes('-100')).to.throw('Invalid input: cspr must be a string representing a valid positive number.');
expect(() => Conversions.csprToMotes('100,3')).to.throw('Invalid input: cspr must be a string representing a valid positive number.');
expect(() => Conversions.csprToMotes('abc')).to.throw('Invalid input: cspr must be a string representing a valid positive number.');
expect(() => Conversions.csprToMotes('34.34.34')).to.throw('Invalid input: cspr must be a string representing a valid positive number.');
});

it('should convert motes to CSPR correctly', function() {
const bal1 = Conversions.motesToCSPR('1');
const bal2 = Conversions.motesToCSPR('123400047000');
const bal3 = Conversions.motesToCSPR('1000000040234023040234023040234023042040230420402000000');
const bal4 = Conversions.motesToCSPR('0');
const bal5 = Conversions.motesToCSPR('100000000000');

expect(bal1).to.deep.equal('0.000000001');
expect(bal2).to.deep.equal('123.400047');
expect(bal3).to.deep.equal('1000000040234023040234023040234023042040230420.402');
expect(bal4).to.deep.equal('0');
expect(bal5).to.deep.equal('100');
expect(() => Conversions.motesToCSPR('-100')).to.throw('Motes cannot be negative number');
});
});
35 changes: 30 additions & 5 deletions src/types/Conversions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ export class Conversions {
/**
* Converts a CSPR amount to its mote equivalent.
*
* @param cspr - A `BigNumberish` amount of CSPR to convert to motes.
* @param cspr - A `string` amount of CSPR to convert to motes.
* @returns A `BigNumber` containing the equivalent amount in motes.
*
* @remarks
Expand All @@ -94,8 +94,22 @@ export class Conversions {
* const motes = Conversions.csprToMotes(cspr);
* console.log(motes.toString()); // Outputs: "1000000000"
*/
static csprToMotes(cspr: BigNumberish): BigNumber {
return BigNumber.from(cspr).mul('1000000000');
static csprToMotes(cspr: string | number): BigNumber {
if (typeof cspr === 'string' && !/^\d+(\.\d+)?$/.test(cspr)) {
throw new Error('Invalid input: cspr must be a string representing a valid positive number.');
}

// eslint-disable-next-line prefer-const
let [integerPart, decimalPart = ""] = cspr.toString().split('.');
let result = BigNumber.from(integerPart).mul(10 ** 9);

if (decimalPart.length > 0) {
decimalPart = (decimalPart + '000000000').slice(0, 9);

result = result.add(decimalPart);
}

return result;
}

/**
Expand All @@ -113,7 +127,18 @@ export class Conversions {
* const cspr = Conversions.motesToCSPR(motes);
* console.log(cspr.toString()); // Outputs: "1"
*/
static motesToCSPR(motes: BigNumberish): BigNumber {
return BigNumber.from(motes).div('1000000000');
static motesToCSPR(motes: BigNumberish): string {
const motesBigNumber = BigNumber.from(motes);

if (motesBigNumber.lt(0)) {
throw new Error('Motes cannot be negative number');
}

const resultStr = motesBigNumber.toBigInt().toString();

const integerPart = resultStr.slice(0, -9) || "0";
const decimalPart = resultStr.slice(-9).padStart(9, '0');

return `${integerPart}.${decimalPart}`.replace(/\.?0+$/, '');
}
}
72 changes: 71 additions & 1 deletion src/types/Transaction.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { BigNumber } from '@ethersproject/bignumber';
import { assert, expect } from 'chai';

import { Duration, Timestamp } from './Time';
import { TransactionV1 } from './Transaction';
import { Transaction, TransactionV1 } from './Transaction';
import { InitiatorAddr } from './InitiatorAddr';
import { FixedMode, PricingMode } from './PricingMode';
import { KeyAlgorithm, PrivateKey, PublicKey } from './keypair';
Expand Down Expand Up @@ -119,4 +119,74 @@ describe('Test Transaction', () => {
assert.deepEqual(parseInt(transactionPaymentAmount, 10), 25000000000);
expect(transactionV1.payload.chainName).to.deep.equal('casper-net-1');
});

it('should parse deploy json', async () => {
const json = {
"deploy": {
"approvals": [],
"hash": "076E77DE17De7F262c5531017c214afd664D9702D4b5b771996aE4dcAf9C01f9",
"header": {
"account": "02024570ae3c361650d5b1Bcd1724a1aF09ffe067d7F69ebd75B567c10c8379a7719",
"timestamp": "2025-01-21T18:07:52.214Z",
"ttl": "30m",
"dependencies": [],
"gas_price": 1,
"body_hash": "D52E4B46542D9C83BA6EF894dBA82e475011166A4C5F434b0d99248cfDC9Abc5",
"chain_name": "casper-test"
},
"payment": {
"ModuleBytes": {
"module_bytes": "",
"args": [
[
"amount",
{
"cl_type": "U512",
"bytes": "0400943577",
"parsed": "2000000000"
}
]
]
}
},
"session": {
"StoredVersionedContractByHash": {
"hash": "6497c59f1bcfBBBC468Dc889dd73dCd542827fb966a24Eb33e4140Ab5BB4aE28",
"version": null,
"entry_point": "mint",
"args": [
[
"recipient",
{
"cl_type": "Key",
"bytes": "00ABbc44715BA77Ea117f9379A3f5b62879Be71D105b7508b610a676AEf4c3C26a",
"parsed": {
"Account": "account-hash-ABBC44715ba77ea117f9379a3f5b62879Be71D105B7508B610a676AeF4C3C26A"
}
}
],
[
"token_metas",
{
"cl_type": {
"List": {
"Map": {
"key": "String",
"value": "String"
}
}
},
"bytes": "0100000003000000040000006e616d65080000004e6f6f6f6f6f6f6f0b0000006465736372697074696f6e04000000747275650500000061737365745400000068747470733a2f2f697066732d676174657761792e637370722e73747564696f2f697066732f516d5a62714d767a5036706a45415554753135376d5470736e38526b4d637a585a48767a56784454647854436572",
"parsed": ""
}
]
]
}
}
}
};

const tx = Transaction.fromJSON(json);
expect(tx.hash.toHex()).to.equal('076e77de17de7f262c5531017c214afd664d9702d4b5b771996ae4dcaf9c01f9')
});
});
20 changes: 9 additions & 11 deletions src/types/clvalue/Map.ts
Original file line number Diff line number Diff line change
Expand Up @@ -195,28 +195,26 @@ export class CLValueMap {

const { result: u32, bytes: u32Bytes } = CLValueUInt32.fromBytes(bytes);
const size = u32.toNumber();
const remainder = u32Bytes;
let remainder = u32Bytes;

if (size === 0) {
return { result: mapResult, bytes: remainder };
}

for (let i = 0; i < size; i++) {
if (remainder.length) {
const keyVal = CLValueParser.fromBytesByType(remainder, mapType.key);
if (!remainder.length) {
continue;
}

if (!keyVal.bytes || !keyVal.result) {
continue;
}
try {
const keyVal = CLValueParser.fromBytesByType(remainder, mapType.key);
remainder = keyVal?.bytes ?? [];

const valVal = CLValueParser.fromBytesByType(keyVal.bytes, mapType.val);

if (!valVal.bytes || !valVal.result) {
continue;
}
remainder = valVal?.bytes ?? [];

mapResult.append(keyVal?.result, valVal?.result);
}
} catch {}
}

return { result: mapResult, bytes: remainder };
Expand Down

0 comments on commit f04b49d

Please sign in to comment.