Skip to content

Commit

Permalink
feat: the chain context is now passed through state
Browse files Browse the repository at this point in the history
  • Loading branch information
Esya committed May 4, 2021
1 parent 7daf8a2 commit aa1fbff
Show file tree
Hide file tree
Showing 10 changed files with 157 additions and 112 deletions.
6 changes: 5 additions & 1 deletion src/app/components/AmountFormatter/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,11 @@ interface Props {

export const AmountFormatter = memo((props: Props) => {
const amount = Number(props.amount) / 10 ** 9
const amountString = new Intl.NumberFormat('en-US', { minimumFractionDigits: 1 }).format(amount)
const amountString = new Intl.NumberFormat('en-US', {
minimumFractionDigits: 1,
maximumFractionDigits: 15,
}).format(amount)

const ticker = useSelector(selectTicker)

return (
Expand Down
175 changes: 95 additions & 80 deletions src/app/components/TransactionModal/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { selectChainContext, selectSelectedNetwork } from 'app/state/network/selectors'
import { selectChainContext } from 'app/state/network/selectors'
import { transactionActions } from 'app/state/transaction'
import { selectTransaction } from 'app/state/transaction/selectors'
import { TransactionStep } from 'app/state/transaction/types'
Expand All @@ -9,6 +9,7 @@ import * as React from 'react'
import { useContext } from 'react'
import { useTranslation } from 'react-i18next'
import { useDispatch, useSelector } from 'react-redux'

import { AmountFormatter } from '../AmountFormatter'
import { PrettyAddress } from '../PrettyAddress'

Expand All @@ -28,7 +29,7 @@ interface Props {}
*/
export function TransactionModal(props: Props) {
const { t } = useTranslation()
const { transaction, step } = useSelector(selectTransaction)
const { preview, step } = useSelector(selectTransaction)
const walletAddress = useSelector(selectAddress)
const balance = useSelector(selectBalance)
const chainContext = useSelector(selectChainContext)
Expand Down Expand Up @@ -74,87 +75,101 @@ export function TransactionModal(props: Props) {
)}
</Text>
</Box>
<Grid
columns={size !== 'small' ? ['auto', 'auto'] : ['auto']}
gap={{ column: 'small', row: 'xsmall' }}
>
<Box>
<Text weight="bold">{t('transaction.preview.type', 'Type')} :</Text>
</Box>
<Box>Transfer</Box>
<Box>
<Text weight="bold">{t('transaction.preview.from', 'From')} :</Text>
</Box>
<Box>
<Text style={{ fontFamily: 'Roboto mono' }}>
<PrettyAddress address={walletAddress} />
</Text>
</Box>
<Box>
<Text weight="bold">{t('transaction.preview.to', 'To')} :</Text>
</Box>
<Box>
<Text style={{ fontFamily: 'Roboto mono' }}>
<PrettyAddress address={transaction!.to!} />
</Text>
</Box>
<Box>
<Text weight="bold">{t('transaction.preview.amount', 'Amount')} :</Text>
</Box>
<Box>
<AmountFormatter amount={transaction!.amount! * 10 ** 9} />
</Box>
<Box>
<Text weight="bold">{t('transaction.preview.balance', 'Balance')} :</Text>
</Box>
<Box>
<AmountFormatter amount={balance.available} />
</Box>
<Box>
<Text weight="bold">{t('transaction.preview.fee', 'Fee')} :</Text>
</Box>
<Box>Coming soon</Box>
<Box>
<Text weight="bold">{t('transaction.preview.gas', 'Gas')} :</Text>
</Box>
<Box>Coming soon</Box>
<Box>
<Text weight="bold">{t('transaction.preview.genesisHash', 'Genesis Hash')} :</Text>
</Box>
<Box
border={{
color: 'background-contrast-2',
side: 'left',
size: '3px',
}}
background={{
color: 'background-contrast',
opacity: 0.04,
}}
width="75%"
pad="xsmall"
{preview && (
<Grid
columns={size !== 'small' ? ['auto', 'auto'] : ['auto']}
gap={{ column: 'small', row: 'xsmall' }}
>
{chainContext}
<Box>
<Text weight="bold">{t('transaction.preview.type', 'Type')} :</Text>
</Box>
<Box>Transfer</Box>
<Box>
<Text weight="bold">{t('transaction.preview.from', 'From')} :</Text>
</Box>
<Box>
<Text style={{ fontFamily: 'Roboto mono' }}>
<PrettyAddress address={walletAddress} />
</Text>
</Box>
<Box>
<Text weight="bold">{t('transaction.preview.to', 'To')} :</Text>
</Box>
<Box>
<Text style={{ fontFamily: 'Roboto mono' }}>
<PrettyAddress address={preview!.transaction.to} />
</Text>
</Box>
<Box>
<Text weight="bold">{t('transaction.preview.amount', 'Amount')} :</Text>
</Box>
<Box>
<AmountFormatter amount={preview!.transaction.amount * 10 ** 9} />
</Box>
<Box>
<Text weight="bold">{t('transaction.preview.balance', 'Balance')} :</Text>
</Box>
<Box>
<AmountFormatter amount={balance.available} />
</Box>
<Box>
<Text weight="bold">{t('transaction.preview.fee', 'Fee')} :</Text>
</Box>
<Box>
<AmountFormatter amount={preview!.fee!} />
</Box>
<Box>
<Text weight="bold">{t('transaction.preview.gas', 'Gas')} :</Text>
</Box>
<Box>
<AmountFormatter amount={preview!.gas!} />
</Box>
<Box>
<Text weight="bold">{t('transaction.preview.genesisHash', 'Genesis Hash')} :</Text>
</Box>
<Box
border={{
color: 'background-contrast-2',
side: 'left',
size: '3px',
}}
background={{
color: 'background-contrast',
opacity: 0.04,
}}
width="75%"
pad="xsmall"
>
{chainContext}
</Box>
</Grid>
)}
{step === TransactionStep.Preview && (
<Box direction="row" gap="small" alignSelf="end" pad={{ top: 'large' }}>
<Button
secondary
label={t('transaction.abort', 'Abort')}
style={{ borderRadius: '4px' }}
icon={<Close size="18px" />}
onClick={abortTransaction}
/>
<Button
primary
label={t('transaction.confirm', 'Confirm')}
onClick={confirmTransaction}
icon={<Checkmark size="18px" />}
style={{ borderRadius: '4px' }}
alignSelf="end"
/>
</Box>
</Grid>
<Box direction="row" gap="small" alignSelf="end" pad={{ top: 'large' }}>
<Button
secondary
label={t('transaction.abort', 'Abort')}
style={{ borderRadius: '4px' }}
icon={<Close size="18px" />}
onClick={abortTransaction}
/>
<Button
primary
label={t('transaction.confirm', 'Confirm')}
onClick={confirmTransaction}
icon={<Checkmark size="18px" />}
style={{ borderRadius: '4px' }}
alignSelf="end"
/>
</Box>
)}
</Box>
{step === TransactionStep.Building && (
<Box direction="row" align="center" gap="medium">
<Spinner size="medium" />
<Text size="large">{t('transaction.step.building', 'Building transaction')}</Text>
</Box>
)}
{step === TransactionStep.Signing && (
<Box direction="row" align="center" gap="medium">
<Spinner size="medium" />
Expand Down
4 changes: 2 additions & 2 deletions src/app/lib/transaction.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,10 +72,10 @@ describe('OasisTransaction', () => {

expect(tw.signedTransaction).toBeUndefined()

await OasisTransaction.sign(nic, testSigner, tw)
await OasisTransaction.sign('', testSigner, tw)
const hexSignature = uint2hex(tw.signedTransaction.signature.signature)
expect(hexSignature).toEqual(
'4a4245ccacd47236cd38c548d140ec6235701f34ec2e7cc1da0a44389bd187b1a46331b2a3b0af126af0b704e99a939670deeb2bad68a571206e4f2c65eb8405',
'275f18f4830f7c10dd9c6243791c24b7508de10b0575483cf875055607bcb2d7d6fb184ddc0606e4222f7f23438cae38e6aff0849c5cd38e5a6c7f798da85d07',
)
})

Expand Down
21 changes: 6 additions & 15 deletions src/app/lib/transaction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ export const signerFromHDSecret = (secret: Uint8Array) => {
type TW<T> = oasis.consensus.TransactionWrapper<T>

export class OasisTransaction {
protected static chainContext?: string
protected static genesis?: oasis.types.GenesisDocument

public static async buildReclaimEscrow(
Expand Down Expand Up @@ -84,17 +83,18 @@ export class OasisTransaction {
return tw
}

public static async signUsingLedger<T>(nic: OasisClient, signer: ContextSigner, tw: TW<T>): Promise<void> {
const chainContext = await OasisTransaction.getChaincontext(nic)
console.log(chainContext)
public static async signUsingLedger<T>(
chainContext: string,
signer: ContextSigner,
tw: TW<T>,
): Promise<void> {
await tw.sign(signer, chainContext)

// @todo Upstream bug in oasis-app, the signature is larger than 64 bytes
tw.signedTransaction.signature.signature = tw.signedTransaction.signature.signature.slice(0, 64)
}

public static async sign<T>(nic: OasisClient, signer: Signer, tw: TW<T>): Promise<void> {
const chainContext = await OasisTransaction.getChaincontext(nic)
public static async sign<T>(chainContext: string, signer: Signer, tw: TW<T>): Promise<void> {
return tw.sign(new oasis.signature.BlindContextSigner(signer), chainContext)
}

Expand Down Expand Up @@ -127,13 +127,4 @@ export class OasisTransaction {

return BigInt(nonce || 0)
}

protected static async getChaincontext(nic: OasisClient): Promise<string> {
if (!OasisTransaction.chainContext) {
OasisTransaction.genesis = await nic.consensusGetGenesisDocument()
OasisTransaction.chainContext = await oasis.genesis.chainContext(OasisTransaction.genesis)
}

return OasisTransaction.chainContext
}
}
12 changes: 6 additions & 6 deletions src/app/state/ledger/saga.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
// import { take, call, put, select, takeLatest } from 'redux-saga/effects';

import * as oasis from '@oasisprotocol/client'
import TransportWebUSB from '@ledgerhq/hw-transport-webusb'
import * as oasis from '@oasisprotocol/client'
import { publicKeyToAddress, uint2hex } from 'app/lib/helpers'
import { Ledger, LedgerSigner } from 'app/lib/ledger'
import { OasisTransaction } from 'app/lib/transaction'
import { all, call, put, takeEvery } from 'typed-redux-saga'
import { all, call, put, select, takeEvery } from 'typed-redux-saga'
import { ErrorPayload, WalletError, WalletErrors } from 'types/errors'

import { ledgerActions } from '.'
import { selectChainContext } from '../network/selectors'
import { getBalance } from '../wallet/saga'
import { LedgerAccount, LedgerStep } from './types'
import { getOasisNic } from '../network/saga'

function* setStep(step: LedgerStep) {
yield* put(ledgerActions.setStep(step))
Expand Down Expand Up @@ -73,11 +73,11 @@ function* enumerateAccounts() {

export function* sign<T>(signer: LedgerSigner, tw: oasis.consensus.TransactionWrapper<T>) {
const transport: any = yield* getUSBTransport()
const nic = yield* call(getOasisNic)
const chainContext = yield* select(selectChainContext)

signer.setTransport(transport)
try {
yield* call([OasisTransaction, OasisTransaction.signUsingLedger], nic, signer, tw)
yield* call([OasisTransaction, OasisTransaction.signUsingLedger], chainContext, signer, tw)
} catch (e) {
yield* call([transport, transport.close])
throw e
Expand Down
16 changes: 13 additions & 3 deletions src/app/state/transaction/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,13 @@ import { ErrorPayload } from 'types/errors'
import { createSlice } from 'utils/@reduxjs/toolkit'
import { useInjectReducer, useInjectSaga } from 'utils/redux-injectors'
import { transactionSaga } from './saga'
import { SendTransactionPayload, TransactionSent, TransactionState, TransactionStep } from './types'
import {
SendTransactionPayload,
TransactionPreview,
TransactionSent,
TransactionState,
TransactionStep,
} from './types'

export const initialState: TransactionState = {
success: false,
Expand All @@ -15,7 +21,7 @@ const slice = createSlice({
initialState,
reducers: {
clearTransaction(state, action: PayloadAction<void>) {
state.transaction = undefined
state.preview = undefined
state.error = undefined
state.success = false
state.active = false
Expand All @@ -29,13 +35,17 @@ const slice = createSlice({
state.error = undefined
state.success = false
state.active = true
state.transaction = Object.assign({}, action.payload)
},
updateTransactionPreview(state, action: PayloadAction<TransactionPreview>) {
state.preview = Object.assign({}, action.payload)
},
transactionSent(state, action: PayloadAction<TransactionSent>) {
state.preview = undefined
state.success = true
state.active = false
},
transactionFailed(state, action: PayloadAction<ErrorPayload>) {
state.preview = undefined
state.error = action.payload
state.active = false
},
Expand Down
5 changes: 4 additions & 1 deletion src/app/state/transaction/saga.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,10 @@ describe('Transaction Sagas', () => {
const sendProviders: (EffectProviders | StaticProvider)[] = [
[matchers.call.fn(signerFromPrivateKey), {}],
[matchers.call.fn(signerFromHDSecret), {}],
[matchers.call.fn(OasisTransaction.buildTransfer), {}],
[
matchers.call.fn(OasisTransaction.buildTransfer),
{ transaction: { fee: { amount: new Uint8Array(0), gas: BigInt(0) } } },
],
[matchers.call.fn(OasisTransaction.sign), {}],
[matchers.call.fn(OasisTransaction.submit), {}],
]
Expand Down
Loading

0 comments on commit aa1fbff

Please sign in to comment.