Skip to content

Commit

Permalink
feat(wallet): add UtxoRepositoryEvent.Changed
Browse files Browse the repository at this point in the history
  • Loading branch information
mkazlauskas committed Oct 14, 2021
1 parent 4321ec4 commit 7699044
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 23 deletions.
16 changes: 14 additions & 2 deletions packages/wallet/src/InMemoryUtxoRepository.ts
@@ -1,17 +1,17 @@
import Schema, { TxIn, TxOut } from '@cardano-ogmios/schema';
import { Buffer } from 'buffer';
import { UtxoRepository } from './types';
import { CardanoProvider, Ogmios, CardanoSerializationLib, CSL, cslUtil } from '@cardano-sdk/core';
import { dummyLogger, Logger } from 'ts-log';
import { ImplicitCoin, InputSelector, SelectionConstraints, SelectionResult } from '@cardano-sdk/cip2';
import { KeyManager } from './KeyManagement';
import {
UtxoRepository,
OnTransactionArgs,
TransactionTracker,
TransactionTrackerEvent,
UtxoRepositoryEvent,
UtxoRepositoryEvents
} from '.';
} from './types';
import { cslToOgmios } from '@cardano-sdk/core/src/Ogmios';
import Emittery from 'emittery';

Expand Down Expand Up @@ -89,6 +89,7 @@ export class InMemoryUtxoRepository extends Emittery<UtxoRepositoryEvents> imple
: undefined;
this.#logger.debug('Rewards balance stored', result.delegationAndRewards.rewards);
}
this.#emitSynced();
}

public async selectInputs(
Expand Down Expand Up @@ -129,6 +130,16 @@ export class InMemoryUtxoRepository extends Emittery<UtxoRepositoryEvents> imple
return this.#delegationAndRewards.delegate ?? null;
}

#emitSynced() {
this.emit(UtxoRepositoryEvent.Changed, {
allUtxos: this.allUtxos,
availableUtxos: this.availableUtxos,
allRewards: this.allRewards,
availableRewards: this.availableRewards,
delegation: this.delegation
}).catch(this.#logger.error);
}

async #onTransaction({ transaction, confirmed }: OnTransactionArgs) {
// Lock reward
const rewardsLockedByTx = this.#getOwnTransactionWithdrawalQty(transaction);
Expand All @@ -142,6 +153,7 @@ export class InMemoryUtxoRepository extends Emittery<UtxoRepositoryEvents> imple
this.#lockedUtxoSet.add(utxo);
utxoLockedByTx.push(utxo);
}
this.#emitSynced();
// Await confirmation. Rejection should be handled by the user after submitting transaction.
await confirmed.catch(() => void 0);
// Unlock utxo
Expand Down
30 changes: 13 additions & 17 deletions packages/wallet/src/types.ts
Expand Up @@ -4,36 +4,32 @@ import { CSL, Ogmios } from '@cardano-sdk/core';
import Emittery from 'emittery';

export enum UtxoRepositoryEvent {
OutOfSync = 'out-of-sync',
UtxoChanged = 'utxo-changed',
RewardsChanged = 'rewards-changed'
Changed = 'changed',
OutOfSync = 'out-of-sync'
}

export type UtxoRepositoryEvents = {
'out-of-sync': void;
'transaction-untracked': CSL.Transaction;
'utxo-changed': {
allUtxos: Schema.Utxo;
availableUtxos: Schema.Utxo;
};
'rewards-changed': {
allRewards: Schema.Lovelace;
availableRewards: Ogmios.Lovelace;
};
};
export interface UtxoRepository extends Emittery<UtxoRepositoryEvents> {
export interface UtxoRepositoryFields {
allUtxos: Schema.Utxo;
availableUtxos: Schema.Utxo;
allRewards: Ogmios.Lovelace | null;
availableRewards: Ogmios.Lovelace | null;
delegation: Schema.PoolId | null;
}

export type UtxoRepositoryEvents = {
changed: UtxoRepositoryFields;
'out-of-sync': void;
'transaction-untracked': CSL.Transaction;
};
export type UtxoRepository = {
sync: () => Promise<void>;
selectInputs: (
outputs: Set<CSL.TransactionOutput>,
constraints: SelectionConstraints,
implicitCoin?: ImplicitCoin
) => Promise<SelectionResult>;
}
} & UtxoRepositoryFields &
Emittery<UtxoRepositoryEvents>;

