From 14467e79b1a31ddfffce0660c67a98c72d8cad36 Mon Sep 17 00:00:00 2001 From: Martynas Kazlauskas Date: Fri, 14 Jan 2022 15:51:41 +0200 Subject: [PATCH] feat(wallet): add Wallet.timeSettings$ add integration test as example of computing tx date --- packages/wallet/.env.example | 1 + packages/wallet/src/SingleAddressWallet.ts | 8 ++++ packages/wallet/src/types.ts | 3 +- .../wallet/test/SingleAddressWallet.test.ts | 13 ++++-- .../SingleAddressWallet/delegation.test.ts | 11 ++++- .../test/e2e/SingleAddressWallet/nft.test.ts | 3 +- packages/wallet/test/e2e/config.ts | 12 +++++- .../test/integration/transactionTime.test.ts | 42 +++++++++++++++++++ .../test/integration/withdrawal.test.ts | 6 ++- 9 files changed, 89 insertions(+), 10 deletions(-) create mode 100644 packages/wallet/test/integration/transactionTime.test.ts diff --git a/packages/wallet/.env.example b/packages/wallet/.env.example index 3ce117ce103..e33ead25020 100644 --- a/packages/wallet/.env.example +++ b/packages/wallet/.env.example @@ -1,5 +1,6 @@ WALLET_PROVIDER=blockfrost STAKE_POOL_SEARCH_PROVIDER=stub +TIME_SETTINGS_PROVIDER=stub_testnet BLOCKFROST_API_KEY=testnetNElagmhpQDubE6Ic4XBUVJjV5DROyijO NETWORK_ID=0 MNEMONIC_WORDS="actor scout worth mansion thumb device mass pave gospel secret height document merge text broom kind lesson invest across estate erase interest end century" diff --git a/packages/wallet/src/SingleAddressWallet.ts b/packages/wallet/src/SingleAddressWallet.ts index 6ef914d6e61..d2c2941d2fd 100644 --- a/packages/wallet/src/SingleAddressWallet.ts +++ b/packages/wallet/src/SingleAddressWallet.ts @@ -6,6 +6,8 @@ import { NetworkInfo, ProtocolParametersRequiredByWallet, StakePoolSearchProvider, + TimeSettings, + TimeSettingsProvider, WalletProvider, coreToCsl } from '@cardano-sdk/core'; @@ -56,6 +58,7 @@ export interface SingleAddressWalletDependencies { readonly walletProvider: WalletProvider; readonly stakePoolSearchProvider: StakePoolSearchProvider; readonly assetProvider: AssetProvider; + readonly timeSettingsProvider: TimeSettingsProvider; readonly inputSelector?: InputSelector; readonly logger?: Logger; } @@ -80,6 +83,7 @@ export class SingleAddressWallet implements Wallet { addresses$: TrackerSubject; protocolParameters$: TrackerSubject; genesisParameters$: TrackerSubject; + timeSettings$: TrackerSubject; assets$: TrackerSubject; name: string; @@ -98,6 +102,7 @@ export class SingleAddressWallet implements Wallet { stakePoolSearchProvider, keyAgent, assetProvider, + timeSettingsProvider, logger = dummyLogger, inputSelector = roundRobinRandomImprove() }: SingleAddressWalletDependencies @@ -117,6 +122,9 @@ export class SingleAddressWallet implements Wallet { coldObservableProvider(walletProvider.networkInfo, retryBackoffConfig, tipBlockHeight$, isEqual) ); const epoch$ = distinctEpoch(this.networkInfo$); + this.timeSettings$ = new TrackerSubject( + coldObservableProvider(timeSettingsProvider, retryBackoffConfig, epoch$, isEqual) + ); this.protocolParameters$ = new TrackerSubject( coldObservableProvider(walletProvider.currentWalletProtocolParameters, retryBackoffConfig, epoch$, isEqual) ); diff --git a/packages/wallet/src/types.ts b/packages/wallet/src/types.ts index 69a9774cd8b..44ef91b808d 100644 --- a/packages/wallet/src/types.ts +++ b/packages/wallet/src/types.ts @@ -1,5 +1,5 @@ import { Balance, BehaviorObservable, DelegationTracker, TransactionalTracker, TransactionsTracker } from './services'; -import { Cardano, NetworkInfo, ProtocolParametersRequiredByWallet } from '@cardano-sdk/core'; +import { Cardano, NetworkInfo, ProtocolParametersRequiredByWallet, TimeSettings } from '@cardano-sdk/core'; import { GroupedAddress } from './KeyManagement'; import { NftMetadata } from './NftMetadata'; import { SelectionSkeleton } from '@cardano-sdk/cip2'; @@ -43,6 +43,7 @@ export interface Wallet { readonly utxo: TransactionalTracker; readonly transactions: TransactionsTracker; readonly tip$: BehaviorObservable; + readonly timeSettings$: BehaviorObservable; readonly genesisParameters$: BehaviorObservable; readonly networkInfo$: BehaviorObservable; readonly protocolParameters$: BehaviorObservable; diff --git a/packages/wallet/test/SingleAddressWallet.test.ts b/packages/wallet/test/SingleAddressWallet.test.ts index a86e1efb2da..ecfa4e88e2d 100644 --- a/packages/wallet/test/SingleAddressWallet.test.ts +++ b/packages/wallet/test/SingleAddressWallet.test.ts @@ -1,7 +1,7 @@ /* eslint-disable max-len */ import * as mocks from './mocks'; -import { AssetId, createStubStakePoolSearchProvider } from '@cardano-sdk/util-dev'; -import { Cardano } from '@cardano-sdk/core'; +import { AssetId, createStubStakePoolSearchProvider, createStubTimeSettingsProvider } from '@cardano-sdk/util-dev'; +import { Cardano, testnetTimeSettings } from '@cardano-sdk/core'; import { KeyManagement, SingleAddressWallet } from '../src'; import { firstValueFrom, skip } from 'rxjs'; import { testKeyAgent } from './mocks'; @@ -20,11 +20,15 @@ describe('SingleAddressWallet', () => { walletProvider = mocks.mockWalletProvider(); assetProvider = mocks.mockAssetProvider(); const stakePoolSearchProvider = createStubStakePoolSearchProvider(); + const timeSettingsProvider = createStubTimeSettingsProvider(testnetTimeSettings); keyAgent.deriveAddress = jest.fn().mockResolvedValue({ address, rewardAccount }); - wallet = new SingleAddressWallet({ name }, { assetProvider, keyAgent, stakePoolSearchProvider, walletProvider }); + wallet = new SingleAddressWallet( + { name }, + { assetProvider, keyAgent, stakePoolSearchProvider, timeSettingsProvider, walletProvider } + ); }); afterEach(() => wallet.shutdown()); @@ -84,6 +88,9 @@ describe('SingleAddressWallet', () => { it('"assets$"', async () => { expect(await firstValueFrom(wallet.assets$)).toEqual(new Map([[AssetId.TSLA, mocks.asset]])); }); + it('timeSettings$', async () => { + expect(await firstValueFrom(wallet.timeSettings$)).toEqual(testnetTimeSettings); + }); }); describe('creating transactions', () => { diff --git a/packages/wallet/test/e2e/SingleAddressWallet/delegation.test.ts b/packages/wallet/test/e2e/SingleAddressWallet/delegation.test.ts index 96dffe19b7a..ecd2d1d9369 100644 --- a/packages/wallet/test/e2e/SingleAddressWallet/delegation.test.ts +++ b/packages/wallet/test/e2e/SingleAddressWallet/delegation.test.ts @@ -1,6 +1,14 @@ import { Cardano } from '@cardano-sdk/core'; import { SingleAddressWallet, StakeKeyStatus, Wallet } from '../../../src'; -import { assetProvider, keyAgentReady, poolId1, poolId2, stakePoolSearchProvider, walletProvider } from '../config'; +import { + assetProvider, + keyAgentReady, + poolId1, + poolId2, + stakePoolSearchProvider, + timeSettingsProvider, + walletProvider +} from '../config'; import { distinctUntilChanged, filter, firstValueFrom, map, merge, mergeMap, skip, tap, timer } from 'rxjs'; const faucetAddress = Cardano.Address( @@ -64,6 +72,7 @@ describe('SingleAddressWallet/delegation', () => { assetProvider, keyAgent: await keyAgentReady, stakePoolSearchProvider, + timeSettingsProvider, walletProvider } ); diff --git a/packages/wallet/test/e2e/SingleAddressWallet/nft.test.ts b/packages/wallet/test/e2e/SingleAddressWallet/nft.test.ts index 2ce8b9330f8..ad0b5d151c3 100644 --- a/packages/wallet/test/e2e/SingleAddressWallet/nft.test.ts +++ b/packages/wallet/test/e2e/SingleAddressWallet/nft.test.ts @@ -1,6 +1,6 @@ import { Cardano } from '@cardano-sdk/core'; import { KeyManagement, SingleAddressWallet, Wallet } from '../../../src'; -import { assetProvider, keyAgentReady, stakePoolSearchProvider, walletProvider } from '../config'; +import { assetProvider, keyAgentReady, stakePoolSearchProvider, timeSettingsProvider, walletProvider } from '../config'; import { combineLatest, filter, firstValueFrom, map } from 'rxjs'; describe('SingleAddressWallet/delegation', () => { @@ -26,6 +26,7 @@ describe('SingleAddressWallet/delegation', () => { assetProvider, keyAgent: await keyAgentReady, stakePoolSearchProvider, + timeSettingsProvider, walletProvider } ); diff --git a/packages/wallet/test/e2e/config.ts b/packages/wallet/test/e2e/config.ts index 18f28616ae7..14c0b09f3be 100644 --- a/packages/wallet/test/e2e/config.ts +++ b/packages/wallet/test/e2e/config.ts @@ -1,7 +1,7 @@ -import { Cardano } from '@cardano-sdk/core'; +import { Cardano, testnetTimeSettings } from '@cardano-sdk/core'; import { InMemoryKeyAgent } from '../../src/KeyManagement'; import { blockfrostAssetProvider, blockfrostWalletProvider } from '@cardano-sdk/blockfrost'; -import { createStubStakePoolSearchProvider } from '@cardano-sdk/util-dev'; +import { createStubStakePoolSearchProvider, createStubTimeSettingsProvider } from '@cardano-sdk/util-dev'; const networkId = Number.parseInt(process.env.NETWORK_ID || ''); if (Number.isNaN(networkId)) throw new Error('NETWORK_ID not set'); @@ -43,6 +43,14 @@ export const stakePoolSearchProvider = (() => { throw new Error(`STAKE_POOL_SEARCH_PROVIDER unsupported: ${stakePoolSearchProviderName}`); })(); +export const timeSettingsProvider = (() => { + const timeSettingsProviderName = process.env.TIME_SETTINGS_PROVIDER; + if (timeSettingsProviderName === 'stub_testnet') { + return createStubTimeSettingsProvider(testnetTimeSettings); + } + throw new Error(`TIME_SETTINGS_PROVIDER unsupported: ${timeSettingsProviderName}`); +})(); + if (!process.env.POOL_ID_1) throw new Error('POOL_ID_1 not set'); export const poolId1 = Cardano.PoolId(process.env.POOL_ID_1!); diff --git a/packages/wallet/test/integration/transactionTime.test.ts b/packages/wallet/test/integration/transactionTime.test.ts new file mode 100644 index 00000000000..2a91ea9192b --- /dev/null +++ b/packages/wallet/test/integration/transactionTime.test.ts @@ -0,0 +1,42 @@ +import { Cardano, createSlotTimeCalc, testnetTimeSettings } from '@cardano-sdk/core'; +import { KeyManagement, SingleAddressWallet, SingleAddressWalletProps } from '../../src'; +import { createStubStakePoolSearchProvider, createStubTimeSettingsProvider } from '@cardano-sdk/util-dev'; +import { firstValueFrom } from 'rxjs'; +import { mockAssetProvider, mockWalletProvider } from '../mocks'; + +const walletProps: SingleAddressWalletProps = { name: 'some-wallet' }; +const networkId = Cardano.NetworkId.mainnet; +const mnemonicWords = KeyManagement.util.generateMnemonicWords(); +const getPassword = async () => Buffer.from('your_password'); + +describe('integration/transactionTime', () => { + let keyAgent: KeyManagement.KeyAgent; + let wallet: SingleAddressWallet; + + beforeAll(async () => { + keyAgent = await KeyManagement.InMemoryKeyAgent.fromBip39MnemonicWords({ + getPassword, + mnemonicWords, + networkId + }); + const walletProvider = mockWalletProvider(); + const stakePoolSearchProvider = createStubStakePoolSearchProvider(); + const timeSettingsProvider = createStubTimeSettingsProvider(testnetTimeSettings); + const assetProvider = mockAssetProvider(); + wallet = new SingleAddressWallet(walletProps, { + assetProvider, + keyAgent, + stakePoolSearchProvider, + timeSettingsProvider, + walletProvider + }); + }); + + it('provides utils necessary for computing transaction time', async () => { + const transactions = await firstValueFrom(wallet.transactions.history.incoming$); + const timeSettings = await firstValueFrom(wallet.timeSettings$); + const slotTimeCalc = createSlotTimeCalc(timeSettings); + const transactionTime = slotTimeCalc(transactions[0].blockHeader.slot); + expect(typeof transactionTime.getTime()).toBe('number'); + }); +}); diff --git a/packages/wallet/test/integration/withdrawal.test.ts b/packages/wallet/test/integration/withdrawal.test.ts index 369bf795456..c3d1473865f 100644 --- a/packages/wallet/test/integration/withdrawal.test.ts +++ b/packages/wallet/test/integration/withdrawal.test.ts @@ -1,6 +1,6 @@ -import { Cardano } from '@cardano-sdk/core'; +import { Cardano, testnetTimeSettings } from '@cardano-sdk/core'; import { KeyManagement, SingleAddressWallet, SingleAddressWalletProps, TransactionFailure } from '../../src'; -import { createStubStakePoolSearchProvider } from '@cardano-sdk/util-dev'; +import { createStubStakePoolSearchProvider, createStubTimeSettingsProvider } from '@cardano-sdk/util-dev'; import { firstValueFrom } from 'rxjs'; import { mockAssetProvider, mockWalletProvider } from '../mocks'; @@ -21,11 +21,13 @@ describe('integration/withdrawal', () => { }); const walletProvider = mockWalletProvider(); const stakePoolSearchProvider = createStubStakePoolSearchProvider(); + const timeSettingsProvider = createStubTimeSettingsProvider(testnetTimeSettings); const assetProvider = mockAssetProvider(); wallet = new SingleAddressWallet(walletProps, { assetProvider, keyAgent, stakePoolSearchProvider, + timeSettingsProvider, walletProvider }); });