384 lines
11 KiB
Vue
384 lines
11 KiB
Vue
<template>
|
|
<div
|
|
:class="{
|
|
'stake-component--variant1': props.variant === 1,
|
|
'stake-component--variant2': props.variant === 2,
|
|
'stake-component--variant3': props.variant === 3,
|
|
}"
|
|
>
|
|
<div class="mid-text text-center" v-if="props.variant === 2">
|
|
<slot name="headline">Staked</slot>
|
|
</div>
|
|
<div
|
|
class="connected-stake bloodline-border card"
|
|
:class="{ 'card--dense': dense, 'connected-stake--variant1': variant === 1 }"
|
|
@click="
|
|
(e) => {
|
|
e.preventDefault();
|
|
e.stopPropagation();
|
|
}
|
|
"
|
|
>
|
|
<div class="connected-stake-headline mid-mid-text">
|
|
<slot name="headline" v-if="variant !== 2">Staked</slot>
|
|
</div>
|
|
<div class="connected-stake-subheadline low-mid-text">
|
|
<slot name="subheadline"
|
|
>Stake for a 25% bonus on your sacrifice.<br />
|
|
Upper limit is your stake.</slot
|
|
>
|
|
</div>
|
|
<div class="connected-stake-body">
|
|
<slot name="body">
|
|
<token-name-price name="$BLOOD staked" :price="formatNumber(walletStore.staked)"></token-name-price>
|
|
<token-logo img="/assets/img/token/bloodline.png" :alt="'bloodline-token'"></token-logo>
|
|
<token-name-price :variant="true" class="stake-reward" name="Bonus" price="+25%"></token-name-price>
|
|
</slot>
|
|
</div>
|
|
<slot name="actions">
|
|
<div class="connected-stake-buttons" v-if="!stakeMenu">
|
|
<template v-if="!walletStore.connected">
|
|
<div class="mid-mid-text text-center" disabled>Please Connect Your Wallet</div>
|
|
</template>
|
|
<template v-else-if="walletStore.connected && !ableToUnstake">
|
|
<div class="btn btn-immortal mid-mid-text" disabled v-if="cycleStore.currentCycle === 1">
|
|
Stake
|
|
</div>
|
|
<div
|
|
class="btn btn-immortal mid-mid-text"
|
|
v-else-if="cycleStore.currentCycle > 1"
|
|
@click="openStake"
|
|
>
|
|
Stake
|
|
</div>
|
|
<div
|
|
v-if="(walletStore.memeToken?.staked === 0 && !stakeonly) || cycleStore.currentCycle === 1"
|
|
class="btn btn-immortal btn--disabled mid-mid-text"
|
|
>
|
|
Unstake
|
|
</div>
|
|
<div v-else-if="!stakeonly" class="btn btn-immortal mid-mid-text" @click="openUnstake">
|
|
Unstake
|
|
</div>
|
|
</template>
|
|
<template v-else-if="walletStore.connected && ableToUnstake">
|
|
<div
|
|
class="btn btn-immortal mid-mid-text text-center"
|
|
v-if="unstakeState === 0 && walletStore.orderedUnstakedAmount > 0n && ableToUnstake"
|
|
@click="unstake"
|
|
>
|
|
Claim Unstaked $BLOOD
|
|
</div>
|
|
<div class="btn btn--disabled mid-mid-text text-center" v-else-if="unstakeState === 1">
|
|
Sign Transaction
|
|
</div>
|
|
<div class="btn btn--disabled mid-mid-text text-center" v-else-if="unstakeState === 2">
|
|
<loading-component></loading-component>
|
|
</div>
|
|
</template>
|
|
</div>
|
|
<Transition name="smooth">
|
|
<stake-menu
|
|
v-model="tokenNumber"
|
|
@close="stakeMenu = false"
|
|
:stake="stake"
|
|
:amount="balanceOf"
|
|
v-if="stakeMenu & !unstakeMenu"
|
|
>
|
|
<template v-slot:body>
|
|
<div class="btn btn-immortal stake-button" disabled v-if="stateStake === 0">
|
|
Enter Amount
|
|
</div>
|
|
<div class="btn btn-immortal stake-button" v-else-if="stateStake === 1" @click="stakeToken">
|
|
Stake
|
|
</div>
|
|
<div class="btn btn-immortal stake-button" disabled v-if="stateStake === 2">
|
|
Sign Transaction
|
|
</div>
|
|
<div class="btn btn-immortal stake-button" disabled v-if="stateStake === 3">
|
|
<loading-component></loading-component>
|
|
</div>
|
|
<div
|
|
class="btn transparent small-text cancel-button text-center"
|
|
@click="stakeMenu = false"
|
|
>
|
|
Cancel
|
|
</div>
|
|
</template>
|
|
<template v-slot:message-end>
|
|
<div class="input-balance">Balance: {{ formatNumber(balanceOf) }}</div>
|
|
</template>
|
|
</stake-menu>
|
|
<div class="unstake-menu" v-else-if="stakeMenu & unstakeMenu">
|
|
<div class="low-mid-text text-center">
|
|
To prevent users from farming rewards you can claim your stake next cycle.
|
|
</div>
|
|
<div class="unstake-menu-actions">
|
|
<div class="btn btn-immortal stake-button" v-if="stateStake <= 1" @click="orderUnstake">
|
|
Unstake Next Cycle
|
|
</div>
|
|
<div class="btn btn--disabled mid-mid-text text-center" v-else-if="stateStake === 2">
|
|
Sign Transaction
|
|
</div>
|
|
<div class="btn btn--disabled mid-mid-text text-center" v-else-if="stateStake === 3">
|
|
<loading-component></loading-component>
|
|
</div>
|
|
|
|
<div
|
|
class="btn transparent small-text cancel-button text-center"
|
|
@click="stakeMenu = false"
|
|
>
|
|
Cancel
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</Transition>
|
|
<div class="connected-stake-first-round small-text text-center" v-if="cycleStore.currentCycle === 0">
|
|
No $BLOOD on the market. Staking is activated after the first cycle is finished.
|
|
</div>
|
|
<div
|
|
class="connected-stake-first-round small-text text-center"
|
|
v-if="walletStore.orderedUnstakedAmount > 0n && !ableToUnstake"
|
|
>
|
|
You can claim {{ formatNumber(walletStore.orderedUnstakedAmount) }} $BLOOD next cycle.
|
|
</div>
|
|
</slot>
|
|
<slot></slot>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup>
|
|
import { ref, useSlots, computed } from "vue";
|
|
import StakeMenu from "@/components/StakeMenu.vue";
|
|
import TokenNamePrice from "@/components/TokenNamePrice.vue";
|
|
import TokenLogo from "@/components/TokenLogo.vue";
|
|
import { waitForTransaction } from "@wagmi/core";
|
|
import LoadingComponent from "@/components/LoadingComponent.vue";
|
|
import { showSuccessToast } from "@/helper/toast.js";
|
|
|
|
import { useCycleStore } from "@/stores/cycles";
|
|
import { useRewardLockerStore } from "@/stores/rewardlocker";
|
|
import { useWalletStoreV2 } from "@/stores/walletV2";
|
|
import { useTokenStore } from "@/stores/tokens";
|
|
import { useToast } from "vue-toastification";
|
|
import { formatNumber } from "@/helper/helper.js";
|
|
|
|
const toast = useToast();
|
|
const walletStore = useWalletStoreV2();
|
|
const tokenStore = useTokenStore();
|
|
const rewardLockerStore = useRewardLockerStore();
|
|
const cycleStore = useCycleStore();
|
|
const slots = useSlots();
|
|
const props = defineProps({
|
|
stakeonly: {
|
|
type: Boolean,
|
|
required: false,
|
|
default: false,
|
|
},
|
|
variant: {
|
|
type: Number,
|
|
required: false,
|
|
default: null,
|
|
},
|
|
dense: {
|
|
type: Boolean,
|
|
required: false,
|
|
default: false,
|
|
},
|
|
});
|
|
|
|
const stakeMenu = ref(false);
|
|
const unstakeMenu = ref(false);
|
|
const stake = ref(null);
|
|
const tokenNumber = ref(null);
|
|
const loading = ref(false);
|
|
|
|
/**
|
|
* state 0 enter amount
|
|
* state 1 rdy to go
|
|
* state 2 signing
|
|
* state 3 loading
|
|
* state 4 staked
|
|
*/
|
|
const state = ref(0);
|
|
const unstakeState = ref(0);
|
|
|
|
function openStake() {
|
|
stake.value = true;
|
|
unstakeMenu.value = false;
|
|
stakeMenu.value = true;
|
|
}
|
|
|
|
function openUnstake() {
|
|
stake.value = false;
|
|
unstakeMenu.value = true;
|
|
stakeMenu.value = true;
|
|
}
|
|
|
|
async function unstake() {
|
|
try {
|
|
unstakeState.value = 1;
|
|
const hash = await rewardLockerStore.unstake();
|
|
unstakeState.value = 2;
|
|
const data = await waitForTransaction({
|
|
hash: hash,
|
|
});
|
|
var rewardData = data.logs.find((logObject) => {
|
|
return logObject.topics.find(
|
|
(topic) => topic === "0xb89343427f692590c388d6346a8e42ea497eb6682a04db1a53f77ea81771ca91"
|
|
);
|
|
});
|
|
console.log("rewardData", rewardData);
|
|
|
|
const outputClaim = BigInt(rewardData.topics[3]) / 10n ** tokenStore.memeToken.decimals;
|
|
showSuccessToast(formatNumber(outputClaim), "Success!", "You just unstaked");
|
|
await walletStore.loadWalletData();
|
|
} catch (error) {
|
|
console.error("unstake", error);
|
|
} finally {
|
|
unstakeState.value = 0;
|
|
}
|
|
}
|
|
|
|
async function orderUnstake() {
|
|
try {
|
|
state.value = 2;
|
|
var hash = await rewardLockerStore.orderUnstake();
|
|
state.value = 3;
|
|
const data = await waitForTransaction({
|
|
hash: hash,
|
|
});
|
|
state.value = 4;
|
|
var rewardData = data.logs.find((logObject) => {
|
|
return logObject.topics.find(
|
|
(topic) => topic === "0xf86340d97020c624010a208b733db95795281fbc45cb6e6a40d161f91fa3e4a0"
|
|
);
|
|
});
|
|
console.log("rewardData", rewardData);
|
|
|
|
const outputClaim = BigInt(rewardData.topics[3]) / 10n ** tokenStore.memeToken.decimals;
|
|
showSuccessToast(
|
|
formatNumber(outputClaim),
|
|
"Success!",
|
|
"You just unstaked",
|
|
"You can claim your stake next cycle."
|
|
);
|
|
stakeMenu.value = false;
|
|
} catch (error) {
|
|
console.error("orderUnstake", error);
|
|
} finally {
|
|
await walletStore.loadWalletData();
|
|
state.value = 0;
|
|
}
|
|
}
|
|
|
|
async function stakeToken() {
|
|
try {
|
|
console.log("stakeToken");
|
|
state.value = 2;
|
|
const hash = await rewardLockerStore.stakeBloodline(tokenNumber.value);
|
|
state.value = 3;
|
|
const data = await waitForTransaction({
|
|
hash: hash,
|
|
});
|
|
var rewardData = data.logs.find((logObject) => {
|
|
return logObject.topics.find(
|
|
(topic) => topic === "0xf496bf2b14b1d178412b6f7a745900105b49b38b315cfdfbfabad31a6f995c6f"
|
|
);
|
|
});
|
|
//
|
|
console.log("rewardData", rewardData);
|
|
|
|
const outputClaim = BigInt(rewardData.topics[3]) / 10n ** tokenStore.memeToken.decimals;
|
|
console.log("data", data);
|
|
state.value = 0;
|
|
showSuccessToast(
|
|
formatNumber(outputClaim),
|
|
"Success!",
|
|
"You just staked",
|
|
"Your next sacrifice will get an extra staking bonus as a reward."
|
|
);
|
|
await walletStore.loadWalletData();
|
|
stakeMenu.value = false;
|
|
} catch (error) {
|
|
console.error(error);
|
|
throw new Error(error);
|
|
} finally {
|
|
state.value = 0;
|
|
}
|
|
}
|
|
|
|
const ableToUnstake = computed(() => {
|
|
var cycleList = walletStore.memeToken?.orderedUnstakedCycles?.findIndex((obj) => obj.result > 0n);
|
|
console.log("cycleList", cycleList);
|
|
if (cycleList && cycleList > -1 && cycleList + 1 <= cycleStore.currentCycle) {
|
|
return true;
|
|
}
|
|
return false;
|
|
});
|
|
|
|
const balanceOf = computed(() => {
|
|
if (!walletStore.memeToken?.balanceOf) {
|
|
return 0n;
|
|
} else {
|
|
return walletStore.memeToken?.balanceOf / 10n ** tokenStore.memeToken.decimals;
|
|
}
|
|
});
|
|
|
|
const stateStake = computed(() => {
|
|
let returnState = 0;
|
|
if (state.value === 2) {
|
|
returnState = 2;
|
|
} else if (state.value === 3) {
|
|
returnState = 3;
|
|
} else if (tokenNumber.value !== null || tokenNumber.value !== "" || tokenNumber.value > 0) {
|
|
returnState = 1;
|
|
} else if (tokenNumber.value === null || tokenNumber.value === "" || tokenNumber.value === 0) {
|
|
returnState = 0;
|
|
}
|
|
return returnState;
|
|
});
|
|
</script>
|
|
|
|
<style lang="sass">
|
|
|
|
.stake-component--variant2
|
|
border-radius: 16px
|
|
background: var(--darkgrey, #202020)
|
|
display: flex
|
|
flex-direction: column
|
|
gap: 18px
|
|
padding: 8px
|
|
@media (min-width: 992px)
|
|
padding: 24px 48px
|
|
.unstake-menu
|
|
display: flex
|
|
flex-direction: column
|
|
gap: 16px
|
|
.unstake-menu-actions
|
|
display: flex
|
|
flex-direction: column
|
|
gap: 8px
|
|
|
|
.stake-component--variant3
|
|
.connected-stake
|
|
.connected-stake-headline
|
|
text-align: left
|
|
.connected-stake-body
|
|
.token-price-wrapper, .stake-reward
|
|
.token-name
|
|
font-size: 14px
|
|
.token-price
|
|
font-size: 24px
|
|
.connected-stake-buttons
|
|
display: flex
|
|
gap: 8px
|
|
.btn
|
|
font-size: 18px
|
|
.connected-stake-first-round
|
|
font-size: 14px
|
|
.connected-stake-claim-info
|
|
font-size: 14px
|
|
</style>
|