export interface OnTransactionArgs {
transaction: CSL.Transaction;
Expand Down
32 changes: 28 additions & 4 deletions packages/wallet/test/InMemoryUtxoRepository.test.ts
Expand Up @@ -8,7 +8,8 @@ import {
KeyManagement,
TransactionTrackerEvent,
UtxoRepository,
UtxoRepositoryEvent
UtxoRepositoryEvent,
UtxoRepositoryFields
} from '../src';
import { MockTransactionTracker } from './mockTransactionTracker';
import { ogmiosToCsl } from '@cardano-sdk/core/src/Ogmios';
Expand Down Expand Up @@ -65,10 +66,22 @@ describe('InMemoryUtxoRepository', () => {
});

test('sync', async () => {
const syncedHandler = jest.fn();
utxoRepository.on(UtxoRepositoryEvent.Changed, syncedHandler);
await utxoRepository.sync();
await expect(utxoRepository.allUtxos.length).toBe(3);
await expect(utxoRepository.allRewards).toBe(rewards);
await expect(utxoRepository.delegation).toBe(delegate);
const expectedFields: UtxoRepositoryFields = {
allUtxos: utxo,
availableUtxos: utxo,
allRewards: rewards,
availableRewards: rewards,
delegation: delegate
};
expect(utxoRepository).toMatchObject(expectedFields);
expect(syncedHandler).toBeCalledTimes(1);
expect(syncedHandler).toBeCalledWith(expectedFields);
// await expect(utxoRepository.allUtxos.length).toBe(3);
// await expect(utxoRepository.allRewards).toBe(rewards);
// await expect(utxoRepository.delegation).toBe(delegate);
const identicalUtxo = [{ ...utxo[1][0] }, { ...utxo[1][1] }] as const; // clone UTxO
provider.utxoDelegationAndRewards.mockResolvedValueOnce({
utxo: [utxo[0], identicalUtxo],
Expand All @@ -79,6 +92,7 @@ describe('InMemoryUtxoRepository', () => {
// Verify we're not replacing the object with an identical one in the UTxO set
await expect(utxoRepository.allUtxos).not.toContain(identicalUtxo);
await expect(utxoRepository.allUtxos).toContain(utxo[1]);
expect(syncedHandler).toBeCalledTimes(2);
});

describe('selectInputs', () => {
Expand All @@ -103,13 +117,23 @@ describe('InMemoryUtxoRepository', () => {
const transactionWithdrawal = 1n;

const trackTransaction = async (confirmed: Promise<void>) => {
const syncedHandler = jest.fn();
utxoRepository.on(UtxoRepositoryEvent.Changed, syncedHandler);
await txTracker.emit(TransactionTrackerEvent.NewTransaction, {
transaction,
confirmed
});
// transaction not yet confirmed
expect(utxoRepository.availableUtxos).toHaveLength(utxoRepository.allUtxos.length - 1);
expect(utxoRepository.availableUtxos).not.toContain(transactionUtxo);
expect(syncedHandler).toBeCalledTimes(1);
expect(syncedHandler).toBeCalledWith({
allUtxos: utxo,
availableUtxos: utxo.slice(1),
allRewards: rewards,
availableRewards: rewards - transactionWithdrawal,
delegation: delegate
} as UtxoRepositoryFields);
};

beforeEach(async () => {
Expand Down

0 comments on commit 7699044

Please sign in to comment.