Skip to content

Commit

Permalink
Unit denomination and conversion (#301)
Browse files Browse the repository at this point in the history
* feat: balance utils with conversion and formatting

* feat: balance utils with conversion and formatting

* test: updated formatBalance call and tests

* test: remove deprecated GAS value

* chore: add to index
  • Loading branch information
LeonFLK authored and Dudleyneedham committed Sep 30, 2020
1 parent d5006a3 commit 35888bc
Show file tree
Hide file tree
Showing 7 changed files with 174 additions and 14 deletions.
3 changes: 0 additions & 3 deletions src/__integrationtests__/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,6 @@ import CType from '../ctype/CType'
import { getOwner } from '../ctype/CType.chain'
import Identity from '../identity/Identity'

// FIXME: check with weights
// export const GAS = new BN(1_000_000)
export const GAS = new BN(125_000_000)
export const MIN_TRANSACTION = new BN(100_000_000)
export const ENDOWMENT = MIN_TRANSACTION.mul(new BN(100))

Expand Down
18 changes: 14 additions & 4 deletions src/balance/Balance.chain.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import BN from 'bn.js'
import { getCached } from '../blockchainApiConnection'
import Identity from '../identity/Identity'
import IPublicIdentity from '../types/PublicIdentity'
import BalanceUtils from './Balance.utils'

/**
* Fetches the current balance of the account with [accountAddress].
Expand Down Expand Up @@ -89,11 +90,12 @@ export async function listenToBalanceChanges(

/**
* Transfer Kilt [amount] tokens to [toAccountAddress] using the given [[Identity]].
* <B>Note that balance amount is in Femto-Kilt (1e-15) and must be translated to Kilt-Coin</B>.
* <B>Note that the value of the transferred currency and the balance amount reported by the chain is in Femto-Kilt (1e-15), and must be translated to Kilt-Coin</B>.
*
* @param identity Identity to use for token transfer.
* @param accountAddressTo Address of the receiver account.
* @param amount Amount of Femto-Kilt (1e-15) to transfer.
* @param amount Amount of Units to transfer.
* @param exponent Magnitude of the amount. Default magnitude of Femto-Kilt.
* @returns Promise containing the transaction status.
*
* @example
Expand All @@ -117,9 +119,17 @@ export async function listenToBalanceChanges(
export async function makeTransfer(
identity: Identity,
accountAddressTo: IPublicIdentity['address'],
amount: BN
amount: BN,
exponent = -15
): Promise<SubmittableResult> {
const blockchain = await getCached()
const transfer = blockchain.api.tx.balances.transfer(accountAddressTo, amount)
const cleanExponent =
(exponent >= 0 ? 1 : -1) * Math.floor(Math.abs(exponent))
const transfer = blockchain.api.tx.balances.transfer(
accountAddressTo,
cleanExponent === -15
? amount
: BalanceUtils.convertToTxUnit(amount, cleanExponent)
)
return blockchain.submitTx(identity, transfer)
}
27 changes: 22 additions & 5 deletions src/balance/Balance.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,16 @@ import {
makeTransfer,
} from './Balance.chain'
import TYPE_REGISTRY from '../blockchainApiConnection/__mocks__/BlockchainQuery'
import BalanceUtils from './Balance.utils'

jest.mock('../blockchainApiConnection/BlockchainApiConnection')

const BALANCE = 42
const FEE = 30

describe('Balance', () => {
let alice: Identity
let bob: Identity
const blockchainApi = require('../blockchainApiConnection/BlockchainApiConnection')
.__mocked_api

Expand All @@ -41,9 +44,11 @@ describe('Balance', () => {
return accountInfo(BALANCE - FEE)
}
)

beforeAll(async () => {
alice = await Identity.buildFromURI('//Alice')
bob = await Identity.buildFromURI('//Bob')
})
it('should listen to balance changes', async (done) => {
const bob = await Identity.buildFromURI('//Bob')
const listener = (account: string, balance: BN, change: BN): void => {
expect(account).toBe(bob.address)
expect(balance.toNumber()).toBe(BALANCE)
Expand All @@ -58,11 +63,23 @@ describe('Balance', () => {
})

it('should make transfer', async () => {
const alice = await Identity.buildFromURI('//Alice')
const bob = await Identity.buildFromURI('//Bob')

const status = await makeTransfer(alice, bob.address, new BN(100))
expect(status).toBeInstanceOf(SubmittableResult)
expect(status.isFinalized).toBeTruthy()
})
it('should make transfer of amount with arbitrary exponent', async () => {
const amount = new BN(10)
const exponent = -6
const expectedAmount = BalanceUtils.convertToTxUnit(
amount,
(exponent >= 0 ? 1 : -1) * Math.floor(Math.abs(exponent))
)
const status = await makeTransfer(alice, bob.address, amount, exponent)
expect(blockchainApi.tx.balances.transfer).toHaveBeenCalledWith(
bob.address,
expectedAmount
)
expect(status).toBeInstanceOf(SubmittableResult)
expect(status.isFinalized).toBeTruthy()
})
})
95 changes: 95 additions & 0 deletions src/balance/Balance.utils.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import BN from 'bn.js'
import {
formatKiltBalance,
convertToTxUnit,
asFemtoKilt,
TRANSACTION_FEE,
} from './Balance.utils'

describe('formatKiltBalance', () => {
const TESTVALUE = new BN('123456789000')
const baseValue = new BN('1')
it('formats the given balance', async () => {
expect(formatKiltBalance(TESTVALUE)).toEqual('123.456 micro KILT')
expect(formatKiltBalance(baseValue.mul(new BN(10).pow(new BN(3))))).toEqual(
'1.000 pico KILT'
)
expect(formatKiltBalance(baseValue.mul(new BN(10).pow(new BN(6))))).toEqual(
'1.000 nano KILT'
)
expect(formatKiltBalance(baseValue.mul(new BN(10).pow(new BN(9))))).toEqual(
'1.000 micro KILT'
)
expect(
formatKiltBalance(baseValue.mul(new BN(10).pow(new BN(12))))
).toEqual('1.000 milli KILT')
expect(
formatKiltBalance(baseValue.mul(new BN(10).pow(new BN(15))))
).toEqual('1.000 KILT')
expect(
formatKiltBalance(baseValue.mul(new BN(10).pow(new BN(18))))
).toEqual('1.000 Kilo KILT')
expect(
formatKiltBalance(baseValue.mul(new BN(10).pow(new BN(21))))
).toEqual('1.000 Mega KILT')
expect(
formatKiltBalance(baseValue.mul(new BN(10).pow(new BN(24))))
).toEqual('1.000 Giga KILT')
expect(
formatKiltBalance(baseValue.mul(new BN(10).pow(new BN(27))))
).toEqual('1.000 Tera KILT')
})
})
describe('convertToTxUnit', () => {
it('converts given value with given power to femto KILT', () => {
expect(new BN(convertToTxUnit(new BN(1), -15).toString())).toEqual(
new BN(1)
)
expect(new BN(convertToTxUnit(new BN(1), -12).toString())).toEqual(
new BN('1000')
)
expect(new BN(convertToTxUnit(new BN(1), -9).toString())).toEqual(
new BN('1000000')
)
expect(new BN(convertToTxUnit(new BN(1), -6).toString())).toEqual(
new BN('1000000000')
)
expect(new BN(convertToTxUnit(new BN(1), -3).toString())).toEqual(
new BN('1000000000000')
)
expect(new BN(convertToTxUnit(new BN(1), 0).toString())).toEqual(
new BN('1000000000000000')
)
expect(new BN(convertToTxUnit(new BN(1), 3).toString())).toEqual(
new BN('1000000000000000000')
)
expect(new BN(convertToTxUnit(new BN(1), 6).toString())).toEqual(
new BN('1000000000000000000000')
)
expect(new BN(convertToTxUnit(new BN(1), 9).toString())).toEqual(
new BN('1000000000000000000000000')
)
expect(new BN(convertToTxUnit(new BN(1), 12).toString())).toEqual(
new BN('1000000000000000000000000000')
)
expect(new BN(convertToTxUnit(new BN(1), 15).toString())).toEqual(
new BN('1000000000000000000000000000000')
)
expect(new BN(convertToTxUnit(new BN(1), 18).toString())).toEqual(
new BN('1000000000000000000000000000000000')
)
})
})
describe('asFemtoKilt', () => {
it('converts whole KILT to femtoKilt using convertToTxUnit', () => {
expect(new BN(asFemtoKilt(new BN(1000)).toString())).toEqual(
new BN('1000000000000000000')
)
})
})

describe('TRANSACTION_FEE', () => {
it('equals 125 nano KILT', () => {
expect(formatKiltBalance(TRANSACTION_FEE)).toEqual('125.000 nano KILT')
})
})
36 changes: 36 additions & 0 deletions src/balance/Balance.utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/**
* @packageDocumentation
* @module BalanceUtils
* @preferred
*/

import BN from 'bn.js'
import { formatBalance } from '@polkadot/util'

export const KILT_COIN = new BN(1)

export function formatKiltBalance(amount: BN): string {
return formatBalance(amount, {
decimals: 15,
withSiFull: true,
withUnit: 'KILT',
})
}

export function convertToTxUnit(balance: BN, power: number): BN {
return new BN(balance).mul(new BN(10).pow(new BN(15 + power)))
}

export function asFemtoKilt(balance: BN): BN {
return convertToTxUnit(balance, 0)
}

export const TRANSACTION_FEE = convertToTxUnit(new BN(125), -9)

export default {
KILT_COIN,
TRANSACTION_FEE,
formatKiltBalance,
asFemtoKilt,
convertToTxUnit,
}
6 changes: 5 additions & 1 deletion src/balance/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,8 @@
* @ignore
*/

export * from './Balance.chain'
import BalanceUtils from './Balance.utils'
import * as Balance from './Balance.chain'

export { Balance, BalanceUtils }
export default Balance
3 changes: 2 additions & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { Accumulator, CombinedPresentation } from '@kiltprotocol/portablegabi'
import { Attester, Claimer, Verifier } from './actor'
import Attestation, { AttestationUtils } from './attestation'
import AttestedClaim, { AttestedClaimUtils } from './attestedclaim'
import * as Balance from './balance'
import { Balance, BalanceUtils } from './balance'
import Blockchain, { IBlockchainApi } from './blockchain'
import * as BlockchainApiConnection from './blockchainApiConnection'
import Claim, { ClaimUtils } from './claim'
Expand Down Expand Up @@ -66,6 +66,7 @@ export {
IBlockchainApi,
BlockchainApiConnection,
Balance,
BalanceUtils,
Crypto,
Identity,
AttesterIdentity,
Expand Down

0 comments on commit 35888bc

Please sign in to comment.