Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make withdrawals work properly in Conway era [ADLT-2833] (WIP) #1420

Open
wants to merge 6 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ commands:
- checkout
- restore_cache:
keys:
- dependencies-{{ checksum "yarn.lock" }}-{{ checksum "app/yarn.lock"}}
- dependencies-v2-{{ checksum "yarn.lock" }}-{{ checksum "app/yarn.lock"}}
- run: cp .env.example .env
- run: yarn install
- run: cd app && yarn install && cd ../
Expand All @@ -23,7 +23,7 @@ commands:
- node_modules
- app/node_modules
- ../.cache/Cypress
key: dependencies-{{ checksum "yarn.lock" }}-{{ checksum "app/yarn.lock"}}
key: dependencies-v2-{{ checksum "yarn.lock" }}-{{ checksum "app/yarn.lock"}}

jobs:
audit:
Expand Down
1 change: 1 addition & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@ node_modules/
app/dist/
app/tests/dist/
app/node_modules/
app/libs/
sandbox.js
2 changes: 2 additions & 0 deletions .iyarc
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,5 @@ GHSA-3h5v-q93c-6h6q
# ip - no available patch at the time
GHSA-2p57-rm9w-gvfp

# cookie
GHSA-pxg6-pf52-xh8x
22 changes: 15 additions & 7 deletions app/frontend/actions/delegate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,13 +73,16 @@ export default (store: Store) => {
}
await setPoolInfo(state)
const poolHash = state.shelleyDelegation.selectedPool.poolHash as string
const isStakingKeyRegistered = getSourceAccountInfo(state).shelleyAccountInfo.hasStakingKey
const stakingAddress = getSourceAccountInfo(state).stakingAddress
const {
shelleyAccountInfo: {hasStakingKey: isStakingKeyRegistered, hasVoteDelegation},
stakingAddress,
} = getSourceAccountInfo(state)
const txPlanResult = prepareTxPlan({
poolHash,
stakingAddress,
isStakingKeyRegistered,
txType: TxType.DELEGATE,
hasVoteDelegation,
})
const newState = getState()
if (hasPoolIdentifiersChanged(newState)) {
Expand Down Expand Up @@ -180,15 +183,20 @@ export default (store: Store) => {
}

state = getState()
const sourceAccount = getSourceAccountInfo(state)
const rewards = getSourceAccountInfo(state).shelleyBalances.rewardsAccountBalance as Lovelace
const balance = getSourceAccountInfo(state).balance as Lovelace
const {
accountIndex,
balance,
stakingAddress,
shelleyAccountInfo: {hasVoteDelegation},
shelleyBalances: {rewardsAccountBalance: rewards},
} = getSourceAccountInfo(state)

loadingAction(state, 'Preparing transaction...')
const txPlanResult = prepareTxPlan({
txType: TxType.DEREGISTER_STAKE_KEY,
rewards,
stakingAddress: sourceAccount.stakingAddress,
stakingAddress,
hasVoteDelegation,
})
if (txPlanResult.success === true) {
const summary = {
Expand All @@ -199,7 +207,7 @@ export default (store: Store) => {

setTransactionSummary(getState(), {plan: txPlanResult.txPlan, transactionSummary: summary})
await confirmTransaction(getState(), {
sourceAccountIndex: sourceAccount.accountIndex,
sourceAccountIndex: accountIndex,
txPlan: txPlanResult.txPlan,
txConfirmType: TxType.DEREGISTER_STAKE_KEY,
})
Expand Down
20 changes: 10 additions & 10 deletions app/frontend/actions/transaction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,7 @@ export default (store: Store) => {
let txAux
try {
if (txPlan) {
txAux = await getWallet()
.getAccount(sourceAccountIndex)
.prepareTxAux(txPlan)
txAux = await getWallet().getAccount(sourceAccountIndex).prepareTxAux(txPlan)
} else {
loadingAction(state, 'Preparing transaction plan...')
await sleep(1000) // wait for plan to be set in case of unfortunate timing
Expand Down Expand Up @@ -220,12 +218,8 @@ export default (store: Store) => {
let sendResponse
try {
assert(txSummary.plan != null)
const txAux = await getWallet()
.getAccount(sourceAccountIndex)
.prepareTxAux(txSummary.plan)
const signedTx = await getWallet()
.getAccount(sourceAccountIndex)
.signTxAux(txAux)
const txAux = await getWallet().getAccount(sourceAccountIndex).prepareTxAux(txSummary.plan)
const signedTx = await getWallet().getAccount(sourceAccountIndex).signTxAux(txAux)
if (isHwWallet(cryptoProviderType)) {
setState({waitingHwWalletOperation: null})
stopLoadingAction(state)
Expand Down Expand Up @@ -330,7 +324,13 @@ export default (store: Store) => {
// TODO: rewards should be of type Lovelace
const rewards = getSourceAccountInfo(state).shelleyBalances.rewardsAccountBalance as Lovelace
const stakingAddress = getSourceAccountInfo(state).stakingAddress
const txPlanResult = prepareTxPlan({rewards, stakingAddress, txType: TxType.WITHDRAW})
const hasVoteDelegation = getSourceAccountInfo(state).shelleyAccountInfo.hasVoteDelegation
const txPlanResult = prepareTxPlan({
rewards,
stakingAddress,
hasVoteDelegation,
txType: TxType.WITHDRAW,
})
// TODO: balance should be of type Lovelace
const balance = getSourceAccountInfo(state).balance as Lovelace

Expand Down
5 changes: 5 additions & 0 deletions app/frontend/helpers/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,3 +55,8 @@ export function getCexplorerUrl() {
SANCHONET: 'https://sancho.cexplorer.io',
}[ADALITE_CONFIG.ADALITE_NETWORK]
}

// https://stackoverflow.com/questions/39419170/how-do-i-check-that-a-switch-block-is-exhaustive-in-typescript
export const safeAssertUnreachable = (x: never): never => {
throw new Error(`Unreachable switch case:${x}`)
}
1 change: 1 addition & 0 deletions app/frontend/state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,7 @@ const initialState: State = {
currentEpoch: 0,
delegation: {},
hasStakingKey: false,
hasVoteDelegation: false,
rewards: '0',
rewardDetails: {
upcoming: null,
Expand Down
5 changes: 5 additions & 0 deletions app/frontend/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ export enum CertificateType {
STAKING_KEY_DEREGISTRATION = 1,
DELEGATION = 2,
STAKEPOOL_REGISTRATION = 3,
VOTE_DELEGATION = 9,
}

export enum CryptoProviderFeature {
Expand Down Expand Up @@ -171,6 +172,7 @@ export type AccountInfo = {
currentEpoch: number
delegation: any
hasStakingKey: boolean
hasVoteDelegation: boolean
rewards: string
rewardDetails: {
upcoming: any
Expand Down Expand Up @@ -267,13 +269,15 @@ export type WithdrawRewardsTxPlanArgs = {
txType: TxType.WITHDRAW
rewards: Lovelace
stakingAddress: Address
hasVoteDelegation: boolean
}

export type DelegateAdaTxPlanArgs = {
txType: TxType.DELEGATE
poolHash: string
isStakingKeyRegistered: boolean
stakingAddress: Address
hasVoteDelegation: boolean
}

export type PoolOwnerTxPlanArgs = {
Expand All @@ -285,6 +289,7 @@ export type DeregisterStakingKeyTxPlanArgs = {
txType: TxType.DEREGISTER_STAKE_KEY
rewards: Lovelace
stakingAddress: Address
hasVoteDelegation: boolean
}

export type VotingRegistrationTxPlanArgs = {
Expand Down
18 changes: 7 additions & 11 deletions app/frontend/wallet/account.ts
Original file line number Diff line number Diff line change
Expand Up @@ -394,14 +394,10 @@ const Account = ({config, cryptoProvider, blockchainExplorer, accountIndex}: Acc

async function getBalance() {
const {legacy, base} = await myAddresses.discoverAllAddresses()
const {
coins: nonStakingBalance,
tokenBundle: nonStakingTokenBundle,
} = await blockchainExplorer.getBalance(legacy)
const {
coins: baseAddressBalance,
tokenBundle: stakingTokenBundle,
} = await blockchainExplorer.getBalance(base)
const {coins: nonStakingBalance, tokenBundle: nonStakingTokenBundle} =
await blockchainExplorer.getBalance(legacy)
const {coins: baseAddressBalance, tokenBundle: stakingTokenBundle} =
await blockchainExplorer.getBalance(base)
return {
tokenBalance: aggregateTokenBundles([nonStakingTokenBundle, stakingTokenBundle]),
baseAddressBalance,
Expand Down Expand Up @@ -436,9 +432,8 @@ const Account = ({config, cryptoProvider, blockchainExplorer, accountIndex}: Acc

async function getStakingInfo(validStakepoolDataProvider: StakepoolDataProvider) {
const stakingAddressHex = bechAddressToHex(await myAddresses.getStakingAddress())
const {nextRewardDetails, ...accountInfo} = await blockchainExplorer.getStakingInfo(
stakingAddressHex
)
const {nextRewardDetails, ...accountInfo} =
await blockchainExplorer.getStakingInfo(stakingAddressHex)
const rewardDetails = await blockchainExplorer.getRewardDetails(
nextRewardDetails,
accountInfo.delegation.poolHash,
Expand All @@ -448,6 +443,7 @@ const Account = ({config, cryptoProvider, blockchainExplorer, accountIndex}: Acc

return {
...accountInfo,
hasVoteDelegation: accountInfo.voteDelegation != null,
rewardDetails,
value: new BigNumber(accountInfo.rewards || 0) as Lovelace,
}
Expand Down
5 changes: 5 additions & 0 deletions app/frontend/wallet/backend-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,11 @@ export type StakingInfoResponse = {
hasStakingKey: boolean
rewards: string
nextRewardDetails: Array<NextRewardDetail>
voteDelegation: {
dRepHash: string
isAlwaysAbstain: boolean
isAlwaysNoConfidence: boolean
} | null
}

export type BestSlotResponse = {
Expand Down
28 changes: 25 additions & 3 deletions app/frontend/wallet/shelley/shelley-bitbox02-crypto-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,16 @@ import {
CryptoProviderType,
Network,
TxCertificate,
TxDRepType,
TxInput,
TxOutput,
TxShelleyWitness,
TxVoteDelegationCert,
} from '../types'
import {encodeCbor} from '../helpers/cbor'
import {safeAssertUnreachable} from '../../helpers/common'

import {
import type {
CardanoAssetGroup,
CardanoCertificate,
CardanoInput,
Expand All @@ -33,7 +37,6 @@ import {CborizedCliWitness, TxAux, TxSigned} from './types'
import {hasRequiredVersion} from './helpers/version-check'
import {BITBOX02_ERRORS, BITBOX02_VERSIONS} from '../constants'
import {ShelleySignedTransactionStructured, cborizeTxWitnesses} from './shelley-transaction'
import {encodeCbor} from '../helpers/cbor'
import {orderTokenBundle} from '../helpers/tokenFormater'
import debugLog from '../../helpers/debugLog'
import CachedDeriveXpubFactory from '../helpers/CachedDeriveXpubFactory'
Expand Down Expand Up @@ -174,6 +177,23 @@ const ShelleyBitBox02CryptoProvider = async ({
}
}

const prepareVoteDelegation = (
voteDelegation: TxVoteDelegationCert,
addressToAbsPathMapper: AddressToPathMapper
): CardanoCertificate => {
switch (voteDelegation.dRep.type) {
case TxDRepType.ALWAYS_ABSTAIN:
return {
voteDelegation: {
keypath: addressToAbsPathMapper(voteDelegation.stakingAddress),
type: 'alwaysAbstain',
},
}
default:
return safeAssertUnreachable(voteDelegation.dRep.type)
}
}

const prepareCertificate = (
certificate: TxCertificate,
addressToAbsPathMapper: AddressToPathMapper
Expand All @@ -198,12 +218,14 @@ const ShelleyBitBox02CryptoProvider = async ({
poolKeyhash: Buffer.from(certificate.poolHash, 'hex'),
},
}
case CertificateType.VOTE_DELEGATION:
return prepareVoteDelegation(certificate, addressToAbsPathMapper)
case CertificateType.STAKEPOOL_REGISTRATION:
throw new UnexpectedError(UnexpectedErrorReason.UnsupportedOperationError, {
message: 'Stakepool registration not supported',
})
default:
throw new UnexpectedError(UnexpectedErrorReason.InvalidCertificateType)
return safeAssertUnreachable(certificate)
}
}

Expand Down
29 changes: 28 additions & 1 deletion app/frontend/wallet/shelley/shelley-ledger-crypto-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,9 @@ import {
TxStakepoolRegistrationCert,
TxStakingKeyDeregistrationCert,
TxStakingKeyRegistrationCert,
TxVoteDelegationCert,
TxWithdrawal,
TxDRepType,
} from '../types'
import {TxSigned, TxAux, CborizedCliWitness, FinalizedAuxiliaryDataTx} from './types'
import {orderTokenBundle} from '../helpers/tokenFormater'
Expand All @@ -63,6 +65,7 @@ import {TxRelayType, TxStakepoolOwner, TxStakepoolRelay} from './helpers/poolCer
import assertUnreachable from '../../helpers/assertUnreachable'
import * as assert from 'assert'
import {encodeCbor} from '../helpers/cbor'
import {safeAssertUnreachable} from '../../helpers/common'

let _activeTransport: Transport | null
const getLedgerTransport = async (ledgerTransportType: LedgerTransportType): Promise<Transport> => {
Expand Down Expand Up @@ -396,6 +399,28 @@ const ShelleyLedgerCryptoProvider = async ({
}
}

type SupportedTxVoteDelegationCert = TxVoteDelegationCert & {
dRep: {type: TxDRepType.ALWAYS_ABSTAIN}
}
function prepareVoteDelegationCertificate(
certificate: SupportedTxVoteDelegationCert,
path: BIP32Path
): LedgerTypes.Certificate {
assert(certificate.dRep.type === TxDRepType.ALWAYS_ABSTAIN)
return {
type: LedgerTypes.CertificateType.VOTE_DELEGATION,
params: {
stakeCredential: {
type: LedgerTypes.CredentialParamsType.KEY_PATH,
keyPath: path,
},
dRep: {
type: LedgerTypes.DRepParamsType.ABSTAIN,
},
},
}
}

function prepareCertificate(
certificate: TxCertificate,
addressToAbsPathMapper: AddressToPathMapper
Expand All @@ -410,8 +435,10 @@ const ShelleyLedgerCryptoProvider = async ({
return prepareDelegationCertificate(certificate, path)
case CertificateType.STAKEPOOL_REGISTRATION:
return prepareStakepoolRegistrationCertificate(certificate, path)
case CertificateType.VOTE_DELEGATION:
return prepareVoteDelegationCertificate(certificate, path)
default:
throw new UnexpectedError(UnexpectedErrorReason.InvalidCertificateType)
return safeAssertUnreachable(certificate)
}
}

Expand Down
Loading