Skip to content

Commit

Permalink
Merge pull request #436 from chain4travel/msig-pending-tx
Browse files Browse the repository at this point in the history
create CamBadge component and add pending transaction badge to KeyRow component
  • Loading branch information
Ysrbolles authored Dec 24, 2024
2 parents 96c98a2 + fc6991b commit 1f1b738
Show file tree
Hide file tree
Showing 10 changed files with 235 additions and 8 deletions.
12 changes: 12 additions & 0 deletions src/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,9 @@ export default {
mounted() {
let { updateSuiteStore } = this.globalHelper()
updateSuiteStore(this.$store.state)
this.$store.dispatch('Signavault/updateImportedMultiSigTransaction')
},
watch: {
'$store.state.isAuth': [
{
Expand All @@ -58,6 +60,13 @@ export default {
deep: false,
},
],
'$store.state.Signavault.importedTransactions': [
{
handler: 'updatePendingTX',
immediate: false,
deep: false,
},
],
},
methods: {
onAuthChanged(val, _) {
Expand All @@ -67,6 +76,9 @@ export default {
this.$router.push('/login')
}
},
updatePendingTX() {
this.globalHelper()?.updateStore('updatePendingTxState', true)
},
},
metaInfo: {
meta: [
Expand Down
2 changes: 1 addition & 1 deletion src/bootloader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ export const mount = (el: string, appSuiteStore: any) => {
install(Vue) {
Vue.prototype.globalHelper = () => {
return {
updateStore: (params) => appSuiteStore.updateStore(params),
updateStore: (type, params) => appSuiteStore.updateStore(type, params),
updateSuiteStore: (s) => setUpdateStore(s),
updateShowAlias: () => updateShowAlias(),
logout: () => setLogOut(true),
Expand Down
112 changes: 112 additions & 0 deletions src/components/CamBadge.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
<template>
<div :class="badgeClass" :style="style">
<label :class="size">{{ label }}</label>
</div>
</template>

<script lang="ts">
import { Component, Prop, Vue } from 'vue-property-decorator'
import { CSSProperties } from 'vue'
enum BadgeVariant {
Default = 'default',
Primary = 'primary',
Positive = 'positive',
Warning = 'warning',
Negative = 'negative',
Verified = 'verified',
}
@Component
export default class CamBadge extends Vue {
@Prop({ default: 'default' }) readonly variant?: BadgeVariant
@Prop() label!: string
@Prop({ default: 'medium' }) size?: 'small' | 'medium'
@Prop() style?: CSSProperties
get badgeClass() {
return `camino__badge camino__${this.variant}--badge`
}
}
</script>

<style lang="scss" scoped>
.camino__badge {
width: fit-content;
display: flex;
align-items: center;
padding: 1px 8px;
border-radius: 4px;
}
.camino__default--badge {
background: var(--tailwind-slate-slate-800);
color: var(--tailwind-slate-slate-300);
}
.camino__primary--badge {
background: rgba(0, 133, 255, 0.2);
color: var(--camino-brand-too-blue-to-be-true);
}
.camino__positive--badge {
background: rgba(9, 222, 107, 0.2);
color: var(--camino-success-light);
}
.camino__warning--badge {
background: rgba(229, 162, 31, 0.2);
color: var(--camino-warning-light);
}
.camino__negative--badge {
background: rgba(229, 67, 31, 0.2);
color: var(--camino-error-light);
}
.camino__verified--badge {
background: var(--camino-aphrodite-aqua);
color: var(--tailwind-slate-slate-800);
}
.small,
.medium {
font-family: Inter;
letter-spacing: 1.6px;
text-align: center;
text-transform: uppercase;
font-weight: 600;
line-height: 18px;
font-variant-numeric: lining-nums tabular-nums slashed-zero;
font-feature-settings: 'ss01' on;
font-size: 10px;
}
.small {
font-size: 10px;
}
.medium {
font-size: 12px;
}
[data-theme='light'] {
.camino__primary--badge {
background: #0085ff33;
}
.camino__positive--badge {
background: var(--camino-success-light);
color: #ffff;
}
.camino__warning--badge {
background: var(--camino-warning-light);
color: #ffff;
}
.camino__negative--badge {
background: var(--camino-error-light);
color: #ffff;
}
}
</style>
15 changes: 14 additions & 1 deletion src/components/wallet/manage/KeyRow.vue
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,11 @@
>
{{ $t('keys.view_priv_key') }}
</button>
<CamBadge
v-if="walletType === 'multisig' && hasPending()"
label="pending tx"
variant="warning"
/>
<button
v-if="walletType === 'multisig'"
@click="showMultisigOwnerModal"
Expand Down Expand Up @@ -141,7 +146,7 @@
</template>
<script lang="ts">
import 'reflect-metadata'
import { Component, Prop, Vue } from 'vue-property-decorator'
import { Component, Prop, Vue, Watch } from 'vue-property-decorator'
import Spinner from '@/components/misc/Spinner.vue'
import Tooltip from '@/components/misc/Tooltip.vue'
Expand All @@ -157,6 +162,7 @@ import { MultisigWallet } from '@/js/wallets/MultisigWallet'
import { SingletonWallet } from '@/js/wallets/SingletonWallet'
import { WalletNameType, WalletType } from '@/js/wallets/types'
import { privateToPublic } from '@ethereumjs/util'
import CamBadge from '@/components/CamBadge.vue'
@Component({
components: {
Expand All @@ -167,6 +173,7 @@ import { privateToPublic } from '@ethereumjs/util'
Tooltip,
ExportKeys,
PrivateKey,
CamBadge,
},
})
export default class KeyRow extends Vue {
Expand Down Expand Up @@ -213,6 +220,11 @@ export default class KeyRow extends Vue {
return ['mnemonic', 'ledger'].includes(this.walletType)
}
hasPending(): boolean {
if (this.wallet.pendingTx) return true
return false
}
get mnemonicPhrase(): MnemonicPhrase | null {
if (this.walletType !== 'mnemonic') return null
let wallet = this.wallet as MnemonicWallet
Expand Down Expand Up @@ -278,6 +290,7 @@ export default class KeyRow extends Vue {
get wallets(): WalletType[] {
return this.$store.state.wallets
}
canRemove(): boolean {
if (this.wallet instanceof MultisigWallet) return true
else {
Expand Down
34 changes: 31 additions & 3 deletions src/components/wallet/manage/MyKeys.vue
Original file line number Diff line number Diff line change
Expand Up @@ -73,8 +73,12 @@ export default class MyKeys extends Vue {
return this.$store.getters['Accounts/account']
}
get getPendingTransaction() {
return this.$store.getters['Signavault/importedTransactions']
}
get inactiveWallets(): WalletType[] {
return this.wallets.filter((wallet) => wallet !== this.activeWallet)
return this.checkInactivePendingWallet()
}
get wallets(): WalletType[] {
Expand Down Expand Up @@ -154,17 +158,17 @@ export default class MyKeys extends Vue {
addAlias() {
this.isLoading = true
this.error = ''
setTimeout(async () => {
try {
const multisigAliases = this.multiSigAliases.map((alias) => 'P-' + alias)
const multisigWallets = await this.$store.dispatch('addWalletsMultisig', {
keys: multisigAliases,
})
await this.$store.dispatch('Signavault/updateImportedMultiSigTransaction')
if (!multisigWallets || multisigWallets.length === 0) {
this.error = 'No address intersection with signing wallets found!'
} else {
this.globalHelper().updateStore('updatePendingTxState', true)
this.globalHelper().dispatchNotification({
message: `Added ${multisigWallets.length} multisig ${multisigWallets.length > 1 ? 'wallets' : 'wallet'} from ${multisigAliases.length} multisig ${multisigAliases.length > 1 ? 'aliases' : 'alias'}`,
type: 'success',
Expand All @@ -182,6 +186,30 @@ export default class MyKeys extends Vue {
}
}, 200)
}
checkInactivePendingWallet() {
const pendingTxs = this.getPendingTransaction
const wallets = this.wallets.filter((wallet) => wallet !== this.activeWallet)
const assignPendingTx = (wallet: WalletType) => {
if (wallet.type === 'multisig') {
delete wallet.pendingTx
const matchingTx = pendingTxs.find(
(tx) => tx.tx.alias === wallet.getStaticAddress('P')
)
if (matchingTx) {
Object.assign(wallet, { pendingTx: matchingTx })
}
}
}
// Check active wallet
assignPendingTx(this.activeWallet)
// Check inactive wallets
wallets.forEach(assignPendingTx)
return wallets
}
}
</script>

Expand Down
2 changes: 1 addition & 1 deletion src/components/wallet/manage/mountKyesComponent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export const mountKyesComponent = (el: string, props: any) => {
return {
dispatchNotification: (params) => dispatchNotification(params),
dispatchSetNewName: () => dispatchSetNewName(),
updateStore: (params) => props.updateStore(params),
updateStore: (type, params) => props.updateStore(type, params),
setAccount: (params) => setAccount(params),
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/components/wallet/sidebar/mountAccountMenu.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ export const mountAccountMenu = (el: string, props: any) => {
setAccount: (acc) => setAccount(acc),
dispatchNotification: (params) => dispatchNotification(params),
dispatchSetNewName: () => dispatchSetNewName(),
updateStore: (params) => props.updateStore(params),
updateStore: (type, params) => props.updateStore(type, params),
}
}
},
Expand Down
1 change: 1 addition & 0 deletions src/js/wallets/WalletCore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ abstract class WalletCore {
name: string = ''
type?: WalletNameType
accountHash?: Buffer
pendingTx?: Object | undefined

utxoset: AVMUTXOSet
platformUtxoset: PlatformUTXOSet
Expand Down
62 changes: 61 additions & 1 deletion src/store/modules/signavault/signavault.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ const signavault_module: Module<SignavaultState, RootState> = {
namespaced: true,
state: {
transactions: [],
importedTransactions: [],
},
getters: {
transactions(state) {
Expand All @@ -16,6 +17,10 @@ const signavault_module: Module<SignavaultState, RootState> = {
transaction: (state) => (txID: string) => {
return state.transactions.find((t) => t.tx.id === txID)
},

importedTransactions(state) {
return state.importedTransactions
},
},
mutations: {
clear(state) {
Expand All @@ -24,9 +29,16 @@ const signavault_module: Module<SignavaultState, RootState> = {
setTx(state, newTx: MultisigTx[]) {
state.transactions = newTx
},

setImportedTx(state, newTx: MultisigTx[]) {
state.importedTransactions = newTx
},
clearImported(state) {
state.importedTransactions = []
},
},
actions: {
async updateTransaction({ commit, rootState, rootGetters }) {
async updateTransaction({ commit, dispatch, rootState, rootGetters }) {
const wallet = rootState.activeWallet
if (!wallet || !(wallet instanceof MultisigWallet)) return commit('clear')

Expand Down Expand Up @@ -54,10 +66,58 @@ const signavault_module: Module<SignavaultState, RootState> = {
})
)
)
await dispatch('updateImportedMultiSigTransaction')
} catch (e: any) {
return commit('clear')
}
},
async updateImportedMultiSigTransaction({ commit, rootState, rootGetters }) {
try {
const network = rootGetters['Network/selectedNetwork']
if (!network) return commit('clearImported')

const multisigWallets = rootState.wallets.filter(
(wallet) => wallet.type === 'multisig'
)

const allTxPromises = multisigWallets.map(async (wallet) => {
if (!(wallet instanceof MultisigWallet)) {
commit('clearImported')
return
}

const staticAddress = wallet.getStaticAddress('P')
const signingKeyPair = wallet.wallets[0]?.getStaticKeyPair()

if (!signingKeyPair) {
console.log('wallet returned undefined staticKeyPair')
commit('clearImported')
return
}

return await SignaVaultTx(staticAddress, signingKeyPair) // Get transactions for each wallet
})

const allTxResults = (await Promise.all(allTxPromises)).flat()

const multisigTxs = allTxResults
.map((mms, index) => {
const wallet = multisigWallets[index]
if (!mms || !(wallet instanceof MultisigWallet)) return []

return {
tx: mms,
state: wallet.getSignatureStatus(mms),
}
})
.filter((tx: any) => tx.length !== 0) // Filter out empty results

commit('setImportedTx', multisigTxs.flat())
} catch (e: any) {
console.error('Error fetching transactions:', e)
commit('clearImported')
}
},
},
}

Expand Down
Loading

0 comments on commit 1f1b738

Please sign in to comment.