Skip to content

Commit

Permalink
auto bond address check (#354)
Browse files Browse the repository at this point in the history
  • Loading branch information
Thorian1te authored Sep 30, 2024
1 parent 207f5e2 commit bd9b4b9
Show file tree
Hide file tree
Showing 23 changed files with 345 additions and 204 deletions.
3 changes: 3 additions & 0 deletions .storybook/preview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ window.apiHDWallet = { ...mockApi.apiHDWallet }
window.apiKeystore = { ...mockApi.apiKeystore }
window.apiLang = { ...mockApi.apiLang }
window.apiUrl = { ...mockApi.apiUrl }
window.apiAssetStorage = { ...mockApi.apiAssetStorage }
window.apiCommonStorage = { ...mockApi.apiCommonStorage }
window.apiChainStorage = { ...mockApi.apiChainStorage }

const lightTheme = { name: 'Light', ...themes.light }
const _darkTheme = { name: 'Dark', ...themes.dark }
Expand Down
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
- redesign asset select modal [#362](https://github.com/asgardex/asgardex-desktop/pull/362)
- Updated electron package [electron](https://github.com/asgardex/asgardex-desktop/pull/360)
- Added chain Radix [#294](https://github.com/asgardex/asgardex-desktop/pull/363)
- Auto bond | node provider address checking [#348](https://github.com/asgardex/asgardex-desktop/pull/354)
- Remove Swapping to synths, Target asset cannot be synth [#373](https://github.com/asgardex/asgardex-desktop/pull/364)

# 1.22.4 (2024-09-6)
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
"generate:bscerc20whitelist": "./node_modules/.bin/ts-node --project tsconfig.scripts.json ./scripts/generateBSCtokenlist.ts",
"generate:arberc20whitelist": "./node_modules/.bin/ts-node --project tsconfig.scripts.json ./scripts/generateARBtokenlist.ts",
"storybook": "NODE_OPTIONS=\"--max-old-space-size=4096\" sb dev -p 9009 ",
"build-storybook": "NODE_OPTIONS=\"--max-old-space-size=4096\" sb build",
"build-storybook": "NODE_OPTIONS=\"--max-old-space-size=8192\" sb build",
"analyze": "source-map-explorer 'build/static/js/*.js'",
"prepare": "husky install"
},
Expand Down Expand Up @@ -98,7 +98,7 @@
"@xchainjs/xchain-evm-providers": "1.0.7",
"@xchainjs/xchain-kujira": "1.0.2",
"@xchainjs/xchain-litecoin": "1.0.2",
"@xchainjs/xchain-mayachain": "2.0.4",
"@xchainjs/xchain-mayachain": "2.0.3",
"@xchainjs/xchain-mayachain-query": "1.0.4",
"@xchainjs/xchain-mayamidgard": "0.1.6",
"@xchainjs/xchain-mayamidgard-query": "0.1.19",
Expand Down
1 change: 1 addition & 0 deletions src/renderer/components/Bonds/Bonds.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ const mockNodeInfo = (address: Address) => ({
award: baseAmount(100000000 * 400000),
status: NodeStatusEnum.Active,
address,
nodeOperatorAddress: '',
bondProviders: {
nodeOperatorFee: baseAmount(100000000 * 400000),
providers: []
Expand Down
2 changes: 1 addition & 1 deletion src/renderer/components/Bonds/Bonds.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ type Props = {
nodes: NodeInfosRD
removeNode: (node: Address) => void
goToNode: (node: Address) => void
goToAction: (action: string, node: string) => void
goToAction: (action: string, node: string, walletType: string) => void
network: Network
addNode: (node: Address, network: Network) => void
addressValidationThor: AddressValidation
Expand Down
1 change: 1 addition & 0 deletions src/renderer/components/Bonds/table/BondsTable.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ const mockNodeInfo = (address: Address) => ({
award: baseAmount(100000000 * 400000),
status: NodeStatusEnum.Active,
address,
nodeOperatorAddress: '',
bondProviders: {
nodeOperatorFee: baseAmount(100000000 * 400000),
providers: []
Expand Down
23 changes: 16 additions & 7 deletions src/renderer/components/Bonds/table/BondsTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ type Props = {
loading?: boolean
removeNode: (node: Address) => void
goToNode: (node: Address) => void
goToAction: (action: string, node: string) => void
goToAction: (action: string, node: string, walletType: string) => void
network: Network
className?: string
walletAddresses: Record<'THOR' | 'MAYA', WalletAddressInfo[]>
Expand Down Expand Up @@ -126,32 +126,40 @@ export const BondsTable: React.FC<Props> = ({
key: 'action',
render: (_, record) => {
const { bondAddress, status, signMembership, nodeAddress } = record
const isWalletAddress =
walletAddresses.THOR.some((walletInfo) => walletInfo.address === bondAddress) ||
walletAddresses.MAYA.some((walletInfo) => walletInfo.address === bondAddress)

const nodeChain = getNodeChain(bondAddress)
// Check if the bond address matches a wallet address in either THOR or MAYA
const matchedWalletInfo =
walletAddresses.THOR.find((walletInfo) => walletInfo.address === bondAddress) ||
walletAddresses.MAYA.find((walletInfo) => walletInfo.address === bondAddress)

// Check if the bond address belongs to the current user's wallet
const isWalletAddress = !!matchedWalletInfo

const nodeChain = getNodeChain(bondAddress)
const matchedAddresses = matchedNodeAddress.filter((address) => {
const addressChain = getNodeChain(address)
return addressChain === nodeChain
})

const unbondDisabled =
status === 'Active' || (status === 'Standby' && signMembership && signMembership.includes(nodeAddress))

// Store walletType for the address and pass it to bond/unbond actions
const walletType = matchedWalletInfo?.walletType || 'Unknown'

return (
<div className="flex">
<TextButton
disabled={!isWalletAddress}
size="normal"
onClick={() => goToAction('bond', matchedAddresses[0])}>
onClick={() => goToAction('bond', matchedAddresses[0], walletType)}>
{intl.formatMessage({ id: 'deposit.interact.actions.bond' })}
</TextButton>
<div className="flex border-solid border-gray1 dark:border-gray1d">
<TextButton
disabled={!isWalletAddress || unbondDisabled}
size="normal"
onClick={() => goToAction('unbond', matchedAddresses[0])}>
onClick={() => goToAction('unbond', matchedAddresses[0], walletType)}>
{intl.formatMessage({ id: 'deposit.interact.actions.unbond' })}
</TextButton>
</div>
Expand Down Expand Up @@ -189,6 +197,7 @@ export const BondsTable: React.FC<Props> = ({
}
// Add other columns for the expanded table as needed
]

const [matchedNodeAddress, setMatchedNodeAddress] = useState<string[]>([])
const [expandedRowKeys, setExpandedRowKeys] = useState<string[]>([])

Expand Down
6 changes: 4 additions & 2 deletions src/renderer/components/deposit/add/SymDeposit.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ import {
max1e8BaseAmount,
to1e8BaseAmount
} from '../../../helpers/assetHelper'
import { getChainAsset, isAvaxChain, isBscChain, isEthChain } from '../../../helpers/chainHelper'
import { getChainAsset, isArbChain, isAvaxChain, isBscChain, isEthChain } from '../../../helpers/chainHelper'
import { isEvmChain, isEvmToken } from '../../../helpers/evmHelper'
import { unionAssets } from '../../../helpers/fp/array'
import { eqBaseAmount, eqOAsset, eqOApproveParams, eqAsset } from '../../../helpers/fp/eq'
Expand Down Expand Up @@ -1657,7 +1657,9 @@ export const SymDeposit: React.FC<Props> = (props) => {
// `0x` needs to be removed from tx hash in case of ETH
// @see https://github.com/thorchain/asgardex-electron/issues/1787#issuecomment-931934508
O.map((txHash) =>
isEthChain(chain) || isAvaxChain(chain) || isBscChain(chain) ? txHash.replace(/0x/i, '') : txHash
isEthChain(chain) || isAvaxChain(chain) || isBscChain(chain) || isArbChain(chain)
? txHash.replace(/0x/i, '')
: txHash
)
)

Expand Down
11 changes: 10 additions & 1 deletion src/renderer/components/wallet/assets/AssetsTableCollapsable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import { isKeystoreWallet } from '../../../../shared/utils/guard'
import { DEFAULT_WALLET_TYPE, ZERO_BASE_AMOUNT } from '../../../const'
import { isCacaoAsset, isMayaAsset, isRuneNativeAsset, isUSDAsset } from '../../../helpers/assetHelper'
import { getChainAsset } from '../../../helpers/chainHelper'
import { isEvmChain } from '../../../helpers/evmHelper'
import { getDeepestPool, getPoolPriceValue } from '../../../helpers/poolHelper'
import { getPoolPriceValue as getPoolPriceValueM } from '../../../helpers/poolHelperMaya'
import { hiddenString, noDataString } from '../../../helpers/stringHelper'
Expand All @@ -58,6 +59,7 @@ import { AssetIcon } from '../../uielements/assets/assetIcon'
import { FlatButton } from '../../uielements/button'
import { Action as ActionButtonAction, ActionButton } from '../../uielements/button/ActionButton'
import { ReloadButton } from '../../uielements/button/ReloadButton'
import { InfoIcon } from '../../uielements/info'
import { QRCodeModal } from '../../uielements/qrCodeModal/QRCodeModal'
import * as Styled from './AssetsTableCollapsable.styles'

Expand Down Expand Up @@ -618,9 +620,16 @@ export const AssetsTableCollapsable: React.FC<Props> = (props): JSX.Element => {
</Styled.CopyLabelContainer>
</Styled.HeaderAddress>
</Col>

<Col flex="0 1 auto" span={3} style={{ textAlign: 'right' }}>
<Styled.HeaderLabel color={RD.isFailure(balancesRD) ? 'error' : 'gray'}>
{`${assetsTxt}`}
<span style={{ display: 'flex', alignItems: 'center', justifyContent: 'flex-end' }}>
{isEvmChain(chain) && (
// @asgardexTeam Add Locale for tooltip
<InfoIcon tooltip={'Token not showing, add contract in wallet settings'} color="primary" />
)}
<span style={{ marginLeft: isEvmChain(chain) ? '5px' : '0' }}>{assetsTxt}</span>
</span>
</Styled.HeaderLabel>
</Col>
<Col flex="0 0 12rem" span={1}>
Expand Down
11 changes: 8 additions & 3 deletions src/renderer/components/wallet/txs/TxForm.helpers.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -89,9 +89,13 @@ export const hasFormErrors = (form: FormInstance) =>
!!form.getFieldsError().filter(({ errors }) => errors.length).length

// detecting a swap memo
export function checkMemo(memo: string): boolean {
// Check if the memo is not empty and starts with '=' or 'SWAP'
if (memo === '') return false
export function checkMemo(memo: string | undefined): boolean {
// Ensure memo is a valid string and not undefined or empty
if (!memo || typeof memo !== 'string') {
return false
}

// Check if the memo starts with '=', 'SWAP', 'swap', 's', or 'S'
if (
memo.startsWith('=') ||
memo.startsWith('SWAP') ||
Expand All @@ -101,6 +105,7 @@ export function checkMemo(memo: string): boolean {
) {
return true
}

return false
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ describe('wallet/interact/helpers', () => {
bond: baseAmount(100000000 * 40000000),
award: baseAmount(100000000 * 400000),
status: 'Active' as NodeStatusEnum,
nodeOperatorAddress: '',
bondProviders: { providers: [], nodeOperatorFee: baseAmount(100000000 * 400000) }, // Mock bondProviders
signMembership: []
},
Expand All @@ -148,6 +149,7 @@ describe('wallet/interact/helpers', () => {
bond: baseAmount(100000000 * 40000000), // Mock bond value
award: baseAmount(100000000 * 400000), // Mock award value
status: 'Standby' as NodeStatusEnum,
nodeOperatorAddress: '',
bondProviders: { providers: [], nodeOperatorFee: baseAmount(100000000 * 400000) }, // Mock bondProviders
signMembership: ['thor16ery22gma35h2fduxr0swdfvz4s6yvy6yhskf6']
},
Expand All @@ -156,6 +158,7 @@ describe('wallet/interact/helpers', () => {
bond: baseAmount(100000000 * 40000000), // Mock bond value
award: baseAmount(100000000 * 400000), // Mock award value
status: 'Standby' as NodeStatusEnum,
nodeOperatorAddress: '',
bondProviders: { providers: [], nodeOperatorFee: baseAmount(100000000 * 400000) }, // Mock bondProviders
signMembership: []
}
Expand Down Expand Up @@ -187,6 +190,7 @@ describe('wallet/interact/helpers', () => {
address: 'thor1nprw0w6ex8xh4tfl3vtkhqnjvds68kwshq9ax9',
bond: baseAmount(100000000 * 40000000), // Mock bond value
award: baseAmount(100000000 * 400000), // Mock award value
nodeOperatorAddress: '',
status: 'Disabled' as NodeStatusEnum,
bondProviders: { providers: [], nodeOperatorFee: baseAmount(100000000 * 400000) }, // Mock bondProviders
signMembership: []
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ const mockNodeInfo = (address: Address) => ({
award: baseAmount(100000000 * 400000),
status: NodeStatusEnum.Active,
address,
nodeOperatorAddress: '',
bondProviders: {
nodeOperatorFee: baseAmount(100000000 * 400000),
providers: []
Expand Down
71 changes: 56 additions & 15 deletions src/renderer/components/wallet/txs/interact/InteractFormThor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -84,8 +84,9 @@ type FormValues = {
}
type UserNodeInfo = {
nodeAddress: string
walletAddress: string
bondAmount: BaseAmount
bondProviderAddress?: string
bondAmount?: BaseAmount
isNodeOperatorAddress: boolean
}

type Props = {
Expand Down Expand Up @@ -214,25 +215,34 @@ export const InteractFormThor: React.FC<Props> = (props) => {
let foundNodeInfo: UserNodeInfo | undefined = undefined

for (const node of nodes) {
const matchingProvider = node.bondProviders.providers.find((provider) => walletAddress === provider.bondAddress)
const normalizedNodeOperatorAddress = node.nodeOperatorAddress.toLowerCase()
const normalizedWalletAddress = walletAddress.toLowerCase()

if (matchingProvider) {
// If a matching provider is found, set the UserNodeInfo state
// Check if the wallet address matches the node address
const isNodeOperatorAddress = normalizedNodeOperatorAddress === normalizedWalletAddress

// Check if the wallet address matches any bond provider address
const matchingProvider = node.bondProviders.providers.find(
(provider) => normalizedWalletAddress === provider.bondAddress.toLowerCase()
)

if (isNodeOperatorAddress || matchingProvider) {
foundNodeInfo = {
nodeAddress: node.address,
walletAddress: matchingProvider.bondAddress,
bondAmount: matchingProvider.bond
isNodeOperatorAddress,
bondProviderAddress: matchingProvider?.bondAddress,
bondAmount: matchingProvider?.bond
}
break // Exit the loop after finding the first match
break
}
}

if (foundNodeInfo) {
setUserNodeInfo(foundNodeInfo)
} else {
setUserNodeInfo(undefined) // Reset the state if no match is found
setUserNodeInfo(undefined)
}
}, [nodes, walletAddress]) // Re-run the effect if nodes or walletAddress changes
}, [nodes, walletAddress])

const [memo, setMemo] = useState<string>('')
const amountToSend = useMemo(() => {
Expand Down Expand Up @@ -340,7 +350,7 @@ export const InteractFormThor: React.FC<Props> = (props) => {
(fee) => {
if (interactType === 'unbond') {
let maxAmountBalOrBond: BaseAmount = ZERO_BASE_AMOUNT
maxAmountBalOrBond = userNodeInfo ? userNodeInfo.bondAmount : ZERO_BASE_AMOUNT
maxAmountBalOrBond = userNodeInfo?.bondAmount ? userNodeInfo.bondAmount : ZERO_BASE_AMOUNT
return maxAmountBalOrBond
} else if (interactType === 'runePool' && runePoolAction === Action.withdraw) {
return runePoolProvider.value.gt(0) ? runePoolProvider.value : ZERO_BASE_AMOUNT
Expand Down Expand Up @@ -750,6 +760,37 @@ export const InteractFormThor: React.FC<Props> = (props) => {
[estimateThornameHandler]
)

const amountLabel = useMemo(() => {
switch (interactType) {
case 'bond':
return `${intl.formatMessage({ id: 'deposit.interact.actions.bond' })} ${intl.formatMessage({
id: 'common.amount'
})}`

case 'unbond':
return `${intl.formatMessage({ id: 'deposit.interact.actions.unbond' })} ${intl.formatMessage({
id: 'common.amount'
})}`
case 'leave':
return intl.formatMessage({ id: 'deposit.interact.actions.leave' })
case 'runePool': {
return intl.formatMessage({
id: 'common.amount'
})
}
case 'custom':
return `${intl.formatMessage({
id: 'common.custom'
})} ${intl.formatMessage({
id: 'common.amount'
})}`
case 'thorname':
return intl.formatMessage({
id: 'common.amount'
})
}
}, [interactType, intl])

const submitLabel = useMemo(() => {
switch (interactType) {
case 'bond':
Expand Down Expand Up @@ -839,7 +880,7 @@ export const InteractFormThor: React.FC<Props> = (props) => {
const [showDetails, setShowDetails] = useState<boolean>(true)
const address = ''
const amount = bn(0)
const bondBaseAmount = userNodeInfo ? userNodeInfo.bondAmount : baseAmount(0)
const bondBaseAmount = userNodeInfo?.bondAmount ? userNodeInfo.bondAmount : baseAmount(0)

return (
<Styled.Form
Expand Down Expand Up @@ -908,7 +949,7 @@ export const InteractFormThor: React.FC<Props> = (props) => {
)}

{/* Provider address input (BOND/UNBOND/ only) */}
{(interactType === 'bond' || interactType === 'unbond') && (
{(interactType === 'bond' || interactType === 'unbond') && !userNodeInfo?.bondProviderAddress && (
<Styled.InputContainer style={{ paddingBottom: '20px' }}>
<CheckButton checked={hasProviderAddress} clickHandler={onClickHasProviderAddress} disabled={isLoading}>
{intl.formatMessage({ id: 'deposit.interact.label.bondprovider' })}
Expand Down Expand Up @@ -1320,10 +1361,10 @@ export const InteractFormThor: React.FC<Props> = (props) => {
)}

<div className="ml-[-2px] flex w-full justify-between pt-10px font-mainBold text-[14px]">
{intl.formatMessage({ id: 'common.amount' })}
{amountLabel}
<div className="truncate pl-10px font-main text-[12px]">
{formatAssetAmountCurrency({
amount: baseToAsset(amountToSend),
amount: interactType === 'unbond' ? baseToAsset(_amountToSend) : baseToAsset(amountToSend),
asset: AssetRuneNative,
decimal: isUSDAsset(AssetRuneNative) ? 2 : 6,
trimZeros: !isUSDAsset(AssetRuneNative)
Expand Down
Loading

0 comments on commit bd9b4b9

Please sign in to comment.