harb/web-app/src/composables/useStake.ts
openhands 8c43d3890c fix: Move BigInt formatting functions from helper.ts to kraiken-lib/format (#246)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-24 23:00:58 +00:00

146 lines
4.7 KiB
TypeScript

import { ref, onMounted, reactive, computed } from 'vue';
import { type ComputedRef } from 'vue';
import { config } from '@/wagmi';
import { decodeEventLog, type Hex, type DecodeEventLogReturnType, type TypedDataDefinition } from 'viem';
import { getAccount, signTypedData, waitForTransactionReceipt, type Config } from '@wagmi/core';
import { HarbContract } from '@/contracts/harb';
import { StakeContract, permitAndSnatch, minStake } from '@/contracts/stake';
import { getNonce, nonce, getName } from '@/contracts/harb';
import { useWallet } from '@/composables/useWallet';
import { createPermitObject, getSignatureRSV } from '@/utils/blockchain';
import { weiToNumber, compactNumber } from 'kraiken-lib/format';
import { getTaxRateOptionByIndex } from '@/composables/useAdjustTaxRates';
import { useContractToast } from './useContractToast';
const wallet = useWallet();
const contractToast = useContractToast();
const wagmiConfig: Config = config;
enum StakeState {
NoBalance = 'NoBalance',
StakeAble = 'StakeAble',
SignTransaction = 'SignTransaction',
Waiting = 'Waiting',
NotEnoughApproval = 'NotEnoughApproval',
}
interface PositionCreatedArgs {
creationTime: number;
owner: Hex;
harbergDeposit: bigint;
positionId: bigint;
share: bigint;
taxRate: number;
}
// const state = ref<StakeState>(StakeState.NoBalance);
export function useStake() {
const stakingAmountRaw = ref();
const stakingAmountShares = ref();
const loading = ref(false);
const waiting = ref(false);
onMounted(async () => {});
const state: ComputedRef<StakeState> = computed(() => {
const balance = wallet.balance.value;
if (loading.value) {
return StakeState.SignTransaction;
} else if (minStake.value > balance || stakingAmount.value > balance) {
return StakeState.NoBalance;
} else if (waiting.value) {
return StakeState.Waiting;
} else {
return StakeState.StakeAble;
}
});
const stakingAmount = computed({
// getter
get() {
return stakingAmountRaw.value || minStake.value;
},
// setter
set(newValue) {
stakingAmountRaw.value = newValue;
},
});
const stakingAmountNumber = computed({
// getter
get() {
return weiToNumber(stakingAmount.value, 18);
},
// setter
set(newValue) {
stakingAmount.value = BigInt(newValue * 10 ** 18);
},
});
// const stakingAmountNumber = computed(() => return staking)
async function snatch(stakingAmount: bigint, taxRateIndex: number, positions: Array<bigint> = []) {
const account = getAccount(wagmiConfig);
const taxRateOption = getTaxRateOptionByIndex(taxRateIndex);
if (!taxRateOption) {
throw new Error(`Invalid tax rate index: ${taxRateIndex}`);
}
try {
const assets: bigint = stakingAmount;
// await snatchService(assets, receiver, taxRate, []);
// assets: BigInt, receiver: Address, taxRate: Number, positionsToSnatch: Array<BigInt>
const deadline = BigInt(Date.now()) / 1000n + 1200n;
const name = await getName();
const { types, message, domain, primaryType } = createPermitObject(
HarbContract.contractAddress,
account.address!,
StakeContract.contractAddress,
nonce.value,
deadline,
assets,
account.chainId!,
name
);
const typedData: TypedDataDefinition = {
domain,
message,
primaryType,
types,
};
const signature = await signTypedData(wagmiConfig, typedData);
const { r, s, v } = getSignatureRSV(signature);
loading.value = true;
const hash = await permitAndSnatch(assets, account.address!, taxRateOption.index, positions, deadline, v, r, s);
loading.value = false;
waiting.value = true;
const data = await waitForTransactionReceipt(wagmiConfig, {
hash: hash,
});
const topics = decodeEventLog({
abi: StakeContract.abi,
data: data.logs[3].data,
topics: data.logs[3].topics,
}) as DecodeEventLogReturnType & { args: PositionCreatedArgs };
const eventArgs: PositionCreatedArgs = topics.args;
const amount = compactNumber(weiToNumber(eventArgs.harbergDeposit, wallet.balance.decimals));
contractToast.showSuccessToast(amount, 'Success!', 'You Staked', 'Check your positions on the<br /> Staker Dashboard', '$KRK');
waiting.value = false;
await getNonce();
} catch (error) {
const message = error instanceof Error ? error.name : 'Transaction failed';
contractToast.showFailToast(message);
} finally {
loading.value = false;
waiting.value = false;
}
}
return reactive({ stakingAmount, stakingAmountShares, stakingAmountNumber, state, snatch });
}