@radixdlt/atom-transaction-mapping
Version:
197 lines (173 loc) • 5.27 kB
text/typescript
import {
makeSimpleTransitioner,
makeTransitioner,
} from '../src/toAtom/fungibleParticleTransitioner'
import {
AnySpunParticle,
ParticleBase,
Spin,
spunDownParticle,
spunUpParticle,
} from '@radixdlt/atom'
import { Amount, AmountT } from '@radixdlt/primitives'
import { UInt256 } from '@radixdlt/uint256'
import { v4 as uuidv4 } from 'uuid'
import { exactlyContainParticles } from '../../atom/test/helpers/particles'
import { two, nine, one, ten } from '@radixdlt/primitives/src/amount'
import { ok } from 'neverthrow'
import { SpunParticleT } from '@radixdlt/atom/src/particles/_types'
describe('fungibleParticleTransitioner', () => {
const eleven = Amount.inSmallestDenomination(UInt256.valueOf(11))
type TestParticle = ParticleBase & {
amount: AmountT
id: string
isChangeReturnedToSender: boolean
}
const testParticle = (
amount: number | AmountT,
id?: string,
isChangeReturnedToSender?: boolean,
): TestParticle => {
const id_ = id ?? uuidv4()
const amount_ =
typeof amount === 'number'
? Amount.inSmallestDenomination(UInt256.valueOf(amount))
: amount
return <TestParticle>{
amount: amount_,
id: id_,
isChangeReturnedToSender: isChangeReturnedToSender ?? false,
equals: (other) => (other as TestParticle).id === id_,
}
}
const transitioner = makeSimpleTransitioner<TestParticle, TestParticle>({
inputAmountMapper: (p) => p.amount,
inputCreator: (amount) => /* From */ testParticle(amount),
outputCreator: (amount) => /* To */ testParticle(amount),
})
it('should create a transition with two particles is output when TWO to 2', () => {
const particle = testParticle(2)
const spunParticles = transitioner
.transition({
currentParticles: [particle],
totalAmountToTransfer: two,
})
._unsafeUnwrap()
expect(spunParticles.length).toBe(2)
const spunParticle0 = spunParticles[0]
expect(spunParticle0.particle.equals(particle)).toBe(true)
expect(spunParticle0.spin).toBe(Spin.DOWN)
const spunParticle1 = spunParticles[1]
expect(spunParticle1.spin).toBe(Spin.UP)
expect(spunParticle1.particle.equals(particle)).toBe(false)
expect(
(spunParticle1.particle as TestParticle).amount.equals(two),
).toBe(true)
})
type SpunTestParticle = SpunParticleT<TestParticle>
const upTP = (tp: TestParticle): SpunTestParticle => spunUpParticle(tp)
const downTP = (tp: TestParticle): SpunTestParticle => spunDownParticle(tp)
const expectTransition = (
input: Readonly<{
actual: AnySpunParticle[]
expected: SpunTestParticle[]
}>,
): void => {
const match = exactlyContainParticles({
actual: input.actual,
expected: input.expected.map((p) => p.eraseToAny()),
})
expect(match).toBe(true)
}
it('should work with many particle and change', () => {
const outCounter = 0
const transitioner = makeTransitioner<TestParticle, TestParticle>({
inputAmountMapper: (p) => p.amount,
inputCreator: (amount, from: TestParticle) =>
/* From */ ok(
testParticle(amount, from.id.toUpperCase(), true),
),
outputCreator: (amount) =>
/* To */ ok(testParticle(amount, `up${outCounter}`)),
})
const a = testParticle(1, 'a')
const b = testParticle(2, 'b')
const c = testParticle(3, 'c')
const d = testParticle(4, 'd')
const spunParticles = transitioner
.transition({
currentParticles: [a, b, c, d],
totalAmountToTransfer: nine,
})
._unsafeUnwrap()
expectTransition({
actual: spunParticles,
expected: [
upTP(testParticle(nine, 'up0', false)),
downTP(a),
downTP(b),
downTP(c),
downTP(d),
upTP(testParticle(one, 'D', true)),
],
})
})
it('should work with many particle and no change', () => {
const transitioner = makeTransitioner<TestParticle, TestParticle>({
inputAmountMapper: (p) => p.amount,
inputCreator: (amount, from: TestParticle) =>
/* From */ ok(testParticle(amount, from.id.toUpperCase())),
outputCreator: (amount) => /* To */ ok(testParticle(amount, `up0`)),
})
const a = testParticle(1, 'a')
const b = testParticle(2, 'b')
const c = testParticle(3, 'c')
const d = testParticle(4, 'd')
const spunParticles = transitioner
.transition({
currentParticles: [a, b, c, d],
totalAmountToTransfer: ten,
})
._unsafeUnwrap()
expectTransition({
actual: spunParticles,
expected: [
upTP(testParticle(nine, 'up0')),
downTP(a),
downTP(b),
downTP(c),
downTP(d),
],
})
})
it('should fail if insufficient funds with single particle', () => {
const particle = testParticle(1)
const transitionResult = transitioner.transition({
currentParticles: [particle],
totalAmountToTransfer: two,
})
transitionResult.match(
() => {
throw Error('expected error, but got none')
},
(e) => expect(e.message).toBe(`Insufficient balance.`),
)
})
it('should fail if insufficient funds with many particle', () => {
const transitionResult = transitioner.transition({
currentParticles: [
testParticle(1),
testParticle(2),
testParticle(3),
testParticle(4),
],
totalAmountToTransfer: eleven,
})
transitionResult.match(
() => {
throw Error('expected error, but got none')
},
(e) => expect(e.message).toBe(`Insufficient balance.`),
)
})
})