Skip to content

Commit

Permalink
Merge pull request #433 from chain4travel/claim-rewards
Browse files Browse the repository at this point in the history
Expired Deposit Rewards Handling
  • Loading branch information
Ysrbolles authored Sep 3, 2024
2 parents 1b2d14e + 8b5d4e5 commit 8cc41d2
Show file tree
Hide file tree
Showing 5 changed files with 385 additions and 33 deletions.
27 changes: 25 additions & 2 deletions src/components/CamOfferCard.vue
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,23 @@
</div>
</div>
</template>
<template v-else-if="isTreasuryRewards">
<div class="offer_detail">
<div class="offer_detail_left">
<p>
{{ $t('earn.rewards.pending_rewards.description') }}
</p>
</div>
<div class="offer_detail_right">
<div class="reward_row">
<label>{{ $t('earn.rewards.pending_rewards.pending_reward') }}:</label>
<p class="reward">
{{ cleanAvaxBN(treasuryRewards.amountToClaim) }} {{ nativeAssetSymbol }}
</p>
</div>
</div>
</div>
</template>
<slot></slot>
</CamCard>
</template>
Expand All @@ -113,7 +130,7 @@ import { cleanAvaxBN, formatDuration } from '@/helpers/helper'
import { WalletHelper } from '@/helpers/wallet_helper'
import AvaAsset from '@/js/AvaAsset'
import { WalletType } from '@/js/wallets/types'
import { PlatformRewardDeposit } from '@/store/modules/platform/types'
import { PlatformRewardDeposit, PlatformRewardTreasury } from '@/store/modules/platform/types'
import { MultisigTx as SignavaultTx } from '@/store/modules/signavault/types'
import { BN, Buffer } from '@c4tplatform/caminojs/dist'
import { ClaimTx, UnsignedTx } from '@c4tplatform/caminojs/dist/apis/platformvm'
Expand All @@ -126,9 +143,10 @@ import CamCard from './CamCard.vue'
})
export default class CamOfferCard extends Vue {
@Prop() readonly title!: string
@Prop() readonly type!: 'offer' | 'reward'
@Prop() readonly type!: 'offer' | 'reward' | 'treasuryRewards'
@Prop() readonly offer!: DepositOffer
@Prop() readonly reward!: PlatformRewardDeposit
@Prop() readonly treasuryRewards!: PlatformRewardTreasury
get isOffer() {
return this.type === 'offer'
Expand All @@ -138,6 +156,10 @@ export default class CamOfferCard extends Vue {
return this.type === 'reward'
}
get isTreasuryRewards() {
return this.type === 'treasuryRewards'
}
get activeWallet(): WalletType {
return this.$store.state.activeWallet
}
Expand Down Expand Up @@ -326,6 +348,7 @@ label {
display: grid;
grid-template-columns: 1fr 1fr;
grid-gap: 1rem;
height: 100%;
.offer_detail_left {
border-right: 2px solid var(--border-color);
}
Expand Down
320 changes: 320 additions & 0 deletions src/components/wallet/earn/TreasuryRewardCard.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,320 @@
<template>
<CamOfferCard
:title="$t('earn.rewards.pending_rewards.title')"
type="treasuryRewards"
:treasuryRewards="reward"
>
<div v-if="!isMultiSig" class="button_group">
<CamBtn variant="primary" @click="openModal" :disabled="isClaimDisabled">
{{ $t('earn.rewards.active_earning.claim') }}
</CamBtn>
</div>
<template v-else>
<div v-if="signatureStatus() === 2" class="button_group">
<CamBtn variant="primary" @click="openModal" :disabled="isClaimDisabled">
{{ $t('earn.rewards.active_earning.execute_claim') }}
</CamBtn>
<CamBtn variant="negative" @click="openAbortModal">
{{ $t('earn.rewards.active_earning.abort') }}
</CamBtn>
</div>
<div v-else-if="signatureStatus() === -1 && disclamer" class="button_group">
<CamBtn variant="primary" @click="openModal" :disabled="isClaimDisabled">
{{ $t('earn.rewards.active_earning.initiate_transaction') }}
</CamBtn>
<CamBtn variant="transparent" @click="disclamer = false">
{{ $t('earn.rewards.active_earning.cancel') }}
</CamBtn>
</div>
<div v-else-if="signatureStatus() === 1 && !alreadySigned()" class="button_group">
<CamBtn variant="transparent" @click="signMultisigTx" :disabled="alreadySigned()">
{{ $t('earn.rewards.active_earning.sign') }}
</CamBtn>
<CamBtn variant="negative" @click="openAbortModal">
{{ $t('earn.rewards.active_earning.abort') }}
</CamBtn>
</div>
<div v-else-if="signatureStatus() === 1 && alreadySigned()" class="button_group">
<CamBtn variant="transparent" @click="signMultisigTx" :disabled="alreadySigned()">
{{
$t('earn.rewards.active_earning.signed', {
nbSigners: numberOfSignatures,
threshold: threshold,
})
}}
</CamBtn>
<CamBtn variant="negative" @click="openAbortModal">
{{ $t('earn.rewards.active_earning.abort') }}
</CamBtn>
</div>
<div v-else class="button_group">
<CamBtn
variant="primary"
@click="disclamer = true"
:disabled="isClaimDisabled || disallowedClaim()"
>
{{ $t('earn.rewards.active_earning.claim') }}
</CamBtn>
</div>
</template>
<Alert v-if="disclamer" variant="warning" class="mt-2">
{{ $t('earn.rewards.active_earning.are_you_sure') }}
</Alert>
<ModalClaimDepositReward
ref="modal_claim_reward"
:amount="reward.amountToClaim"
:rewardOwner="reward.rewardOwner"
:canExecuteMultisigTx="canExecuteMultisigTx"
/>
<ModalAbortSigning
ref="modal_abort_signing"
:title="$t('earn.rewards.abort_modal.title')"
:modalText="$t('earn.rewards.abort_modal.message')"
@cancelTx="cancelMultisigTx"
/>
</CamOfferCard>
</template>
<script lang="ts">
import 'reflect-metadata'
import { Component, Prop, Vue, Watch } from 'vue-property-decorator'
import ModalClaimReward from '@/components/modals/ClaimRewardModal.vue'
import { cleanAvaxBN } from '@/helpers/helper'
import { PlatformRewardDeposit } from '@/store/modules/platform/types'
import { bintools } from '@/AVA'
import Alert from '@/components/Alert.vue'
import CamBtn from '@/components/CamBtn.vue'
import CamOfferCard from '@/components/CamOfferCard.vue'
import { WalletHelper } from '@/helpers/wallet_helper'
import { MultisigWallet } from '@/js/wallets/MultisigWallet'
import { WalletType } from '@/js/wallets/types'
import { MultisigTx as SignavaultTx } from '@/store/modules/signavault/types'
import { BN, Buffer } from '@c4tplatform/caminojs/dist'
import { ClaimTx, UnsignedTx } from '@c4tplatform/caminojs/dist/apis/platformvm'
import { DepositOffer } from '@c4tplatform/caminojs/dist/apis/platformvm/interfaces'
import { ModelMultisigTxOwner } from '@c4tplatform/signavaultjs'
import ModalAbortSigning from './ModalAbortSigning.vue'
import ModalClaimDepositReward from './ModalClaimDepositReward.vue'
@Component({
components: {
ModalClaimReward,
ModalClaimDepositReward,
ModalAbortSigning,
CamBtn,
Alert,
CamOfferCard,
},
})
export default class TreasuryRewardCard extends Vue {
now: number = Date.now()
intervalID: any = null
claimDisabled: boolean = true
disclamer: boolean = false
// @ts-ignore
helpers = this.globalHelper()
signedclaimedAmount: BN = new BN(0)
// signedDepositID: string = ''
@Prop() reward!: PlatformRewardDeposit
$refs!: {
// modal_claim_reward: ModalClaimReward
modal_claim_reward: ModalClaimDepositReward
modal_abort_signing: ModalAbortSigning
}
openAbortModal() {
this.$refs.modal_abort_signing.open()
}
updateNow() {
this.now = Date.now()
}
created() {
this.intervalID = setInterval(() => {
this.updateNow()
}, 2000)
}
destroyed() {
clearInterval(this.intervalID)
}
mounted() {
this.updateMultisigTxDetails()
}
get activeWallet(): WalletType {
return this.$store.state.activeWallet
}
get pendingSendMultisigTX(): SignavaultTx | undefined {
return this.$store.getters['Signavault/transactions'].find(
(item: any) =>
item?.tx?.alias === this.activeWallet.getStaticAddress('P') &&
WalletHelper.getUnsignedTxType(item?.tx?.unsignedTx) === 'ClaimTx'
)
}
async signMultisigTx() {
const wallet = this.activeWallet
if (!wallet || !(wallet instanceof MultisigWallet))
return console.debug('MultiSigTx::sign: Invalid wallet')
if (!this.pendingSendMultisigTX) return console.debug('MultiSigTx::sign: Invalid Tx')
try {
await wallet.addSignatures(this.pendingSendMultisigTX?.tx)
this.helpers.dispatchNotification({
message: this.$t('notifications.multisig_transaction_saved'),
type: 'success',
})
this.$store.dispatch('Signavault/updateTransaction')
} catch (e: any) {
this.helpers.dispatchNotification({
message: this.$t('multisig_transaction_not_saved'),
type: 'error',
})
this.disclamer = false
}
}
async cancelMultisigTx() {
try {
const wallet = this.activeWallet as MultisigWallet
if (this.pendingSendMultisigTX) {
// cancel from the wallet
await wallet.cancelExternal(this.pendingSendMultisigTX?.tx)
await this.$store.dispatch('Signavault/updateTransaction')
this.helpers.dispatchNotification({
message: this.$t('transfer.multisig.transaction_aborted'),
type: 'success',
})
}
} catch (err) {
console.log(err)
this.helpers.dispatchNotification({
message: this.$t('transfer.multisig.cancel_transaction_failed'),
type: 'error',
})
}
}
private async updateMultisigTxDetails() {
if (this.pendingSendMultisigTX) {
let unsignedTx = new UnsignedTx()
unsignedTx.fromBuffer(Buffer.from(this.pendingSendMultisigTX.tx?.unsignedTx, 'hex'))
const utx = unsignedTx.getTransaction() as ClaimTx
const claimAmounts = utx.getClaimAmounts()
const amount = claimAmounts[0].getAmount()
this.signedclaimedAmount = new BN(amount)
}
}
get numberOfSignatures(): number {
let signers = 0
this.txOwners().forEach((owner) => {
if (owner.signature) signers++
})
return signers
}
get threshold(): number {
return this.pendingSendMultisigTX?.tx?.threshold ?? 0
}
signedDepositID() {
const tx = this.pendingSendMultisigTX
if (!tx) return undefined
const unsignedTx = new UnsignedTx()
unsignedTx.fromBuffer(Buffer.from(tx.tx?.unsignedTx, 'hex'))
const utx = unsignedTx.getTransaction() as ClaimTx
const claimAmounts = utx.getClaimAmounts()
return bintools.cb58Encode(claimAmounts[0].getID())
}
txOwners(): ModelMultisigTxOwner[] | [] {
return this.pendingSendMultisigTX?.tx?.owners ?? []
}
signatureStatus(): number {
if (!this.pendingSendMultisigTX?.tx) return -1
else if (!this.canExecuteMultisigTx()) return 1
else if (this.canExecuteMultisigTx()) return 2
return -1
}
canExecuteMultisigTx(): boolean {
let signers = 0
let threshold = this.pendingSendMultisigTX?.tx?.threshold
const txOwners = this.txOwners()
txOwners.forEach((owner) => {
if (owner.signature) signers++
})
if (threshold) return signers >= threshold
return false
}
alreadySigned(): boolean {
const txOwners = this.txOwners()
if (!txOwners) return false
const walletAddresses = (this.activeWallet as MultisigWallet)?.wallets?.map(
(w) => w?.getAllAddressesP()?.[0]
)
if (!walletAddresses) return false
const isSigned = txOwners.some((owner) => {
if (!owner) return false
const isOwnerSigned = owner.signature && walletAddresses.includes(owner.address)
return isOwnerSigned
})
return isSigned
}
disallowedClaim(): boolean {
if (!this.pendingSendMultisigTX) return false
else {
if (!this.signedDepositID()) return false
else return true
}
}
get isMultiSig(): boolean {
let wallet: WalletType = this.$store.state.activeWallet
return wallet.type === 'multisig'
}
get isClaimDisabled() {
return this.reward.amountToClaim.isZero()
}
cleanAvaxBN(val: BN): string {
return cleanAvaxBN(val)
}
openModal() {
this.disclamer = false
this.$refs.modal_claim_reward.open()
}
}
</script>
<style scoped lang="scss">
@use '../../../styles/abstracts/mixins';
.mt-2 {
margin-top: 0.5rem;
}
.button_group {
display: flex;
margin-left: auto;
gap: 0.5rem;
justify-content: end;
margin-top: 0.6rem;
}
</style>
Loading

0 comments on commit 8cc41d2

Please sign in to comment.