73 Commits
Author SHA1 Message Date
EmberSpirit 7d1e7dcbf5 contract update 2023-10-24 06:31:01 +02:00
EmberSpirit cc3fb88d1e replace static 18n 2023-10-23 22:09:42 +02:00
EmberSpirit fcf6133a47 contract update 2023-10-23 22:00:09 +02:00
EmberSpirit 32db2d291c update bloodchart compact number 2023-10-23 21:58:54 +02:00
EmberSpirit 1b799b8825 Merge branch 'fix/simplifyUniswap' into development 2023-10-23 21:40:07 +02:00
EmberSpirit 99ff2cb166 merge pull request 2023-10-23 21:39:39 +02:00
EmberSpirit 6e58bc6319 update m issues + e frontend improvements 2023-10-23 21:35:38 +02:00
butterscotch 74dd5b7e0a sacrifice.js getRewards fixes 2023-10-23 20:45:24 +03:00
butterscotch bc3b7eac67 simplified uniswap.js 2023-10-23 01:01:34 +03:00
EmberSpirit 44df04cc23 fix issues e + new contracts 2023-10-22 21:37:15 +02:00
EmberSpirit bf76e55fb5 update m issues + digit change numbers 2023-10-22 17:14:00 +02:00
EmberSpirit fa4fa54033 bloodchart crown fix 2023-10-19 20:47:32 +02:00
EmberSpirit 167ad941bc update m issues + e issues 2023-10-19 20:30:27 +02:00
EmberSpirit cfaf527b95 bloodchart resize 2023-10-19 11:46:43 +02:00
EmberSpirit f45128ceb9 update visual fixes 2023-10-18 23:26:29 +02:00
EmberSpirit 32ababbb39 update bigint + smaller style issues fixes 2023-10-17 22:19:52 +02:00
EmberSpirit fedcd0314d Merge branch 'feat/sacrificeChoice' into development 2023-10-17 18:18:03 +02:00
EmberSpirit 9eabba9c11 merged pull request 2023-10-17 18:17:18 +02:00
EmberSpirit d25ef5ad63 bigint umpdate 2023-10-17 18:06:25 +02:00
butterscotch fe44a619d4 sacrifice: refactoring. 2023-10-16 22:05:00 +03:00
butterscotch 320cbb5c63 Quoter: define tokenIn and tokenOut, use ethBase as a param. 2023-10-16 22:04:16 +03:00
butterscotch 2d35457076 memeburner: use minETH and minBLOOD params in sacrifice functions. 2023-10-16 22:03:22 +03:00
butterscotch dad9fd4fe6 ConnectWallet: use variable instead of static value. 2023-10-16 22:02:22 +03:00
EmberSpirit d761adef18 fix user not logged in getrewardsFor & badget +/- fix 2023-10-16 17:31:44 +02:00
EmberSpirit 1fb59225e3 bloodsplash component fix 2023-10-16 13:54:24 +02:00
EmberSpirit b3191f493b blood splash 2023-10-16 13:52:19 +02:00
EmberSpirit 35f2f0782f stepper badge update + injected wallet + smaller fixes 2023-10-16 12:07:07 +02:00
EmberSpirit 301c569edc footer gap improve 2023-10-16 09:36:24 +02:00
EmberSpirit a34de54d60 update loading cycle + potential staking rewards 2023-10-12 23:04:35 +02:00
EmberSpirit 2b4405579e comments + contract update +
smaller design issues fix2
2023-10-12 20:05:22 +02:00
EmberSpirit b5c6f8af33 comments + contract update +
smaller design issues
2023-10-12 20:01:11 +02:00
EmberSpirit 68cd720c59 fill round update + notification update + visual fixes 2023-10-08 22:44:14 +02:00
EmberSpirit 5c7e176457 token-result 2023-10-08 12:17:57 +02:00
EmberSpirit 18d14f1478 updated contracts + install metamask if not installed 2023-10-08 11:22:17 +02:00
EmberSpirit 8d8423b1cb padding sacrifice-token 2023-10-08 10:00:52 +02:00
EmberSpirit 2965cbe065 Merge branch 'development' of http://gitea.loseyourip.com:4000/cindylouwho/ImmortalClanVue into development 2023-10-07 23:58:48 +02:00
EmberSpirit e33c59d621 update new images + update smaller fixes 2023-10-07 23:58:36 +02:00
EmberSpirit 2445bb1f78 update getRewardsFor function 2023-10-07 16:44:07 +02:00
EmberSpirit ea60d365d5 code clean up + claimcomponent value update# 2023-10-06 16:14:18 +02:00
EmberSpirit dd7a0a113d update desktop resize 2023-10-05 21:23:59 +02:00
EmberSpirit 2f712d41d6 update getresultfor 2 output params 2023-10-04 17:59:52 +02:00
EmberSpirit 64d46693ea toast rework + fix bugs 2023-10-04 17:20:21 +02:00
EmberSpirit 3d53d9e7c8 quoter update + desktop update 2023-09-27 20:20:06 +02:00
EmberSpirit 5c7053c0d9 update contracts+ desktop version 2023-09-24 11:38:12 +02:00
EmberSpirit 1b2ea9b2a2 update tokens + desktop version 2023-09-21 19:08:03 +02:00
EmberSpirit 9330168af2 update cycle 2023-09-17 17:16:09 +02:00
EmberSpirit 02182c8128 update slideoutpanel height 2023-09-14 22:23:24 +02:00
EmberSpirit ca243064f7 no bigint rounddata + cycle improvements 2023-09-14 22:07:51 +02:00
EmberSpirit 0ff38abfb4 fix firefox 2023-09-12 22:57:38 +02:00
EmberSpirit a0aafaddf0 update new contracts 2023-09-12 21:59:01 +02:00
EmberSpirit 44173a36e1 new coins + chart swiper 2023-09-08 23:56:44 +02:00
EmberSpirit dfd208e075 update profilepage 2023-09-08 23:05:34 +02:00
EmberSpirit cd773e16c9 update cycleview, pageview + profileview 2023-08-30 18:08:51 +02:00
EmberSpirit c8f7c7cd5e Merge branch 'master' into development 2023-08-16 20:16:26 +02:00
EmberSpirit 034cc10f06 cycleview 2023-08-16 20:16:13 +02:00
EmberSpirit 904df8ac7d merge development master 2023-08-14 18:57:02 +02:00
EmberSpirit 1925a2d8af Merge branch 'master' into development 2023-08-14 18:37:35 +02:00
EmberSpirit 23100d9a2a stakemenu 2023-08-14 18:37:11 +02:00
EmberSpirit 7d33f225ce update menu 2023-08-14 18:34:12 +02:00
EmberSpirit 641755201e cycle-view init 2023-08-13 21:11:47 +02:00
EmberSpirit a77cf3a668 update profile profile page 2023-08-13 20:57:02 +02:00
EmberSpirit ceac2a1083 update slideoutpanel, open errors tokeninit 2023-08-05 12:03:19 +02:00
EmberSpirit 6c4933a6a8 menu no scroll 2023-08-01 16:27:58 +02:00
Michel Fromme 2555217641 update mobile 2023-07-31 14:45:41 +02:00
Michel Fromme 259ddec9ec Merge branch 'development' 2023-07-28 12:23:48 +02:00
Michel Fromme c160b1c836 fix master repo 2023-07-28 12:23:17 +02:00
Michel Fromme 8ae8f9a64a Merge branch 'master' into development 2023-07-28 12:19:40 +02:00
Michel Fromme b7a54f2cdd images + update wagmi 2023-07-27 17:09:34 +02:00
Michel Fromme 650df134d2 contracts update 2023-07-27 15:34:07 +02:00
Michel Fromme 5157308745 contract changes init 2023-07-27 12:29:12 +02:00
Michel Fromme 0bab85fe75 walletv2 + connectwallet 2023-07-27 11:25:34 +02:00
Michel Fromme 34a445eaa3 slideoutpanel 2023-07-27 11:22:00 +02:00
Michel Fromme e200b82697 update 2023-07-27 11:19:57 +02:00
99 changed files with 11896 additions and 15483 deletions
-12
View File
@@ -1,15 +1,3 @@
# vue-ethereum2
This template should help get you started developing with Vue 3 in Vite.
## Recommended IDE Setup
[VSCode](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) (and disable Vetur) + [TypeScript Vue Plugin (Volar)](https://marketplace.visualstudio.com/items?itemName=Vue.vscode-typescript-vue-plugin).
## Customize configuration
See [Vite Configuration Reference](https://vitejs.dev/config/).
## Project Setup
```sh
+1
View File
@@ -8,6 +8,7 @@
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/assets/js/blockies.min.js"></script>
<script type="module" src="/src/main.js"></script>
</body>
</html>
+1561 -10189
View File
File diff suppressed because it is too large Load Diff
+5 -7
View File
@@ -14,21 +14,19 @@
"@fortawesome/free-solid-svg-icons": "^6.4.0",
"@fortawesome/vue-fontawesome": "^3.0.3",
"@wagmi/core": "^1.3.8",
"@walletconnect/ethereum-provider": "^2.9.1",
"@walletconnect/modal": "^2.6.0",
"@walletconnect/modal-sign-html": "^2.6.0",
"@web3modal/html": "^2.7.0",
"abi-decoder": "^2.4.0",
"ethers": "^6.6.3",
"blockies": "^0.0.2",
"pinia": "^2.0.36",
"pinia-plugin-persistedstate": "^3.1.0",
"sass": "^1.62.1",
"swiper": "^9.4.1",
"viem": "^1.4.1",
"vite-svg-loader": "^4.0.0",
"vue": "^3.3.2",
"vue-collapsed": "^1.2.8",
"vue-router": "^4.2.0",
"wagmi": "^1.3.9",
"web3": "^v1.9.0"
"vue-toastification": "^2.0.0-rc.5",
"vue3-lottie": "^3.2.0"
},
"devDependencies": {
"@esbuild-plugins/node-globals-polyfill": "^0.2.3",
Binary file not shown.

After

Width:  |  Height:  |  Size: 699 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 445 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 798 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 492 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 428 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.1 KiB

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 8.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 120 KiB

After

Width:  |  Height:  |  Size: 91 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 62 KiB

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 963 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

+238 -62
View File
@@ -1,50 +1,59 @@
<script setup>
import { onMounted, onUnmounted, provide, ref } from "vue";
import { onMounted, onUnmounted, provide, ref, watch } from "vue";
import { storeToRefs } from "pinia";
import { useRoute, useRouter } from "vue-router";
import Navbar from "./components/Navbar.vue";
import { useWalletStoreV2 } from "@/stores/walletV2";
const walletStore = useWalletStoreV2();
import { useTokenStore } from "@/stores/tokens";
import { useContractStore } from "@/stores/contracts";
import { useSacrificeStore } from "@/stores/sacrifice";
import { useMemeburnerStore } from "@/stores/memeburner";
import { useRewardLockerStore } from "@/stores/rewardlocker";
import { useMultiCallStore } from "@/stores/multicall";
import { useRoundsStore } from "@/stores/rounds";
import { useCycleStore } from "@/stores/cycles";
import SlideoutPanel from "./components/SlideoutPanel.vue";
import ConnectWallet from "./components/ConnectWallet.vue";
import BloodSplash from "./components/BloodSplash.vue";
import { getNetwork, fetchTransaction } from "@wagmi/core";
import { watchAccount, getPublicClient, getWalletClient } from "@wagmi/core";
import profileIcon from "@/assets/img/profile-icon.svg?component";
import cycleIcon from "@/assets/img/cycle-icon.svg?component";
import homeIcon from "@/assets/img/home-icon.svg?component";
const tokenStore = useTokenStore();
const contractStore = useContractStore();
const memeBurnerStore = useMemeburnerStore();
const rewardLockerStore = useRewardLockerStore();
const multiCallStore = useMultiCallStore();
const roundsStore = useRoundsStore();
const { memeBurner, token } = storeToRefs(tokenStore);
const { list } = storeToRefs(contractStore);
const isMobile = ref(false);
const showPanel = ref(false);
const eventWatch = ref(null);
const splashBlood = ref(0);
const router = useRouter();
const route = useRoute();
isMobile.value = isMobileFunc();
onUnmounted(() => {
window.removeEventListener("resize", handleWindowSizeChange);
eventWatch.value();
console.log("unsubscribe");
});
watch(showPanel, (newValue, oldValue) => {
console.log("document.body", document.body);
if (newValue) {
document.body.classList.add("sideoutpanel-open");
if (isMobile) {
document.body.classList.add("mobile");
}
} else {
document.body.classList.remove("sideoutpanel-open");
if (isMobile) {
document.body.classList.remove("mobile");
}
}
});
const handleWindowSizeChange = () => {
isMobile.value = isMobileFunc();
// your code
};
function showPanelTest(bla) {
console.log("bla", bla);
}
//to have mobile breakpoint not only on sass side
function isMobileFunc() {
if (screen.width <= 760) {
return true;
@@ -52,71 +61,238 @@ function isMobileFunc() {
return false;
}
}
function changeRoute(name) {
router.push({
name: name,
});
}
provide("isMobile", isMobile);
provide("showPanel", showPanel);
provide("splashBlood", splashBlood);
onMounted(async () => {
window.addEventListener("resize", handleWindowSizeChange);
handleWindowSizeChange();
// initContracts
await walletStore.init();
// await tokenStore.init();
// await memeBurnerStore.init();
// await rewardLockerStore.init();
// await memeBurnerStore.init();
// await multiCallStore.init();
//Memeburner Contract
//init
// roundsStore.currentRound = parseInt(
// await memeBurnerStore.getCurrentRound()
// );
// console.log("roundsStore.currentRound", roundsStore.currentRound);
// roundsStore.activeRound = roundsStore.currentRound;
// await roundsStore.fillRound(roundsStore.activeRound);
//events
eventWatch.value = watchAccount(async (account) => {
console.log("account123", account);
const publicClient = getPublicClient();
console.log("publicClient", publicClient);
var walletClient = await getWalletClient();
console.log("walletClient", walletClient);
if (account.address) {
walletStore.address = account.address;
walletStore.connected = true;
} else {
walletStore.address = null;
walletStore.connected = false;
console.log("beforeEach");
const memeBurnerStore = useMemeburnerStore();
const cycleStore = useCycleStore();
const walletStore = useWalletStoreV2();
walletStore.initialized = true;
console.log("init router");
//check if it is necessary
if (!cycleStore.currentCycle) {
cycleStore.currentCycle = parseInt(await memeBurnerStore.getCurrentCycle());
console.log("cycleStore.currentCycle", cycleStore.currentCycle);
cycleStore.activeCycle = cycleStore.currentCycle;
}
});
console.log("cycleStore.activeCycle", cycleStore.activeCycle);
await cycleStore.fillCycle(cycleStore.activeCycle);
});
</script>
<template>
<navbar @show-panel="((value) => showPanel = value)"/>
<navbar @show-panel="(value) => (showPanel = value)" />
<slideout-panel v-model="showPanel">
<connect-wallet></connect-wallet>
</slideout-panel>
<div class="main">
<div class="main" :class="{ 'no-scroll': showPanel, mobile: isMobile }">
<RouterView />
</div>
<blood-splash :key="splashBlood"></blood-splash>
<div class="footer">
<div class="footer-inner">
$BLOOD is 100%<br />
community owned.<br />
No team %, no pre-mine.
<div class="footer-headline" v-if="!isMobile">Join Bloodline</div>
<div class="footer-social-links">
<div class="social-bloodline-badge">
<div class="social-bloodline-badge-icon">
<font-awesome-icon icon="fa-brands fa-discord" />
</div>
</div>
<div class="social-bloodline-badge">
<div class="social-bloodline-badge-icon">
<font-awesome-icon icon="fa-brands fa-telegram" />
</div>
</div>
<div class="social-bloodline-badge">
<div class="social-bloodline-badge-icon">
<font-awesome-icon icon="fa-brands fa-twitter" />
</div>
</div>
<div class="social-bloodline-badge">
<div class="social-bloodline-badge-icon">
<font-awesome-icon icon="fa-solid fa-blog" />
</div>
</div>
</div>
</div>
</div>
<div class="mobile-navigation-bar" v-if="isMobile">
<div @click="changeRoute('home')" :class="{ active: route.name === 'home' }">
<!-- <font-awesome-icon icon="fa-droplet" /> -->
<!-- <img src="/assets/img/sacrifice-icon.png" alt="sacrifice-icon" /> -->
<homeIcon />
</div>
<div @click="changeRoute('cycle')" :class="{ active: route.name === 'cycle' }">
<!-- <font-awesome-icon icon="fa-moon" /> -->
<!-- <img src="/assets/img/cycle-icon.png" alt="cycle-icon" /> -->
<cycleIcon />
</div>
<div @click="changeRoute('profile')" :class="{ active: route.name === 'profile' }">
<!-- <img src="/assets/img/profile-icon.svg " alt="profile-icon" /> -->
<profileIcon />
<!-- <font-awesome-icon icon="fa-person" /> -->
</div>
</div>
</template>
<style lang="sass">
.footer
height: 450px
min-height: 450px
background-color: var(--grey2)
height: auto
background-color: #2D2D2D
padding-bottom: 72px
@media (min-width: 992px)
background-color: var(--midnight-black)
height: 150px
min-height: 150px
display: flex
flex-direction: column
justify-content: center
padding-bottom: unset
margin-top: auto
.footer-inner
padding: 24px
padding: 24px 0
font-size: 24px
display: flex
flex-direction: column
gap: 16px
align-items: center
border-top: 1px solid #000
@media (min-width: 992px)
padding: 16px 0 24px 0
justify-content: center
border-top: unset
background-color: transparent
.footer-headline
font-size: 16px
.footer-social-links
display: flex
gap: 24px
.social-bloodline-badge
border-radius: 14px
background: var(--grey, #858585)
display: flex
padding: 6px 20px
align-items: center
flex: 0 1 0
color: black
&:hover,&:active,&:focus
background-color: lighten( #858585, 10%)
cursor: pointer
.social-bloodline-badge-icon
font-size: 16px
.main
// padding-top: 24px
margin-top: 82px
padding: 24px 0
@media (min-width: 992px)
margin-top: 80px
padding: 80px 0
&.mobile
&.no-scroll
overflow: hidden
.mobile-navigation-bar
height: 72px
z-index: 1
width: 100%
padding: 16px 48px
border-radius: 16px 16px 0px 0px
box-shadow: 0px -4px 6px 0px rgba(0, 0, 0, 0.25)
background: var(--midnight-black, #0F0F0F)
bottom: -1px
position: fixed
display: flex
justify-content: space-around
align-items: center
div
font-size: 40px
cursor: pointer
-webkit-tap-highlight-color: transparent
&.active
svg
path
color: var(--purple)
fill: var(--purple)
.modal-overlay
background-color: rgb(15, 15, 15, 0.7)
height: 100vh
width: 100vw
position: fixed
left: 0
bottom: 0
z-index: 10
@media (min-width: 992px)
background-color: unset
.modal-card
border-radius: 16px
padding: 16px
width: 342px
text-align: center
position: absolute
top: 50%
left: 50%
transform: translate(-50%, -50%)
border: 2px solid var(--dark-purple, #4B0082)
background: var(--midnight-black, #0F0F0F)
z-index: 100
gap: 16px
@media (min-width: 992px)
top: 10%
right: 24px
left: unset
transform: unset
.body
display: flex
flex-direction: column
gap: 8px
.amount-number
display: flex
justify-content: center
align-items: end
gap: 8px
img
width: 74px
height: 74px
body::-webkit-scrollbar
width: 10px
body::-webkit-scrollbar-track
background: #202020
body::-webkit-scrollbar-thumb
background: grey
body:hover::-webkit-scrollbar-thumb
background: grey
.toast-header, .toast-body
font-size: 16px
.Vue-Toastification__container
&.bloodline-toast-container
&.top-right
@media (min-width: 992px)
top: 100px
</style>
@@ -1,6 +1,6 @@
{
"contractName": "MemeToken",
"contractAddress": "0x9dcD7Cd83ED0Fe69DDfE3c2A265a1207F2Bc3219",
"contractName": "Bloodline",
"contractAddress": "0x16351Cd1f3F1eb010758ff9FCf7013f48B0f5495",
"abi": [
{
"inputs": [
@@ -172,7 +172,13 @@
}
],
"name": "burn",
"outputs": [],
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "nonpayable",
"type": "function"
},
@@ -202,7 +208,7 @@
"type": "uint256"
}
],
"name": "mintMemeToken",
"name": "mintBloodline",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
+277 -327
View File
@@ -1,6 +1,6 @@
{
"contractName": "LiquidityOwner",
"contractAddress": "0x88E69D5CE691644F7cE151a2b085798194DAFEa1",
"contractAddress": "0x460f41499B6dA662ce289b57ba62A75FBd753b5c",
"abi": [
{
"inputs": [
@@ -11,7 +11,7 @@
},
{
"internalType": "address",
"name": "_memeToken",
"name": "_bloodline",
"type": "address"
},
{
@@ -21,22 +21,92 @@
},
{
"internalType": "address",
"name": "_nfPositionManager",
"name": "_memeAltar",
"type": "address"
}
],
"stateMutability": "nonpayable",
"type": "constructor"
},
{
"internalType": "address",
"name": "_memeBurner",
"type": "address"
"inputs": [],
"name": "CallbackCanBeCalledOnlyByPool",
"type": "error"
},
{
"inputs": [],
"name": "CurrentPriceDisallowsToProvide",
"type": "error"
},
{
"inputs": [],
"name": "NothingToProvide",
"type": "error"
},
{
"inputs": [],
"name": "OnlyMemeAltar",
"type": "error"
},
{
"inputs": [],
"name": "ProjectAlive",
"type": "error"
},
{
"inputs": [],
"name": "WrongSideOfPrice",
"type": "error"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "int24",
"name": "tickLower",
"type": "int24"
},
{
"indexed": true,
"internalType": "int24",
"name": "tickUpper",
"type": "int24"
},
{
"indexed": true,
"internalType": "uint256",
"name": "_chunk",
"name": "amountWETH",
"type": "uint256"
}
],
"stateMutability": "payable",
"type": "constructor"
"name": "LiquidityProvided",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "int24",
"name": "tickLower",
"type": "int24"
},
{
"indexed": true,
"internalType": "int24",
"name": "tickUpper",
"type": "int24"
},
{
"indexed": true,
"internalType": "uint256",
"name": "amountWETH",
"type": "uint256"
}
],
"name": "LiquidityShouldBeProvidedLater",
"type": "event"
},
{
"inputs": [
@@ -65,7 +135,10 @@
{
"inputs": [
{
"components": [
"internalType": "int24",
"name": "tick",
"type": "int24"
},
{
"internalType": "int24",
"name": "tickLower",
@@ -75,54 +148,17 @@
"internalType": "int24",
"name": "tickUpper",
"type": "int24"
},
{
"internalType": "uint128",
"name": "liquidity",
"type": "uint128"
},
{
"internalType": "uint80",
"name": "tokenId",
"type": "uint80"
}
],
"internalType": "struct LiquidityOwner.Position",
"name": "position",
"type": "tuple"
"name": "_liquidityCanBeProvided",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"name": "addETHPositionToLinkedList",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "int24",
"name": "_tickLower",
"type": "int24"
},
{
"internalType": "int24",
"name": "_tickUpper",
"type": "int24"
},
{
"internalType": "uint256",
"name": "amountMemeToken",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "amountWETH",
"type": "uint256"
}
],
"name": "addNewPosition",
"outputs": [],
"stateMutability": "nonpayable",
"stateMutability": "view",
"type": "function"
},
{
@@ -133,12 +169,17 @@
"type": "int48"
}
],
"name": "allRangesLinkedList",
"name": "_positions",
"outputs": [
{
"internalType": "int48",
"name": "",
"type": "int48"
"internalType": "uint112",
"name": "providedETH",
"type": "uint112"
},
{
"internalType": "uint112",
"name": "unprovidedETH",
"type": "uint112"
}
],
"stateMutability": "view",
@@ -146,129 +187,7 @@
},
{
"inputs": [],
"name": "burn",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "chunk",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256[]",
"name": "liquidityTokenIds",
"type": "uint256[]"
}
],
"name": "collectDeveloperFees",
"outputs": [
{
"internalType": "uint256",
"name": "amount0",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "amount1",
"type": "uint256"
}
],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "currentTokenIdToFill",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "tokenId",
"type": "uint256"
},
{
"internalType": "uint128",
"name": "liquidity",
"type": "uint128"
}
],
"name": "decreasePositionLiquidity",
"outputs": [
{
"internalType": "uint256",
"name": "amount0",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "amount1",
"type": "uint256"
}
],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "tokenId",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "amountWETH",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "amountMemeToken",
"type": "uint256"
}
],
"name": "increasePositionLiquidity",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "memeBurner",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "memeToken",
"name": "bloodline",
"outputs": [
{
"internalType": "address",
@@ -282,74 +201,22 @@
{
"inputs": [
{
"internalType": "uint256[]",
"name": "positionsToCancel",
"type": "uint256[]"
},
{
"internalType": "uint256",
"name": "amountOfWETHToUse",
"type": "uint256"
"internalType": "int24",
"name": "tickCycle",
"type": "int24"
}
],
"name": "movePriceUP",
"name": "calculateTicksForRange1",
"outputs": [
{
"internalType": "uint256",
"name": "amount0Collected",
"type": "uint256"
"internalType": "int24",
"name": "tickLower",
"type": "int24"
},
{
"internalType": "uint256",
"name": "amount1Collected",
"type": "uint256"
}
],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "nfPositionManager",
"outputs": [
{
"internalType": "contract INonfungiblePositionManager",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "",
"type": "address"
},
{
"internalType": "address",
"name": "",
"type": "address"
},
{
"internalType": "uint256",
"name": "",
"type": "uint256"
},
{
"internalType": "bytes",
"name": "",
"type": "bytes"
}
],
"name": "onERC721Received",
"outputs": [
{
"internalType": "bytes4",
"name": "",
"type": "bytes4"
"internalType": "int24",
"name": "tickUpper",
"type": "int24"
}
],
"stateMutability": "pure",
@@ -358,12 +225,12 @@
{
"inputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
"internalType": "int24",
"name": "tickCycle",
"type": "int24"
}
],
"name": "positions",
"name": "calculateTicksForRange2",
"outputs": [
{
"internalType": "int24",
@@ -374,35 +241,35 @@
"internalType": "int24",
"name": "tickUpper",
"type": "int24"
}
],
"stateMutability": "pure",
"type": "function"
},
{
"inputs": [
{
"internalType": "int24",
"name": "tickLower",
"type": "int24"
},
{
"internalType": "int24",
"name": "tickUpper",
"type": "int24"
}
],
"name": "collectPositionFees",
"outputs": [
{
"internalType": "uint128",
"name": "liquidity",
"name": "wethAmount",
"type": "uint128"
},
{
"internalType": "uint80",
"name": "tokenId",
"type": "uint80"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "bool",
"name": "round1",
"type": "bool"
}
],
"name": "provideLiquidity",
"outputs": [
{
"internalType": "uint256",
"name": "ethSpentOnGas",
"type": "uint256"
"internalType": "uint128",
"name": "bloodlineAmount",
"type": "uint128"
}
],
"stateMutability": "nonpayable",
@@ -410,31 +277,12 @@
},
{
"inputs": [],
"name": "rebalance",
"name": "collectedEthTotal",
"outputs": [
{
"internalType": "uint256",
"name": "tokenId",
"type": "uint256"
}
],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"internalType": "uint112",
"name": "",
"type": "uint256"
}
],
"name": "tokenIds",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
"type": "uint112"
}
],
"stateMutability": "view",
@@ -444,34 +292,24 @@
"inputs": [
{
"internalType": "uint256",
"name": "payForGas",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "memeAltarGasPrice",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "consumedGasByMemeAltar",
"name": "",
"type": "uint256"
}
],
"name": "triggeredByMemeAltar",
"name": "cycleTicks",
"outputs": [
{
"internalType": "bool",
"internalType": "int24",
"name": "",
"type": "bool"
"type": "int24"
}
],
"stateMutability": "nonpayable",
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "uniV3Pool",
"name": "memeAltar",
"outputs": [
{
"internalType": "address",
@@ -485,22 +323,145 @@
{
"inputs": [
{
"internalType": "int256",
"name": "amount0Delta",
"type": "int256"
"internalType": "uint256",
"name": "developerFee",
"type": "uint256"
}
],
"name": "payDeveloperFee",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"internalType": "int256",
"name": "amount1Delta",
"type": "int256"
"inputs": [
{
"internalType": "address",
"name": "uniswapPool",
"type": "address"
},
{
"internalType": "uint256",
"name": "extraAmount",
"type": "uint256"
}
],
"name": "payWETHToUniswapPool",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "pool",
"outputs": [
{
"internalType": "contract IUniswapV3Pool",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "previousBDLTotalSupply",
"outputs": [
{
"internalType": "uint128",
"name": "",
"type": "uint128"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint112",
"name": "collectedEthInCycle",
"type": "uint112"
}
],
"name": "provideLiquidity",
"outputs": [
{
"internalType": "uint256",
"name": "issuancePrice",
"type": "uint256"
}
],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "int24",
"name": "tickLower",
"type": "int24"
},
{
"internalType": "int24",
"name": "tickUpper",
"type": "int24"
}
],
"name": "provideUnprovidedLiquidity",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "int24",
"name": "tickLower",
"type": "int24"
},
{
"internalType": "int24",
"name": "tickUpper",
"type": "int24"
}
],
"name": "rageQuit",
"outputs": [
{
"internalType": "uint128",
"name": "wethAmount",
"type": "uint128"
},
{
"internalType": "uint128",
"name": "bloodlineAmount",
"type": "uint128"
}
],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "amount0Owed",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "amount1Owed",
"type": "uint256"
},
{
"internalType": "bytes",
"name": "_data",
"name": "",
"type": "bytes"
}
],
"name": "uniswapV3SwapCallback",
"name": "uniswapV3MintCallback",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
@@ -517,17 +478,6 @@
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "withdrawETH",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"stateMutability": "payable",
"type": "receive"
}
]
}
+368
View File
@@ -0,0 +1,368 @@
{
"contractName": "Meme",
"contractAddress": "0xC99B9d1693b71eF503c86B4cC05f141714176E5b",
"abi": [
{
"inputs": [
{
"internalType": "string",
"name": "name",
"type": "string"
},
{
"internalType": "string",
"name": "symbol",
"type": "string"
},
{
"internalType": "address",
"name": "_weth",
"type": "address"
},
{
"internalType": "address",
"name": "_uniV2Factory",
"type": "address"
}
],
"stateMutability": "payable",
"type": "constructor"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "owner",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "spender",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "amount",
"type": "uint256"
}
],
"name": "Approval",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "from",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "to",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "amount",
"type": "uint256"
}
],
"name": "Transfer",
"type": "event"
},
{
"inputs": [],
"name": "DOMAIN_SEPARATOR",
"outputs": [
{
"internalType": "bytes32",
"name": "",
"type": "bytes32"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "",
"type": "address"
},
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"name": "allowance",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "spender",
"type": "address"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
}
],
"name": "approve",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"name": "balanceOf",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
}
],
"name": "burn",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "decimals",
"outputs": [
{
"internalType": "uint8",
"name": "",
"type": "uint8"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
}
],
"name": "mint",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "name",
"outputs": [
{
"internalType": "string",
"name": "",
"type": "string"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"name": "nonces",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "owner",
"type": "address"
},
{
"internalType": "address",
"name": "spender",
"type": "address"
},
{
"internalType": "uint256",
"name": "value",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "deadline",
"type": "uint256"
},
{
"internalType": "uint8",
"name": "v",
"type": "uint8"
},
{
"internalType": "bytes32",
"name": "r",
"type": "bytes32"
},
{
"internalType": "bytes32",
"name": "s",
"type": "bytes32"
}
],
"name": "permit",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "symbol",
"outputs": [
{
"internalType": "string",
"name": "",
"type": "string"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "totalSupply",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "to",
"type": "address"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
}
],
"name": "transfer",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "from",
"type": "address"
},
{
"internalType": "address",
"name": "to",
"type": "address"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
}
],
"name": "transferFrom",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "uniV2Pool",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
}
]
}
+368
View File
@@ -0,0 +1,368 @@
{
"contractName": "Meme",
"contractAddress": "0xBCf48173f0767465Ef22fcDe2e1a099C8A5B4712",
"abi": [
{
"inputs": [
{
"internalType": "string",
"name": "name",
"type": "string"
},
{
"internalType": "string",
"name": "symbol",
"type": "string"
},
{
"internalType": "address",
"name": "_weth",
"type": "address"
},
{
"internalType": "address",
"name": "_uniV2Factory",
"type": "address"
}
],
"stateMutability": "payable",
"type": "constructor"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "owner",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "spender",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "amount",
"type": "uint256"
}
],
"name": "Approval",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "from",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "to",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "amount",
"type": "uint256"
}
],
"name": "Transfer",
"type": "event"
},
{
"inputs": [],
"name": "DOMAIN_SEPARATOR",
"outputs": [
{
"internalType": "bytes32",
"name": "",
"type": "bytes32"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "",
"type": "address"
},
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"name": "allowance",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "spender",
"type": "address"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
}
],
"name": "approve",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"name": "balanceOf",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
}
],
"name": "burn",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "decimals",
"outputs": [
{
"internalType": "uint8",
"name": "",
"type": "uint8"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
}
],
"name": "mint",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "name",
"outputs": [
{
"internalType": "string",
"name": "",
"type": "string"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"name": "nonces",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "owner",
"type": "address"
},
{
"internalType": "address",
"name": "spender",
"type": "address"
},
{
"internalType": "uint256",
"name": "value",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "deadline",
"type": "uint256"
},
{
"internalType": "uint8",
"name": "v",
"type": "uint8"
},
{
"internalType": "bytes32",
"name": "r",
"type": "bytes32"
},
{
"internalType": "bytes32",
"name": "s",
"type": "bytes32"
}
],
"name": "permit",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "symbol",
"outputs": [
{
"internalType": "string",
"name": "",
"type": "string"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "totalSupply",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "to",
"type": "address"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
}
],
"name": "transfer",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "from",
"type": "address"
},
{
"internalType": "address",
"name": "to",
"type": "address"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
}
],
"name": "transferFrom",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "uniV2Pool",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
}
]
}
+368
View File
@@ -0,0 +1,368 @@
{
"contractName": "Meme",
"contractAddress": "0xD563C6d061c5fc09eCf94c6Ce30CB400Ce2FD295",
"abi": [
{
"inputs": [
{
"internalType": "string",
"name": "name",
"type": "string"
},
{
"internalType": "string",
"name": "symbol",
"type": "string"
},
{
"internalType": "address",
"name": "_weth",
"type": "address"
},
{
"internalType": "address",
"name": "_uniV2Factory",
"type": "address"
}
],
"stateMutability": "payable",
"type": "constructor"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "owner",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "spender",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "amount",
"type": "uint256"
}
],
"name": "Approval",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "from",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "to",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "amount",
"type": "uint256"
}
],
"name": "Transfer",
"type": "event"
},
{
"inputs": [],
"name": "DOMAIN_SEPARATOR",
"outputs": [
{
"internalType": "bytes32",
"name": "",
"type": "bytes32"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "",
"type": "address"
},
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"name": "allowance",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "spender",
"type": "address"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
}
],
"name": "approve",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"name": "balanceOf",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
}
],
"name": "burn",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "decimals",
"outputs": [
{
"internalType": "uint8",
"name": "",
"type": "uint8"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
}
],
"name": "mint",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "name",
"outputs": [
{
"internalType": "string",
"name": "",
"type": "string"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"name": "nonces",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "owner",
"type": "address"
},
{
"internalType": "address",
"name": "spender",
"type": "address"
},
{
"internalType": "uint256",
"name": "value",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "deadline",
"type": "uint256"
},
{
"internalType": "uint8",
"name": "v",
"type": "uint8"
},
{
"internalType": "bytes32",
"name": "r",
"type": "bytes32"
},
{
"internalType": "bytes32",
"name": "s",
"type": "bytes32"
}
],
"name": "permit",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "symbol",
"outputs": [
{
"internalType": "string",
"name": "",
"type": "string"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "totalSupply",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "to",
"type": "address"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
}
],
"name": "transfer",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "from",
"type": "address"
},
{
"internalType": "address",
"name": "to",
"type": "address"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
}
],
"name": "transferFrom",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "uniV2Pool",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
}
]
}
@@ -1,6 +1,6 @@
{
"contractName": "MemeBurner",
"contractAddress": "0xc9cC73C414f122f85EfE20382EB753d29C5a0351",
"contractName": "MemeAltar",
"contractAddress": "0xAa72C9dB8332c28b4ebcC36D927e967EFC98D78C",
"abi": [
{
"inputs": [
@@ -19,11 +19,6 @@
"name": "_weth",
"type": "address"
},
{
"internalType": "address",
"name": "_developer",
"type": "address"
},
{
"internalType": "address",
"name": "_admin",
@@ -36,13 +31,13 @@
},
{
"internalType": "address",
"name": "_memeToken",
"name": "_bloodline",
"type": "address"
},
{
"internalType": "uint256[]",
"name": "roundGoals",
"type": "uint256[]"
"internalType": "uint112",
"name": "_defaultGoal",
"type": "uint112"
}
],
"stateMutability": "nonpayable",
@@ -55,7 +50,17 @@
},
{
"inputs": [],
"name": "Impossible",
"name": "CycleCompletedRegistrationFailed",
"type": "error"
},
{
"inputs": [],
"name": "GoalCannotBeZero",
"type": "error"
},
{
"inputs": [],
"name": "InsufficientOutputAmount",
"type": "error"
},
{
@@ -63,11 +68,6 @@
"name": "LiquidityOwnerAlreadyInitialized",
"type": "error"
},
{
"inputs": [],
"name": "LiquidityOwnerTriggerFailed",
"type": "error"
},
{
"inputs": [],
"name": "MemeIsNotInAList",
@@ -75,7 +75,17 @@
},
{
"inputs": [],
"name": "NextRoundRegistrationFailed",
"name": "NextCycleRegistrationFailed",
"type": "error"
},
{
"inputs": [],
"name": "NotAdmin",
"type": "error"
},
{
"inputs": [],
"name": "NotExactInput",
"type": "error"
},
{
@@ -90,7 +100,17 @@
},
{
"inputs": [],
"name": "RoundCompletedRegistrationFailed",
"name": "SwapCallbackCanBeCalledOnlyByPool",
"type": "error"
},
{
"inputs": [],
"name": "SwapWithinZeroLiquidity",
"type": "error"
},
{
"inputs": [],
"name": "SwitchRequiresMemeBeSet",
"type": "error"
},
{
@@ -98,6 +118,11 @@
"name": "TokenIsNotInSacrificableList",
"type": "error"
},
{
"inputs": [],
"name": "TooLittleReceived",
"type": "error"
},
{
"inputs": [
{
@@ -115,7 +140,7 @@
{
"indexed": true,
"internalType": "uint256",
"name": "roundNumber",
"name": "cycleNumber",
"type": "uint256"
},
{
@@ -140,7 +165,7 @@
{
"indexed": true,
"internalType": "uint256",
"name": "roundNumber",
"name": "cycleNumber",
"type": "uint256"
},
{
@@ -195,60 +220,21 @@
"anonymous": false,
"inputs": [
{
"components": [
{
"internalType": "uint8",
"name": "b1",
"type": "uint8"
},
{
"internalType": "uint8",
"name": "m1",
"type": "uint8"
},
{
"internalType": "uint8",
"name": "b2",
"type": "uint8"
},
{
"internalType": "uint8",
"name": "m2",
"type": "uint8"
},
{
"internalType": "uint8",
"name": "b3",
"type": "uint8"
},
{
"internalType": "uint8",
"name": "m4",
"type": "uint8"
}
],
"indexed": true,
"internalType": "struct MemeBurner.BM",
"name": "_bm",
"type": "tuple"
"internalType": "uint64",
"name": "b",
"type": "uint64"
},
{
"indexed": true,
"internalType": "uint64",
"name": "m",
"type": "uint64"
}
],
"name": "NewBM",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "uint256",
"name": "newDefaultGoal",
"type": "uint256"
}
],
"name": "NewDefaultRoundGoal",
"type": "event"
},
{
"anonymous": false,
"inputs": [
@@ -259,7 +245,20 @@
"type": "uint256"
}
],
"name": "NewRoundDurationLimit",
"name": "NewCycleDurationLimit",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "uint256",
"name": "newDefaultGoal",
"type": "uint256"
}
],
"name": "NewDefaultCycleGoal",
"type": "event"
},
{
@@ -289,41 +288,14 @@
{
"inputs": [
{
"components": [
{
"internalType": "uint8",
"name": "b1",
"type": "uint8"
"internalType": "uint64",
"name": "newB",
"type": "uint64"
},
{
"internalType": "uint8",
"name": "m1",
"type": "uint8"
},
{
"internalType": "uint8",
"name": "b2",
"type": "uint8"
},
{
"internalType": "uint8",
"name": "m2",
"type": "uint8"
},
{
"internalType": "uint8",
"name": "b3",
"type": "uint8"
},
{
"internalType": "uint8",
"name": "m4",
"type": "uint8"
}
],
"internalType": "struct MemeBurner.BM",
"name": "newBM",
"type": "tuple"
"internalType": "uint64",
"name": "newM",
"type": "uint64"
}
],
"name": "adjustBM",
@@ -340,12 +312,12 @@
{
"inputs": [
{
"internalType": "uint256",
"name": "newDefaultGoal",
"type": "uint256"
"internalType": "uint32",
"name": "newDurationLimit",
"type": "uint32"
}
],
"name": "adjustDefaultGoal",
"name": "adjustCycleDurationLimit",
"outputs": [
{
"internalType": "bool",
@@ -359,12 +331,12 @@
{
"inputs": [
{
"internalType": "uint256",
"name": "newDurationLimit",
"type": "uint256"
"internalType": "uint112",
"name": "newDefaultGoal",
"type": "uint112"
}
],
"name": "adjustRoundDurationLimit",
"name": "adjustDefaultGoal",
"outputs": [
{
"internalType": "bool",
@@ -390,37 +362,12 @@
},
{
"inputs": [],
"name": "bm",
"name": "b",
"outputs": [
{
"internalType": "uint8",
"name": "b1",
"type": "uint8"
},
{
"internalType": "uint8",
"name": "m1",
"type": "uint8"
},
{
"internalType": "uint8",
"name": "b2",
"type": "uint8"
},
{
"internalType": "uint8",
"name": "m2",
"type": "uint8"
},
{
"internalType": "uint8",
"name": "b3",
"type": "uint8"
},
{
"internalType": "uint8",
"name": "m4",
"type": "uint8"
"internalType": "uint64",
"name": "",
"type": "uint64"
}
],
"stateMutability": "view",
@@ -428,12 +375,67 @@
},
{
"inputs": [],
"name": "currentRound",
"name": "bloodline",
"outputs": [
{
"internalType": "uint256",
"internalType": "contract Bloodline",
"name": "",
"type": "uint256"
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "currentCycle",
"outputs": [
{
"internalType": "uint112",
"name": "",
"type": "uint112"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "cycleDurationLimit",
"outputs": [
{
"internalType": "uint32",
"name": "",
"type": "uint32"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint112",
"name": "",
"type": "uint112"
}
],
"name": "cycles",
"outputs": [
{
"internalType": "uint112",
"name": "goal",
"type": "uint112"
},
{
"internalType": "uint112",
"name": "ethUsedToBuy",
"type": "uint112"
},
{
"internalType": "uint32",
"name": "expirationTimestamp",
"type": "uint32"
}
],
"stateMutability": "view",
@@ -444,8 +446,42 @@
"name": "defaultGoal",
"outputs": [
{
"internalType": "uint256",
"internalType": "uint112",
"name": "",
"type": "uint112"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "memeToSacrifice",
"type": "address"
},
{
"internalType": "uint256",
"name": "amountToSacrifice",
"type": "uint256"
},
{
"internalType": "bool",
"name": "cycleParticipant",
"type": "bool"
}
],
"name": "getAmountETHBase",
"outputs": [
{
"internalType": "uint256",
"name": "amountETHBase",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "amountETHForSelling",
"type": "uint256"
}
],
@@ -474,12 +510,12 @@
{
"inputs": [
{
"internalType": "uint256",
"name": "roundNumber",
"type": "uint256"
"internalType": "uint112",
"name": "cycleNumber",
"type": "uint112"
}
],
"name": "getGoalInBLD",
"name": "getGoalInBLOOD",
"outputs": [
{
"internalType": "uint256",
@@ -503,11 +539,16 @@
"type": "uint256"
}
],
"name": "getRewardFor",
"name": "getRewardForSacrifice",
"outputs": [
{
"internalType": "uint256",
"name": "",
"name": "rewardCurrentCycle",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "rewardNextCycle",
"type": "uint256"
}
],
@@ -517,9 +558,9 @@
{
"inputs": [
{
"internalType": "uint256",
"name": "roundNumber",
"type": "uint256"
"internalType": "uint112",
"name": "cycleNumber",
"type": "uint112"
},
{
"internalType": "address",
@@ -543,6 +584,19 @@
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "issuancePrice",
"outputs": [
{
"internalType": "uint128",
"name": "",
"type": "uint128"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "liquidityOwner",
@@ -556,6 +610,19 @@
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "m",
"outputs": [
{
"internalType": "uint64",
"name": "",
"type": "uint64"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
@@ -626,41 +693,33 @@
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "roundDurationLimit",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"name": "rounds",
"outputs": [
{
"internalType": "uint256",
"name": "goal",
"type": "uint256"
"internalType": "address",
"name": "memeToSacrifice",
"type": "address"
},
{
"internalType": "uint256",
"name": "expirationTimestamp",
"name": "amountToSacrifice",
"type": "uint256"
},
{
"internalType": "uint112",
"name": "minETH",
"type": "uint112"
}
],
"stateMutability": "view",
"name": "sacrificeMeme",
"outputs": [
{
"internalType": "uint128",
"name": "reward",
"type": "uint128"
}
],
"stateMutability": "nonpayable",
"type": "function"
},
{
@@ -674,9 +733,14 @@
"internalType": "uint256",
"name": "amountToSacrifice",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "minBLOOD",
"type": "uint256"
}
],
"name": "sacrificeMeme",
"name": "sacrificeMemeAndBuyBLOOD",
"outputs": [
{
"internalType": "uint256",
@@ -719,6 +783,66 @@
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "meme",
"type": "address"
},
{
"internalType": "address",
"name": "newUniV2Pool",
"type": "address"
}
],
"name": "switchUniV2Pool",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "uniV3Pool",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "int256",
"name": "amount0Delta",
"type": "int256"
},
{
"internalType": "int256",
"name": "amount1Delta",
"type": "int256"
},
{
"internalType": "bytes",
"name": "_data",
"type": "bytes"
}
],
"name": "uniswapV3SwapCallback",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "weth",
+386
View File
@@ -0,0 +1,386 @@
{
"Meme1": {
"address": "0x4435ABC578136e2Eca50b5EFf950F17CAF42485b",
"uniV2Pool": "0xdD84B97DbA213e1aAdFEFD3de7067fC4Ab357378"
},
"Meme2": {
"address": "0xa0B7b2a78dF87eDc70736f7ED9D40d86c37B533F",
"uniV2Pool": "0xe9428ba55920DAB804153E9c4E8910EF1564a2b9"
},
"Meme3": {
"address": "0xC99B9d1693b71eF503c86B4cC05f141714176E5b",
"uniV2Pool": "0x905F0FA7F878eB8bd50782F9a4B739fb50394715"
},
"Meme4": {
"address": "0xBCf48173f0767465Ef22fcDe2e1a099C8A5B4712",
"uniV2Pool": "0x32Ba68Da1d5Df661181C8CA420b96925bFc748AA"
},
"Meme5": {
"address": "0xD563C6d061c5fc09eCf94c6Ce30CB400Ce2FD295",
"uniV2Pool": "0xf51E0b3804945d05eC20a4a1a2B0F7eD5BFf0068"
},
"abi": [
{
"inputs": [
{
"internalType": "string",
"name": "name",
"type": "string"
},
{
"internalType": "string",
"name": "symbol",
"type": "string"
},
{
"internalType": "address",
"name": "_weth",
"type": "address"
},
{
"internalType": "address",
"name": "_uniV2Factory",
"type": "address"
}
],
"stateMutability": "payable",
"type": "constructor"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "owner",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "spender",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "amount",
"type": "uint256"
}
],
"name": "Approval",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "from",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "to",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "amount",
"type": "uint256"
}
],
"name": "Transfer",
"type": "event"
},
{
"inputs": [],
"name": "DOMAIN_SEPARATOR",
"outputs": [
{
"internalType": "bytes32",
"name": "",
"type": "bytes32"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "",
"type": "address"
},
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"name": "allowance",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "spender",
"type": "address"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
}
],
"name": "approve",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"name": "balanceOf",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
}
],
"name": "burn",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "decimals",
"outputs": [
{
"internalType": "uint8",
"name": "",
"type": "uint8"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
}
],
"name": "mint",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "name",
"outputs": [
{
"internalType": "string",
"name": "",
"type": "string"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"name": "nonces",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "owner",
"type": "address"
},
{
"internalType": "address",
"name": "spender",
"type": "address"
},
{
"internalType": "uint256",
"name": "value",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "deadline",
"type": "uint256"
},
{
"internalType": "uint8",
"name": "v",
"type": "uint8"
},
{
"internalType": "bytes32",
"name": "r",
"type": "bytes32"
},
{
"internalType": "bytes32",
"name": "s",
"type": "bytes32"
}
],
"name": "permit",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "symbol",
"outputs": [
{
"internalType": "string",
"name": "",
"type": "string"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "totalSupply",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "to",
"type": "address"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
}
],
"name": "transfer",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "from",
"type": "address"
},
{
"internalType": "address",
"name": "to",
"type": "address"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
}
],
"name": "transferFrom",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "uniV2Pool",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
}
]
}
-444
View File
@@ -1,444 +0,0 @@
{
"contractName": "Multicall3",
"contractAddress": "0xcA11bde05977b3631167028862bE2a173976CA11",
"abi": [
{
"inputs": [
{
"components": [
{
"internalType": "address",
"name": "target",
"type": "address"
},
{
"internalType": "bytes",
"name": "callData",
"type": "bytes"
}
],
"internalType": "struct Multicall3.Call[]",
"name": "calls",
"type": "tuple[]"
}
],
"name": "aggregate",
"outputs": [
{
"internalType": "uint256",
"name": "blockNumber",
"type": "uint256"
},
{
"internalType": "bytes[]",
"name": "returnData",
"type": "bytes[]"
}
],
"stateMutability": "payable",
"type": "function"
},
{
"inputs": [
{
"components": [
{
"internalType": "address",
"name": "target",
"type": "address"
},
{
"internalType": "bool",
"name": "allowFailure",
"type": "bool"
},
{
"internalType": "bytes",
"name": "callData",
"type": "bytes"
}
],
"internalType": "struct Multicall3.Call3[]",
"name": "calls",
"type": "tuple[]"
}
],
"name": "aggregate3",
"outputs": [
{
"components": [
{
"internalType": "bool",
"name": "success",
"type": "bool"
},
{
"internalType": "bytes",
"name": "returnData",
"type": "bytes"
}
],
"internalType": "struct Multicall3.Result[]",
"name": "returnData",
"type": "tuple[]"
}
],
"stateMutability": "payable",
"type": "function"
},
{
"inputs": [
{
"components": [
{
"internalType": "address",
"name": "target",
"type": "address"
},
{
"internalType": "bool",
"name": "allowFailure",
"type": "bool"
},
{
"internalType": "uint256",
"name": "value",
"type": "uint256"
},
{
"internalType": "bytes",
"name": "callData",
"type": "bytes"
}
],
"internalType": "struct Multicall3.Call3Value[]",
"name": "calls",
"type": "tuple[]"
}
],
"name": "aggregate3Value",
"outputs": [
{
"components": [
{
"internalType": "bool",
"name": "success",
"type": "bool"
},
{
"internalType": "bytes",
"name": "returnData",
"type": "bytes"
}
],
"internalType": "struct Multicall3.Result[]",
"name": "returnData",
"type": "tuple[]"
}
],
"stateMutability": "payable",
"type": "function"
},
{
"inputs": [
{
"components": [
{
"internalType": "address",
"name": "target",
"type": "address"
},
{
"internalType": "bytes",
"name": "callData",
"type": "bytes"
}
],
"internalType": "struct Multicall3.Call[]",
"name": "calls",
"type": "tuple[]"
}
],
"name": "blockAndAggregate",
"outputs": [
{
"internalType": "uint256",
"name": "blockNumber",
"type": "uint256"
},
{
"internalType": "bytes32",
"name": "blockHash",
"type": "bytes32"
},
{
"components": [
{
"internalType": "bool",
"name": "success",
"type": "bool"
},
{
"internalType": "bytes",
"name": "returnData",
"type": "bytes"
}
],
"internalType": "struct Multicall3.Result[]",
"name": "returnData",
"type": "tuple[]"
}
],
"stateMutability": "payable",
"type": "function"
},
{
"inputs": [],
"name": "getBasefee",
"outputs": [
{
"internalType": "uint256",
"name": "basefee",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "blockNumber",
"type": "uint256"
}
],
"name": "getBlockHash",
"outputs": [
{
"internalType": "bytes32",
"name": "blockHash",
"type": "bytes32"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "getBlockNumber",
"outputs": [
{
"internalType": "uint256",
"name": "blockNumber",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "getChainId",
"outputs": [
{
"internalType": "uint256",
"name": "chainid",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "getCurrentBlockCoinbase",
"outputs": [
{
"internalType": "address",
"name": "coinbase",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "getCurrentBlockDifficulty",
"outputs": [
{
"internalType": "uint256",
"name": "difficulty",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "getCurrentBlockGasLimit",
"outputs": [
{
"internalType": "uint256",
"name": "gaslimit",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "getCurrentBlockTimestamp",
"outputs": [
{
"internalType": "uint256",
"name": "timestamp",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "addr",
"type": "address"
}
],
"name": "getEthBalance",
"outputs": [
{
"internalType": "uint256",
"name": "balance",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "getLastBlockHash",
"outputs": [
{
"internalType": "bytes32",
"name": "blockHash",
"type": "bytes32"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "bool",
"name": "requireSuccess",
"type": "bool"
},
{
"components": [
{
"internalType": "address",
"name": "target",
"type": "address"
},
{
"internalType": "bytes",
"name": "callData",
"type": "bytes"
}
],
"internalType": "struct Multicall3.Call[]",
"name": "calls",
"type": "tuple[]"
}
],
"name": "tryAggregate",
"outputs": [
{
"components": [
{
"internalType": "bool",
"name": "success",
"type": "bool"
},
{
"internalType": "bytes",
"name": "returnData",
"type": "bytes"
}
],
"internalType": "struct Multicall3.Result[]",
"name": "returnData",
"type": "tuple[]"
}
],
"stateMutability": "payable",
"type": "function"
},
{
"inputs": [
{
"internalType": "bool",
"name": "requireSuccess",
"type": "bool"
},
{
"components": [
{
"internalType": "address",
"name": "target",
"type": "address"
},
{
"internalType": "bytes",
"name": "callData",
"type": "bytes"
}
],
"internalType": "struct Multicall3.Call[]",
"name": "calls",
"type": "tuple[]"
}
],
"name": "tryBlockAndAggregate",
"outputs": [
{
"internalType": "uint256",
"name": "blockNumber",
"type": "uint256"
},
{
"internalType": "bytes32",
"name": "blockHash",
"type": "bytes32"
},
{
"components": [
{
"internalType": "bool",
"name": "success",
"type": "bool"
},
{
"internalType": "bytes",
"name": "returnData",
"type": "bytes"
}
],
"internalType": "struct Multicall3.Result[]",
"name": "returnData",
"type": "tuple[]"
}
],
"stateMutability": "payable",
"type": "function"
}
]
}
+197
View File
@@ -0,0 +1,197 @@
{
"contractName": "Quoter",
"contractAddress": "0xb27308f9F90D607463bb33eA1BeBb41C27CE5AB6",
"abi": [
{
"inputs": [
{
"internalType": "address",
"name": "_factory",
"type": "address"
},
{
"internalType": "address",
"name": "_WETH9",
"type": "address"
}
],
"stateMutability": "nonpayable",
"type": "constructor"
},
{
"inputs": [],
"name": "WETH9",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "factory",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "bytes",
"name": "path",
"type": "bytes"
},
{
"internalType": "uint256",
"name": "amountIn",
"type": "uint256"
}
],
"name": "quoteExactInput",
"outputs": [
{
"internalType": "uint256",
"name": "amountOut",
"type": "uint256"
}
],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "tokenIn",
"type": "address"
},
{
"internalType": "address",
"name": "tokenOut",
"type": "address"
},
{
"internalType": "uint24",
"name": "fee",
"type": "uint24"
},
{
"internalType": "uint256",
"name": "amountIn",
"type": "uint256"
},
{
"internalType": "uint160",
"name": "sqrtPriceLimitX96",
"type": "uint160"
}
],
"name": "quoteExactInputSingle",
"outputs": [
{
"internalType": "uint256",
"name": "amountOut",
"type": "uint256"
}
],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "bytes",
"name": "path",
"type": "bytes"
},
{
"internalType": "uint256",
"name": "amountOut",
"type": "uint256"
}
],
"name": "quoteExactOutput",
"outputs": [
{
"internalType": "uint256",
"name": "amountIn",
"type": "uint256"
}
],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "tokenIn",
"type": "address"
},
{
"internalType": "address",
"name": "tokenOut",
"type": "address"
},
{
"internalType": "uint24",
"name": "fee",
"type": "uint24"
},
{
"internalType": "uint256",
"name": "amountOut",
"type": "uint256"
},
{
"internalType": "uint160",
"name": "sqrtPriceLimitX96",
"type": "uint160"
}
],
"name": "quoteExactOutputSingle",
"outputs": [
{
"internalType": "uint256",
"name": "amountIn",
"type": "uint256"
}
],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "int256",
"name": "amount0Delta",
"type": "int256"
},
{
"internalType": "int256",
"name": "amount1Delta",
"type": "int256"
},
{
"internalType": "bytes",
"name": "path",
"type": "bytes"
}
],
"name": "uniswapV3SwapCallback",
"outputs": [],
"stateMutability": "view",
"type": "function"
}
]
}
+207 -197
View File
@@ -1,6 +1,6 @@
{
"contractName": "RewardLocker",
"contractAddress": "0x7C3D5a19878d550D0c6c2b0BFC884ef410F6e440",
"contractAddress": "0x8b15b2CB5b019472C31aEf487BF700037c321F85",
"abi": [
{
"inputs": [
@@ -15,17 +15,22 @@
},
{
"inputs": [],
"name": "MemeAltarAlreadyInitialized",
"name": "AlreadyInitialized",
"type": "error"
},
{
"inputs": [],
"name": "MemeTokenAlreadyInitialized",
"name": "CycleIsNotCompletedYet",
"type": "error"
},
{
"inputs": [],
"name": "RoundIsNotCompletedYet",
"name": "NotMemeAltar",
"type": "error"
},
{
"inputs": [],
"name": "StakePartMoreThan100Percent",
"type": "error"
},
{
@@ -57,6 +62,44 @@
"name": "ClaimedReward",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "uint256",
"name": "index",
"type": "uint256"
},
{
"indexed": true,
"internalType": "address",
"name": "winnerToken",
"type": "address"
},
{
"indexed": true,
"internalType": "uint256",
"name": "totalCycleRewards",
"type": "uint256"
}
],
"name": "CycleCompleted",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "uint256",
"name": "index",
"type": "uint256"
}
],
"name": "CycleStarted",
"type": "event"
},
{
"anonymous": false,
"inputs": [
@@ -69,7 +112,7 @@
{
"indexed": true,
"internalType": "uint256",
"name": "stakedRound",
"name": "stakedCycle",
"type": "uint256"
},
{
@@ -94,7 +137,7 @@
{
"indexed": true,
"internalType": "uint256",
"name": "unstakeRound",
"name": "unstakeCycle",
"type": "uint256"
},
{
@@ -119,7 +162,7 @@
{
"indexed": true,
"internalType": "uint256",
"name": "roundNumber",
"name": "cycleNumber",
"type": "uint256"
},
{
@@ -138,44 +181,6 @@
"name": "Rewarded",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "uint256",
"name": "index",
"type": "uint256"
},
{
"indexed": true,
"internalType": "address",
"name": "winnerToken",
"type": "address"
},
{
"indexed": true,
"internalType": "uint256",
"name": "totalRoundRewards",
"type": "uint256"
}
],
"name": "RoundCompleted",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "uint256",
"name": "index",
"type": "uint256"
}
],
"name": "RoundStarted",
"type": "event"
},
{
"anonymous": false,
"inputs": [
@@ -188,7 +193,7 @@
{
"indexed": true,
"internalType": "uint256",
"name": "unstakeRound",
"name": "unstakeCycle",
"type": "uint256"
},
{
@@ -201,11 +206,24 @@
"name": "UnstakeOrdered",
"type": "event"
},
{
"inputs": [],
"name": "bloodline",
"outputs": [
{
"internalType": "contract Bloodline",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256[]",
"name": "_rounds",
"name": "_cycles",
"type": "uint256[]"
},
{
@@ -229,7 +247,7 @@
"inputs": [
{
"internalType": "uint256[]",
"name": "_rounds",
"name": "_cycles",
"type": "uint256[]"
}
],
@@ -248,7 +266,7 @@
"inputs": [
{
"internalType": "uint256[]",
"name": "_rounds",
"name": "_cycles",
"type": "uint256[]"
},
{
@@ -272,7 +290,70 @@
"inputs": [
{
"internalType": "uint256",
"name": "roundNumber",
"name": "",
"type": "uint256"
}
],
"name": "cycles",
"outputs": [
{
"internalType": "uint32",
"name": "cycleCompletedTimestamp",
"type": "uint32"
},
{
"internalType": "uint224",
"name": "totalSacrificeCompetitionRewards",
"type": "uint224"
},
{
"internalType": "uint256",
"name": "totalStakeRewards",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "user",
"type": "address"
},
{
"internalType": "uint256",
"name": "cycleNumber",
"type": "uint256"
},
{
"internalType": "address",
"name": "sacrificedToken",
"type": "address"
}
],
"name": "getRewards",
"outputs": [
{
"internalType": "uint256",
"name": "stakeReward",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "sacrificeReward",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "cycleNumber",
"type": "uint256"
}
],
@@ -291,7 +372,7 @@
"inputs": [
{
"internalType": "uint256",
"name": "roundNumber",
"name": "cycleNumber",
"type": "uint256"
},
{
@@ -314,26 +395,26 @@
{
"inputs": [
{
"internalType": "uint256",
"name": "roundNumber",
"type": "uint256"
"internalType": "address",
"name": "user",
"type": "address"
},
{
"internalType": "address",
"name": "sacrificedToken",
"type": "address"
}
],
"name": "getSacrificedTokenTotalRewards",
"outputs": [
{
"internalType": "uint256",
"name": "totalDefaultRewardsForToken",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "totalRewardsForToken",
"name": "reward",
"type": "uint256"
}
],
"name": "getStakeRewardForSacrificeReward",
"outputs": [
{
"internalType": "uint256",
"name": "stakeReward",
"type": "uint256"
}
],
@@ -349,7 +430,7 @@
},
{
"internalType": "uint256[]",
"name": "roundNumbers",
"name": "cycleNumbers",
"type": "uint256[]"
}
],
@@ -357,7 +438,36 @@
"outputs": [
{
"internalType": "uint256",
"name": "totalRewardsAmount",
"name": "totalSacrificeRewards",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "totalStakeRewards",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "cycleNumber",
"type": "uint256"
},
{
"internalType": "address",
"name": "sacrificedToken",
"type": "address"
}
],
"name": "getTotalSacrificeRewardsForToken",
"outputs": [
{
"internalType": "uint256",
"name": "totalSacrificeRewardsForToken",
"type": "uint256"
}
],
@@ -373,7 +483,7 @@
},
{
"internalType": "address",
"name": "_memeToken",
"name": "_bloodline",
"type": "address"
}
],
@@ -384,7 +494,7 @@
},
{
"inputs": [],
"name": "lastCompletedRound",
"name": "lastCompletedCycle",
"outputs": [
{
"internalType": "uint256",
@@ -408,26 +518,13 @@
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "memeToken",
"outputs": [
{
"internalType": "contract MemeToken",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "orderUnstake",
"outputs": [
{
"internalType": "uint256",
"name": "unstakeRound",
"name": "unstakeCycle",
"type": "uint256"
}
],
@@ -438,7 +535,31 @@
"inputs": [
{
"internalType": "uint256",
"name": "roundIndex",
"name": "cycleIndex",
"type": "uint256"
},
{
"internalType": "address",
"name": "winnerToken",
"type": "address"
}
],
"name": "registerCycleCompleted",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "cycleIndex",
"type": "uint256"
},
{
@@ -447,7 +568,7 @@
"type": "address[]"
}
],
"name": "registerNextRound",
"name": "registerNextCycle",
"outputs": [
{
"internalType": "bool",
@@ -487,117 +608,6 @@
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "user",
"type": "address"
},
{
"internalType": "address",
"name": "_sacrificedToken",
"type": "address"
},
{
"internalType": "uint256",
"name": "reward",
"type": "uint256"
}
],
"name": "registerRewardNextRound",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "roundIndex",
"type": "uint256"
},
{
"internalType": "address",
"name": "winnerToken",
"type": "address"
}
],
"name": "registerRoundCompleted",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "",
"type": "address"
},
{
"internalType": "uint256",
"name": "",
"type": "uint256"
},
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"name": "rewards",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"name": "rounds",
"outputs": [
{
"internalType": "uint256",
"name": "roundCompletedTimestamp",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "totalDefaultRewards",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "totalRewards",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
@@ -607,7 +617,7 @@
},
{
"internalType": "uint256[]",
"name": "_rounds",
"name": "_cycles",
"type": "uint256[]"
},
{
@@ -675,7 +685,7 @@
"inputs": [
{
"internalType": "uint256[]",
"name": "_rounds",
"name": "_cycles",
"type": "uint256[]"
},
{
@@ -737,7 +747,7 @@
"inputs": [
{
"internalType": "uint256",
"name": "unstakeRound",
"name": "unstakeCycle",
"type": "uint256"
}
],
File diff suppressed because one or more lines are too long
+5
View File
@@ -0,0 +1,5 @@
{
"contractName": "WETH",
"contractAddress": "0xB4FBF271143F4FBf7B91A5ded31805e42b2208d6",
"contractAddressMainnet": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
}
+1
View File
@@ -0,0 +1 @@
[{"inputs":[{"internalType":"address","name":"meme","type":"address"},{"internalType":"address","name":"uniV2Pool","type":"address"}],"name":"addMemeToList","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint40","name":"b1","type":"uint40"},{"internalType":"uint40","name":"m1","type":"uint40"},{"internalType":"uint40","name":"b2","type":"uint40"},{"internalType":"uint40","name":"m2","type":"uint40"},{"internalType":"uint40","name":"b3","type":"uint40"},{"internalType":"uint40","name":"m4","type":"uint40"}],"internalType":"struct MemeAltar.BM","name":"newBM","type":"tuple"}],"name":"adjustBM","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint112","name":"newDefaultGoal","type":"uint112"}],"name":"adjustDefaultGoal","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"newDurationLimit","type":"uint32"}],"name":"adjustRoundDurationLimit","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newAdmin","type":"address"}],"name":"switchAdmin","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"meme","type":"address"},{"internalType":"address","name":"newUniV2Pool","type":"address"}],"name":"switchUniV2Pool","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"meme","type":"address"}],"name":"removeMemeFromList","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"}]
+3
View File
@@ -0,0 +1,3 @@
<svg width="40" height="40" viewBox="0 0 40 40" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M12.5332 0.223612C14.5688 -0.68935 16.3324 1.37298 15.6956 3.16362C13.5347 9.2395 14.8624 16.1404 19.3476 20.6276C23.8556 25.1377 30.7963 26.4633 36.8868 24.2619C38.659 23.6213 40.6637 25.369 39.7876 27.3579C39.7616 27.4167 39.7355 27.4752 39.7091 27.534C38.1498 30.9948 35.6553 34.2494 32.4281 36.4315C28.9883 38.7574 24.9319 40 20.7803 40H20.7783C15.9506 39.9948 11.2749 38.3095 7.5529 35.2332C3.83085 32.1569 1.2942 27.8809 0.377993 23.1382C-0.538209 18.3955 0.22314 13.4818 2.53147 9.23928C4.71976 5.21736 8.39949 2.09189 12.4733 0.250546L12.5332 0.223612Z" fill="#F9F9FA"/>
</svg>

After

Width:  |  Height:  |  Size: 731 B

+3
View File
@@ -0,0 +1,3 @@
<svg width="30" height="40" viewBox="0 0 30 40" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M16.4808 0.762253C16.1401 0.28454 15.5867 0 14.9994 0C14.4107 0 13.8586 0.283234 13.5153 0.762253C9.85024 5.87744 0.667969 19.3317 0.667969 25.6686C0.667969 33.5835 7.08316 40 14.9981 40C22.9143 40 29.3308 33.5835 29.3308 25.6686C29.3321 19.3317 20.1459 5.87744 16.4808 0.762253Z" fill="#F9F9FA"/>
</svg>

After

Width:  |  Height:  |  Size: 410 B

+12
View File
@@ -0,0 +1,12 @@
<svg width="40" height="40" viewBox="0 0 40 40" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_1478_31440)">
<path fill-rule="evenodd" clip-rule="evenodd" d="M11.8333 12C11.8333 7.58797 15.498 7.6 19.9997 7.6C24.5035 7.6 28.1661 7.58797 28.1661 12C28.1661 16.412 24.5035 20 19.9997 20C15.498 20 11.8333 16.412 11.8333 12ZM39.9114 35.2719C38.4271 28.5539 33.7845 23.5959 27.674 21.3459C30.912 18.7919 32.8005 14.6619 32.1063 10.1399C31.302 4.89386 26.8472 0.695954 21.4697 0.0839537C14.0464 -0.762046 7.75014 4.89797 7.75014 12C7.75014 15.78 9.53858 19.1479 12.3274 21.3459C6.21487 23.5959 1.57433 28.5539 0.088048 35.2719C-0.450933 37.7139 1.558 40 4.10795 40H35.8915C38.4434 40 40.4524 37.7139 39.9114 35.2719Z" fill="#F9F9FA"/>
<path d="M17.2809 18.8008L16.4813 16.4008L15.2025 15.2008L19.3594 15.2008L18.0813 16.4008L17.2809 18.8008Z" fill="#F9F9FA"/>
<path d="M23.359 18.8008L22.5594 16.4008L21.2806 15.2008L25.4375 15.2008L24.1594 16.4008L23.359 18.8008Z" fill="#F9F9FA"/>
</g>
<defs>
<clipPath id="clip0_1478_31440">
<rect width="40" height="40" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

+1
View File
@@ -0,0 +1 @@
!function(){function e(e){for(var o=0;o<c.length;o++)c[o]=0;for(var o=0;o<e.length;o++)c[o%4]=(c[o%4]<<5)-c[o%4]+e.charCodeAt(o)}function o(){var e=c[0]^c[0]<<11;return c[0]=c[1],c[1]=c[2],c[2]=c[3],c[3]=c[3]^c[3]>>19^e^e>>8,(c[3]>>>0)/(1<<31>>>0)}function r(){var e=Math.floor(360*o()),r=60*o()+40+"%",t=25*(o()+o()+o()+o())+"%",l="hsl("+e+","+r+","+t+")";return l}function t(e){for(var r=e,t=e,l=Math.ceil(r/2),n=r-l,a=[],c=0;t>c;c++){for(var i=[],f=0;l>f;f++)i[f]=Math.floor(2.3*o());var s=i.slice(0,n);s.reverse(),i=i.concat(s);for(var h=0;h<i.length;h++)a.push(i[h])}return a}function l(o){var t={};return t.seed=o.seed||Math.floor(Math.random()*Math.pow(10,16)).toString(16),e(t.seed),t.size=o.size||8,t.scale=o.scale||4,t.color=o.color||r(),t.bgcolor=o.bgcolor||r(),t.spotcolor=o.spotcolor||r(),t}function n(e,o){var r=t(e.size),l=Math.sqrt(r.length);o.width=o.height=e.size*e.scale;var n=o.getContext("2d");n.fillStyle=e.bgcolor,n.fillRect(0,0,o.width,o.height),n.fillStyle=e.color;for(var a=0;a<r.length;a++)if(r[a]){var c=Math.floor(a/l),i=a%l;n.fillStyle=1==r[a]?e.color:e.spotcolor,n.fillRect(i*e.scale,c*e.scale,e.scale,e.scale)}return o}function a(e){var e=l(e||{}),o=document.createElement("canvas");return n(e,o),o}var c=new Array(4),i={create:a,render:n};"undefined"!=typeof module&&(module.exports=i),"undefined"!=typeof window&&(window.blockies=i)}();
File diff suppressed because one or more lines are too long
+13 -30
View File
@@ -1,51 +1,34 @@
.bloodline-devider
font-size: 42px
text-align: center
margin: 16px 0
@media (min-width: 992px)
margin: 24px 0
.bloodline-border
padding: 16px
padding: 12px
border-radius: 16px
border: 2px solid #000
&.bloodline-border--variant1
border: 4px solid var(--midnight-black)
border: 3px solid var(--midnight-black)
&.bloodline-border__thin
border-width: 1px
@media (min-width: 992px)
padding: 24px 32px
border: 4px solid #000
padding: 18px 24px
border: 3px solid #000
&.purple
border-color: var(--purple)
&.white
border-color: var(--white)
&.grey
border-color: var(--grey, #858585)
.bloodline-badge
padding: 8px 16px 8px 16px
padding: 6px 12px 6px 12px
border-radius: 14px
background-color: #0F0F0F
display: flex
.bloodline-badge-icon
margin-right: 8px
.card
display: block
overflow: hidden
overflow-wrap: break-word
position: relative
padding: 0
text-decoration: none
transition-duration: .28s
transition-property: box-shadow,opacity,background
transition-timing-function: cubic-bezier(.4,0,.2,1)
z-index: 0
border-color: rgba(var(--v-border-color),var(--v-border-opacity))
border-style: solid
border-width: 0
border-radius: 16px
box-shadow: 0 2px 1px -1px rgba(0, 0, 0, .2),0 1px 1px 0rgba(0, 0, 0, .14),0 1px 3px 0 rgba(0, 0, 0, .12)
background-color: $darkgrey
@media (min-width: 992px)
border-radius: 4px
&.card--variant1
border-radius: 0
&.grey
background-color: var(--grey)
.bloodline-token
height: 50px
+18 -10
View File
@@ -1,17 +1,25 @@
.btn
&.btn-immortal
background-color: $purple
color: $button-color
font-size: 24px
padding: 16px 24px
gap: 8px
border-radius: 14px
border: none
display: block
width: 100%
text-decoration: none
&:hover,&:focus,&:active
cursor: pointer
&[disabled], &.btn--disabled
background-color: darken($purple, 10%)
cursor: not-allowed
&.black
background-color: var(--midnight-black)
&.btn-immortal
background-color: $purple
color: $button-color
&[disabled], &.btn--disabled
background-color: darken($purple, 10%)
cursor: not-allowed
color: var(--white-dark)
&:hover,&:focus,&:active
background-color: darken($purple, 10%),
cursor: pointer
&.btn--disabled
background-color: #151515
color: #808080
cursor: not-allowed
+14 -11
View File
@@ -17,15 +17,15 @@ body
background-color: #2D2D2D
color: $white
font-family: 'Inter', sans-serif
&.sideoutpanel-open
&:not(.mobile)
overflow-y: hidden
padding-right: 10px
.navbar
padding-right: 10px
.main
padding-top: 120px
@media (min-width: 992px)
padding-top: 208px
html
font-size: var(--font-size-main)
html, body, #app
height: 100%
body
margin: 0
@@ -33,16 +33,19 @@ body
#app
display: flex
flex-direction: column
.footer
margin-top: auto
height: 100vh
.container
margin-right: auto
margin-left: auto
padding-right: 16px
padding-left: 16px
// &.container--variant1
// @media (min-width: 992px)
// max-width: 800px
// padding: 24px 64px
@media (min-width: 992px)
max-width: 800px
padding-right: 15px
padding-left: 15px
max-width: 670px
h1
font-weight: 700
+89 -1
View File
@@ -9,13 +9,16 @@ $tertiary-dark: darken($tertiary, 20%)
$tertiary-light: lighten($tertiary, 20%)
$white: #F9F9FA
$white-dark: darken($white, 20%)
$black: #0F0F0F
$grey: #808080
$grey: #858585
$grey-light: lighten($grey, 20%)
$red: #8B0000
$purple: #4B0082
$midnight-black: #0F0F0F
$darkgrey: #202020
$grey2: #2D2D2D
$dark-grey: #202020
$button-color: $white
$button-background-color: $black
@@ -29,15 +32,100 @@ $button-background-color: $black
--tertiary: #{$tertiary}
--tertiary-light: #{$tertiary-light}
--tertiary-dark: #{$tertiary-dark}
--white: #{$white}
--white-dark: #{$white-dark}
--grey: #{$grey}
--grey-light: #{$grey-light}
--grey2: #{$grey2}
--dark-grey: #{$dark-grey}
--purple: #{$purple}
--blood-color: #{$red}
--midnight-black: #{$midnight-black}
--black: #{$midnight-black}
--darkgrey: #{$darkgrey}
//fonts
.tiny-text
font-family: Inter
font-size: 14px
.low-mid-text
font-family: Inter
font-size: 16px
font-style: normal
font-weight: 400
line-height: normal
// @media (min-width: 992px)
// font-size: 18px
.mid-mid-text
font-family: Inter
font-size: 18px
font-style: normal
font-weight: 400
line-height: normal
// @media (min-width: 992px)
// font-size: 24px
.mid-text
font-family: Inter
font-size: 18px
font-style: normal
font-weight: 400
line-height: normal
.small-text
font-family: Inter
font-size: 14px
font-style: normal
font-weight: 400
line-height: normal
@media (min-width: 992px)
font-size: 18px
.number-mobile
font-family: Inter
font-size: 24px
font-style: normal
font-weight: 400
line-height: normal
letter-spacing: 4.32px
.sub-header
font-family: Inter
font-style: normal
font-weight: 400
line-height: normal
font-size: 24px
// @media (min-width: 992px)
// font-size: 32px
.header
font-family: Inter
font-size: 32px
font-style: normal
font-weight: 400
line-height: normal
// @media (min-width: 992px)
// font-size: 30px
.sub-header-2
font-family: Inter
font-style: normal
font-weight: 400
line-height: normal
font-size: 24px
@media (min-width: 992px)
font-size: 32px
// :root
// --font-size-text: 16px
// --font-size-title: 32px
// @media (min-width: 992px)
// --font-size-text: 24px
// --font-size-title: 36px
.text-center
text-align: center
.transparent
background-color: transparent
.card
border-radius: 16px
@media (min-width: 992px)
padding: 48px 32px
&.card--glow
box-shadow: 0px 12px 150px 0px rgba(75, 0, 130, 0.35)
+153 -51
View File
@@ -1,15 +1,37 @@
<template>
<div class="blood-chart-wrapper" v-if="props.data">
<div class="blood-chart-element" v-for="coin in props.data.token" :key="coin.name">
<div class="blood-chart-wrapper">
<div class="blood-arrow left">
<img
class="swiper-arrow"
src="/assets/img/blood-arrow-left.png"
alt="left-arrow"
@click="swiperInstance.slidePrev()"
v-if="token?.length > 3"
/>
</div>
<swiper
class="blood-chart"
:slidesPerView="3"
:centeredSlides="false"
:initial-slide="0"
:spaceBetween="0"
@swiper="onSwiper"
>
<swiper-slide class="blood-chart-element" v-for="coin in token" :key="coin.name">
<div class="blood-chart-element-header">
<div class="blood-chart-coin">
<img :src="getImageUrl(coin.vamplogo)" alt="logo" />
<template v-if="cycleStore.getCycleWinner.contractAddress === coin.contractAddress">
<img class="logo" :src="coin.vamplogo" alt="logo" />
<img class="crown" src="/assets/img/winnerCrown.png" alt="" />
</template>
<template v-else>
<img :src="coin.vamplogo" alt="logo" />
</template>
</div>
<div class="blood-chart-coin-title">{{ coin.name }}</div>
<div class="blood-chart-coin-title low-mid-text">{{ coin.name }}</div>
</div>
<div class="blood-chart-element-body">
<div class="blood-chart-bar-wrapper">
<div class="blood-chart-bar" :style="`height: ${getPercentage(coin.amount, props.data.goal)}%`">
<svg
class="waves"
xmlns="http://www.w3.org/2000/svg"
@@ -31,6 +53,10 @@
<use xlink:href="#gentle-wave" x="48" y="7" fill="#8B0000" />
</g>
</svg>
<div
class="blood-chart-bar"
:style="`height: ${getPercentageBloodChart(coin.amount, props.data.goal)}%`"
>
<div class="wrapper">
<div><span class="dot"></span></div>
<div><span class="dot"></span></div>
@@ -39,116 +65,192 @@
<div><span class="dot"></span></div>
<div><span class="dot"></span></div>
</div>
<div class="blood-chart-bar-percentage">{{ getPercentage(coin.amount, props.data.goal) }}%</div>
<div class="blood-chart-bar-percentage">
{{ getPercentage(coin.amount, props.data.goal) }}%
</div>
</div>
</div>
</div>
<div class="blood-chart-element-footer">
<div class="blood-chart-amount">
{{ compactNumber(coin.amount) }}
<div
class="blood-chart-amount"
:title="formatBigIntDivision(coin.amountInBLD, 10n ** tokenStore.memeToken.decimals)"
>
{{
compactNumber(formatBigIntDivision(coin.amountInBLD, 10n ** tokenStore.memeToken.decimals))
}}
</div>
<div class="blood-chart-coin">$BLOOD</div>
<div>$BLOOD</div>
</div>
</swiper-slide>
<!-- <button @click="swiperInstance.slidePrev()">left</button>
<button @click="swiperInstance.slideNext()">left</button> -->
</swiper>
<div class="blood-arrow right">
<img
class="swiper-arrow"
src="/assets/img/blood-arrow-right.png"
alt="left-arrow"
@click="swiperInstance.slideNext()"
v-if="token?.length > 3"
/>
</div>
</div>
</template>
<script setup>
import { getPercentage, compactNumber } from "@/helper/helper.js";
import { useMemeburnerStore } from "@/stores/memeburner";
import { computed, ref, inject, onMounted } from "vue";
import { getPercentage, formatNumber, compactNumber, formatBigIntDivision } from "@/helper/helper.js";
import { useCycleStore } from "@/stores/cycles";
const memeBurnerStore = useMemeburnerStore();
import { useMemeburnerStore } from "@/stores/memeburner";
import { useTokenStore } from "@/stores/tokens";
import { Swiper, SwiperSlide } from "swiper/vue";
// Import Swiper styles
import "swiper/css";
import "swiper/css/navigation";
import "swiper/css/pagination";
const cycleStore = useCycleStore();
const tokenStore = useTokenStore();
const isMobile = inject("isMobile");
const props = defineProps({
data: Array,
data: Object,
});
console.log(props.data);
onMounted(() => {
console.log("bloodchart-data", props.data);
});
function getImageUrl(url) {
return new URL(url, import.meta.url).href;
const swiperInstance = ref();
function onSwiper(swiper) {
swiperInstance.value = swiper;
}
// const dataPoints = [
// {
// name: "$PEPE",
// percentage: 62.2,
// icon: "/assets/img/token/pepevamp.png",
// },
// {
// name: "$SHIB",
// percentage: 31.2,
// icon: "/assets/img/token/shibvamp.png",
// },
// {
// name: "$ELON",
// percentage: 54.5,
// icon: "/assets/img/token/elonvamp.png",
// },
// ];
const token = computed(() => {
return props.data?.token.sort((a, b) => (a.amount > b.amount ? -1 : b.amount > a.amount ? 1 : 0));
});
//start with visual 8% of the filled bar, because otherwise the percentage number is not visible
function getPercentageBloodChart(amount, goal) {
let returnNumber = 8;
if ((Number(amount) / Number(goal)) * 100 < 8) {
returnNumber = 8;
} else {
returnNumber = (Number(amount) / Number(goal)) * 100;
}
return returnNumber.toFixed(2);
}
</script>
<style lang="sass">
.blood-chart-wrapper
height: 750px
// margin-top: 56px
display: flex
justify-content: center
// margin-bottom: 80px
position: relative
margin-top: 24px
.blood-chart
height: 560px
width: 100%
justify-content: space-around
display: inline-flex
overflow: unset
@media (min-width: 992px)
gap: 96px
gap: 32px
width: unset
justify-content: unset
.blood-chart-element
height: 100%
width: 80px
align-items: center
@media (min-width: 992px)
width: 100px
display: flex
flex-direction: column
.blood-chart-element-header
flex: 0 0 100px
.blood-chart-coin
height: 80px
width: 80px
border-radius: 80px
margin-left: auto
margin-right: auto
position: relative
margin-bottom: 16px
overflow: hidden
// overflow: hidden
height: 80px
width: 80px
@media (min-width: 992px)
height: 72px
width: 72px
img
&.logo
height: 100%
width: 100%
border: 1px solid yellow
border-radius: 50%
img
&.crown
position: absolute
top: -10px
transform: translate(-50%, -50%)
left: 50%
.blood-chart-coin-title
text-align: center
margin-bottom: 32px
font-size: 16px
@media (min-width: 992px)
font-size: 24px
.blood-chart-element-body
background-color: rgba(233, 233, 233, 0.2)
flex: 0 0 500px
flex: 1 1 100%
width: 60px
border-radius: 8px 8px 40px 40px
text-align: left
overflow: hidden
.blood-chart-bar-wrapper
height: 100%
display: flex
flex-direction: column
.blood-chart-bar
.waves
margin-top: auto
.blood-chart-bar
background-color: var(--blood-color)
position: relative
border-radius: 0 0 40px 40px
.blood-chart-bar-percentage
font-size: 14px
text-align: center
.waves
position: absolute
top: -10px
width: 100%
height: 10px
.blood-chart-element-footer
margin-top: 32px
text-align: center
.blood-chart-amount
font-size: 24px
margin-bottom: 8px
.blood-chart-coin
font-size: 16px
.swiper-slide
width: 80px
.blood-arrow
min-width: 30px
&.left, &.right
img
height: 50px
position: absolute
top: 50%
z-index: 0
&.right
img
right: -5px
&.left
img
left: -5px
</style>
File diff suppressed because one or more lines are too long
+81
View File
@@ -0,0 +1,81 @@
<template>
<div
class="connected-stake bloodline-border card"
:class="{ 'card--dense': dense }"
@click="
(e) => {
e.preventDefault();
e.stopPropagation();
}
"
>
<div class="connected-stake-headline mid-mid-text" v-if="slots.headline">
<slot name="headline"></slot>
</div>
<div class="connected-stake-subheadline" v-if="slots.subheadline">
<slot name="subheadline"></slot>
</div>
<div class="connected-stake-body" v-if="slots.body">
<slot name="body"></slot>
</div>
<slot name="actions"></slot>
<slot></slot>
</div>
</template>
<script setup>
import { useTokenStore } from "@/stores/tokens";
import { useWalletStoreV2 } from "@/stores/walletV2";
import { ref } from "vue";
import { useSlots } from "vue";
const slots = useSlots();
const props = defineProps({
stakeonly: {
type: Boolean,
required: false,
default: false,
},
dense: {
type: Boolean,
required: false,
default: false,
},
});
</script>
<style lang="sass">
.card--dense
padding: 8px
.connected-stake
background-color: var(--darkgrey)
display: flex
flex-direction: column
gap: 16px
border: 2px solid var(--grey, #858585)
border-color: var(--grey, #858585)
@media (min-width: 992px)
padding: 8px 12px
&.connected-stake--variant1
background-color: transparent
border: none
padding: 16px 6px
.connected-stake-headline
text-align: center
.connected-stake-subheadline
text-align: center
.connected-stake-body
display: flex
text-align: left
gap: 16px
.token-logo
margin-left: auto
.connected-stake-buttons
display: flex
text-align: center
gap: 16px
justify-content: center
// div
// flex: 1 1 50%
</style>
+244
View File
@@ -0,0 +1,244 @@
<template>
<card-component>
<template v-slot:headline> Unclaimed </template>
<template v-slot:body>
<token-name-price
:name="tokenStore.getToken(walletStore.memeToken?.contractAddress)?.name"
:price="formatNumber(walletStore.unclaimedRewards, 10n ** tokenStore.memeToken.decimals)"
></token-name-price>
<token-logo img="/assets/img/token/bloodline.png" :alt="'bloodline logo'"></token-logo>
</template>
<template v-slot:actions>
<template v-if="walletStore.unclaimedRewards > 0n">
<Transition name="smooth">
<div class="connected-stake-buttons" v-show="!stakeMenu">
<div class="btn btn-immortal mid-mid-text" @click="claimAll" v-if="stateStake === 0">Claim</div>
<div class="btn btn-immortal mid-mid-text" disabled v-else-if="stateStake === 2">
Sign Transaction
</div>
<div class="btn btn-immortal stake-button" disabled v-else-if="stateStake === 3">
<loading-component></loading-component>
</div>
<div class="btn btn-immortal mid-mid-text" @click="openStake" v-if="stateStake === 0">
Stake
</div>
</div>
</Transition>
<Transition name="smooth">
<stake-menu
v-model="tokenNumber"
@close="stakeMenu = false"
:amount="walletStore.unclaimedRewards"
:stake="stake"
v-if="stakeMenu"
>
<template v-slot:body>
<div
class="btn btn-immortal stake-button"
disabled
v-if="
tokenNumber > 0 &&
BigInt(tokenNumber) * 10n ** tokenStore.memeToken.decimals >
walletStore.unclaimedRewards
"
>
Insufficient Balance
</div>
<div class="btn btn-immortal stake-button" disabled v-else-if="stateClaimComp === 0">
Enter Amount
</div>
<div
class="btn btn-immortal stake-button"
v-else-if="stateClaimComp === 1"
@click="stakeAndClaimAllCycles"
>
Stake & Claim Rest
</div>
<div class="btn btn-immortal stake-button" disabled v-else-if="stateClaimComp === 2">
Sign Transaction
</div>
<div class="btn btn-immortal stake-button" disabled v-else-if="stateClaimComp === 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(walletStore.unclaimedRewards, 10n ** tokenStore.memeToken.decimals) }}
</div>
</template>
</stake-menu>
</Transition>
</template>
<template v-else-if="cycleStore.rewardsSacrificeCurrentCycle > 0n">
<div class="connected-stake-buttons">
<div class="btn btn-immortal mid-mid-text btn--disabled">Claim</div>
<div class="btn btn-immortal mid-mid-text btn--disabled">Stake</div>
</div>
<div class="text-center">You can claim, once the cycle is over</div>
</template>
<template v-else>
<div class="btn btn-immortal mid-mid-text text-center" @click="router.push({ name: 'home' })">
Go to Sacrifice
</div>
<div class="small-text text-center">Sacrifice to earn $BLOOD</div>
</template>
</template>
</card-component>
</template>
<script setup>
import { ref, computed } from "vue";
import CardComponent from "@/components/CardComponent.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 StakeSuccessToast from "@/components/toasts/StakeSuccessToast.vue";
import { useCycleStore } from "@/stores/cycles";
import { useWalletStoreV2 } from "@/stores/walletV2";
import { useTokenStore } from "@/stores/tokens";
import { useRewardLockerStore } from "@/stores/rewardlocker";
import { useRouter } from "vue-router";
import { useToast } from "vue-toastification";
import { formatNumber } from "@/helper/helper.js";
import { showSuccessToast } from "@/helper/toast.js";
const toast = useToast();
const rewardLockerStore = useRewardLockerStore();
const walletStore = useWalletStoreV2();
const tokenStore = useTokenStore();
const cycleStore = useCycleStore();
const router = useRouter();
const props = defineProps({
stakeonly: {
type: Boolean,
required: false,
default: false,
},
});
const stakeMenu = ref(false);
const stake = ref(null);
const tokenNumber = ref(null);
/**
* state 0 enter amount
* state 1 rdy to go
* state 2 signing
* state 3 loading
* state 4 staked
*/
const state = ref(0);
const stateClaim = ref(0);
function openStake() {
stake.value = true;
stakeMenu.value = true;
}
async function stakeAndClaimAllCycles() {
try {
stateClaim.value = 2;
const coefficient = BigInt(10000 * tokenNumber.value) / walletStore.unclaimedRewards;
var hash = await rewardLockerStore.stakeAndClaimAllCycles(coefficient);
stateClaim.value = 3;
const data = await waitForTransaction({
hash: hash,
});
stateClaim.value = 4;
var rewardData = data.logs.find((logObject) => {
return logObject.topics.find(
(topic) => topic === "0xd0813ff03c470dcc7baa9ce36914dc2febdfd276d639deffaac383fd3db42ba3"
);
});
//
console.log("rewardData", rewardData);
//ClaimedReward (address staker, uint256 reward)
const outputClaim = formatNumber(BigInt(rewardData.topics[2]), 10n ** tokenStore.memeToken.decimals);
showSuccessToast(
outputClaim,
"Success!",
"You just claimed and staked",
"Join the next cycle to increase your rewards and win with your clan"
);
await walletStore.loadWalletData();
} catch (error) {
stateClaim.value = 0;
console.error(error);
throw new Error(error);
}
}
async function claimAll() {
try {
state.value = 2;
const hash = await rewardLockerStore.claimAll();
state.value = 3;
const data = await waitForTransaction({
hash: hash,
});
var rewardData = data.logs.find((logObject) => {
return logObject.topics.find(
(topic) => topic === "0xd0813ff03c470dcc7baa9ce36914dc2febdfd276d639deffaac383fd3db42ba3"
);
});
//
console.log("rewardData", rewardData);
//ClaimedReward (address staker, uint256 reward)
const outputClaim = formatNumber(BigInt(rewardData.topics[2]), 10n ** tokenStore.memeToken.decimals);
showSuccessToast(
outputClaim,
"Success!",
"You just claimed",
"Join the next cycle to increase your rewards and win with your clan."
);
await walletStore.loadWalletData();
} catch (error) {
state.value = 0;
console.error(error);
throw new Error(error);
}
}
const stateStake = computed(() => {
let returnState = 0;
if (state.value === 2) {
returnState = 2;
} else if (state.value === 3) {
returnState = 3;
}
return returnState;
});
const stateClaimComp = computed(() => {
let returnState = 0;
console.log("tokenNumber.value", tokenNumber.value);
if (
tokenNumber.value === null ||
tokenNumber.value === "" ||
tokenNumber.value === 0 ||
BigInt(tokenNumber.value) > walletStore.unclaimedRewards / 10n ** tokenStore.memeToken.decimals
) {
returnState = 0;
} else if (stateClaim.value === 2) {
returnState = 2;
} else if (stateClaim.value === 3) {
returnState = 3;
} else if (tokenNumber.value !== null || tokenNumber.value !== "" || tokenNumber.value > 0) {
returnState = 1;
}
return returnState;
});
</script>
<style lang="sass"></style>
+164 -73
View File
@@ -1,120 +1,167 @@
<template>
<h3>Connect Wallet</h3>
<div class="connect-wallet-wrapper">
<template v-if="!walletStore.connected">
<div class="connect-wallet-headline low-mid-text">Connect your wallet</div>
<div class="connectors-wrapper">
<div class="connectors-element" v-for="connector in walletStore.connectors" @click="connectWallet(connector)">
<div
class="connectors-element card"
:class="[[connector.id]]"
v-for="connector in walletStore.config?.connectors"
@click="connectWallet(connector)"
>
<div class="connector-icon">
<img :src="`/assets/img/connectors/${connector.id}.svg`" :alt="`${connector.name} Logo`">
<template v-if="connector.id === 'injected'">
<template v-if="connector.name === 'MetaMask'">
<img :src="`/assets/img/connectors/metaMask.svg`" :alt="`${connector.name} Logo`" />
</template>
<template v-else>
<font-awesome-icon :icon="['fas', 'wallet']" />
</template>
</template>
<template v-else>
<img :src="`/assets/img/connectors/${connector.id}.svg`" :alt="`${connector.name} Logo`" />
</template>
</div>
<div class="connector-name">{{ connector.name }}</div>
<div class="connector-name">
{{ connector.name }}
</div>
</div>
<div @click="disconnectWallet">disconnect</div>
<div @click="getWalletClientTest">getwalletclient</div>
<div>Connected: {{ walletStore.connected }}</div>
</div>
<div>Are you coming from Binance, Bybit, Kucoin or any other crypto exchange?</div>
<div>Follow these instructions first.</div>
</template>
<template v-else>
<div class="connected-header">
<div class="connected-header-avatar">
<img :src="getblocky(walletStore.address)" alt="avatar" />
</div>
<div class="connected-header-address" :title="walletStore.address">
{{ getAddressShortName(walletStore.address) }}
</div>
<div class="connected-header-logout" @click="disconnectWallet">
<font-awesome-icon :icon="['fas', 'fa-arrow-right-from-bracket']" />
</div>
</div>
<div class="connected-tokens-headline">Your Tokens</div>
<div class="connected-tokens">
<div class="connected-token" v-for="token in walletStore.token">
<token-name-price
:name="tokenStore.getToken(token.contractAddress).name"
:price="
formatNumber(token.balanceOf, 10n ** tokenStore.getToken(token.contractAddress).decimals)
"
></token-name-price>
<div class="connected-token-button">
<div class="bloodline-badge grey" @click="badgeClick(token)">
<div
class="bloodline-badge-text"
v-if="tokenStore.memeToken.contractAddress === token.contractAddress"
>
Buy
</div>
<div v-else class="bloodline-badge-text">Sacrifice</div>
</div>
</div>
<token-logo :img="tokenStore.getToken(token.contractAddress).logo" :alt="'test'"></token-logo>
</div>
</div>
<stake-component-v1 :variant="3"></stake-component-v1>
</template>
</div>
</template>
<script setup>
import { ref, toRaw, onMounted, onUnmounted, getCurrentInstance } from "vue";
import { useWalletStoreV2 } from "@/stores/walletV2";
import Meme1Json from "@/assets/contracts/Meme1.json";
import { useTokenStore } from "@/stores/tokens";
import TokenNamePrice from "./TokenNamePrice.vue";
import TokenLogo from "./TokenLogo.vue";
import StakeComponentV1 from "@/components/StakeComponentV1.vue";
import {
createConfig,
configureChains,
mainnet,
getAccount,
getContract,
connect,
disconnect,
InjectedConnector,
watchAccount,
getWalletClient,
} from "@wagmi/core";
import { getAddressShortName, getblocky, formatNumber } from "@/helper/helper.js";
import { useRoute, useRouter } from "vue-router";
import { disconnect } from "@wagmi/core";
const router = useRouter();
const walletStore = useWalletStoreV2();
const tokenStore = useTokenStore();
const goerliKey = import.meta.env.VITE_GOERLI_KEY;
const fromAddress = ref(null);
const accountSub = ref(null);
// const goerliKey = import.meta.env.VITE_GOERLI_KEY;
const instance = getCurrentInstance();
// config.value = createConfig({
// autoConnect: true,
// connectors: [
// new CoinbaseWalletConnector({
// chains,
// options: {
// appName: "wagmi demo",
// },
// }),
// new MetaMaskConnector({ chains }),
// new WalletConnectConnector({
// chains,
// options: {
// projectId: projectId,
// showQrModal: true,
// metadata: {
// name: "Bloodline-App",
// description: "TODO Bloodline Description",
// url: "https://gitea.loseyourip.com/",
// icons: [
// "https://gitea.loseyourip.com/assets/img/vampir.png",
// ],
// },
// },
// }),
// ],
// publicClient,
// webSocketPublicClient,
// });
// console.log("config", config);
async function disconnectWallet() {
console.log("disconnectWallet");
try {
instance.parent.emit("update:modelValue", false);
await disconnect();
} catch (error) {
console.log("error", error);
}
}
async function getWalletClientTest() {
const walletClient = await getWalletClient();
console.log("walletClient", walletClient);
const contract = getContract({
address: Meme1Json.contractAddress,
abi: Meme1Json.abi,
walletClient,
});
const result = await contract.read.totalSupply();
console.log("result", result);
// console.log("obj", obj);
// });
function isMetaMaskInstalled(connector) {
const metamaskInstalled = connector?.options?.getProvider();
if (metamaskInstalled) {
return true;
}
return false;
}
//go to the sacrifice-page and select the clicked token
//if contract === bloodline show buy
//we could also show buy, if there is no pepe
function badgeClick(token) {
var tokenData = tokenStore.getToken(token.contractAddress);
if (tokenStore.memeToken.contractAddress === token.contractAddress) {
//buy
window.open(
`https://app.uniswap.org/swap?inputCurrency=ETH&outputCurrency=${token.contractAddress}&chain=goerli`,
"_blank"
);
} else {
router.push({ name: "home" });
instance.parent.emit("update:modelValue", false);
}
}
//special case for metaMask, but I think that is the most used wallet
async function connectWallet(connector) {
console.log("connector", connector);
instance.parent.emit("update:modelValue", false);
await walletStore.connectWallet(toRaw(connector));
}
</script>
<style lang="sass">
.connectors-wrapper
.connect-wallet-wrapper
display: flex
flex-direction: column
gap: 24px
.connectors-wrapper
display: flex
flex-direction: column
gap: 8px
.connectors-element
display: flex
padding: 12px
border: 1px solid rgba(152, 161, 192, 0.24)
background-color: #202020
background: var(--grey, #858585)
color: var(--midnight-black, #0F0F0F)
&:hover, &:active, &:focus
background-color: lighten(#202020, 20%)
background-color: lighten(#858585, 20%)
cursor: pointer
&.injected
.connector-icon
background-color: white
display: flex
justify-content: center
align-items: center
svg
font-size: 25px
.connector-icon
border-radius: 12px
width: 40px
@@ -123,4 +170,48 @@ async function connectWallet(connector) {
.connector-name
padding: 0 8px
align-self: center
font-size: 16px
@media (min-width: 992px)
font-size: 18px
.connected-header
margin-bottom: 24px
display: flex
gap: 16px
align-items: center
.connected-header-avatar
img
border-radius: 8px
.connected-header-logout
margin-left: auto
&:hover, &:active, &:focus
cursor: pointer
svg
font-size: 25px
.connected-tokens-headline
font-size: 18px
margin-bottom: 16px
.connected-tokens
display: flex
flex-direction: column
gap: 16px
margin-bottom: 24px
.connected-token
display: flex
gap: 16px
align-items: center
.connected-token-button
margin-left: auto
.bloodline-badge
padding: 4px 16px
color: black
font-size: 14px
&:hover, &:active, &:focus
cursor: pointer
background-color: var(--grey-light)
</style>
+43
View File
@@ -0,0 +1,43 @@
<template>
<div class="loading-container">
<div class="blood"></div>
<div class="blood"></div>
<div class="blood"></div>
</div>
</template>
<style lang="sass">
.loading-container
display: flex
align-items: center
justify-content: center
gap: 10px
.blood
width: 15px
height: 15px
border: 1px solid black
border-radius: 0% 100% 100% 100%
transform: rotate(45deg)
animation: blink 1s infinite
@media (min-width: 992px)
width: 20px
height: 20px
.blood
&:nth-child(1)
animation-delay: -.2s
&:nth-child(2)
animation-delay: 0.2s
&:nth-child(3)
animation-delay: 0.5s
@keyframes blink
0%
background-color: transparent
50%
background-color: red
</style>
+136 -76
View File
@@ -1,21 +1,72 @@
<template>
<div class="navbar" :class="{ 'navbar--hidden': !showNavbar }">
<div class="navbar-inner">
<div class="navbar-icon">
<router-link to="/">
<img alt="logo" class="logo" src="/assets/img/vampir.png" />
</router-link>
</div>
<div class="navbar-text">
<router-link to="/">Bloodline</router-link>
</div>
<div class="navbar-center" v-if="!isMobile"></div>
<div class="navbar-end">
<div class="navbar-navigation mid-text" v-if="!isMobile">
<div
class="navbar-navigation-link"
v-for="link in links"
:key="link.name"
:class="{ active: link.name === route.name }"
@click="router.push(link.path)"
>
<div class="icon">
<img :src="link.icon" alt="" />
</div>
<div class="text">{{ link.title }}</div>
</div>
</div>
<div v-if="!isMobile">
<div v-if="!address" class="btn btn-immortal mid-text" @click="showPanel = true">Connect</div>
<div class="login-icon-desktop mid-text" v-else @click="showPanel = true">
<img :src="getblocky(address)" alt="avatar" />
<div>{{ getAddressShortName(walletStore.address) }}</div>
</div>
</div>
<div v-else @click="showPanel = true">
<div class="login-icon" v-if="!address">
<font-awesome-icon :icon="['fas', 'fa-arrow-right-to-bracket']" />
</div>
<div v-else>
<img :src="getblocky(address)" alt="avatar" />
</div>
</div>
</div>
</div>
</div>
</template>
<script setup>
import { storeToRefs } from "pinia";
import { ref, onMounted, onBeforeUnmount, inject } from "vue";
import { useWalletStoreV2 } from "@/stores/walletV2";
import { getblocky, getAddressShortName } from "@/helper/helper.js";
import { useRoute, useRouter } from "vue-router";
const emit = defineEmits(["showPanel"]);
const walletStore = useWalletStoreV2();
const { connected, address } = storeToRefs(walletStore);
const { address } = storeToRefs(walletStore);
const isMobile = inject("isMobile");
const showPanel = inject("showPanel");
const showPanel = ref(false);
const router = useRouter();
const route = useRoute();
const showNavbar = ref(true);
const lastScrollPosition = ref(0);
function onScroll() {
const currentScrollPosition =
window.pageYOffset || document.documentElement.scrollTop;
const currentScrollPosition = window.pageYOffset || document.documentElement.scrollTop;
if (currentScrollPosition < 0) {
return;
}
@@ -23,6 +74,27 @@ function onScroll() {
lastScrollPosition.value = currentScrollPosition;
}
const links = [
{
title: "Sacrifice",
name: "home",
path: "/",
icon: "/assets/img/sacrifice-icon.png",
},
{
title: "Cycle",
name: "cycle",
path: "/cycle",
icon: "/assets/img/cycle-icon.png",
},
{
title: "Profile",
name: "profile",
path: "/profile",
icon: "/assets/img/profile-icon.png",
},
];
onMounted(() => {
window.addEventListener("scroll", onScroll);
});
@@ -32,56 +104,8 @@ onBeforeUnmount(() => {
});
</script>
<template>
<header>
<div class="navbar" :class="{ 'navbar--hidden': !showNavbar }">
<div class="navbar-inner">
<div class="navbar-icon">
<router-link to="/">
<img alt="logo" class="logo" src="/assets/img/vampir.png" />
</router-link>
</div>
<div class="navbar-text">Bloodline</div>
<div class="navbar-center" v-if="!isMobile">
<div class="navbar-social-links">
<div class="social-bloodline-badge">
<div class="social-bloodline-badge-icon">
<font-awesome-icon icon="fa-brands fa-discord" />
</div>
<div class="social-bloodline-badge-text">Discord</div>
</div>
<div class="social-bloodline-badge">
<div class="social-bloodline-badge-icon">
<font-awesome-icon icon="fa-brands fa-telegram" />
</div>
<div class="social-bloodline-badge-text">Telegram</div>
</div>
<div class="social-bloodline-badge">
<div class="social-bloodline-badge-icon">
<font-awesome-icon icon="fa-brands fa-twitter" />
</div>
<div class="social-bloodline-badge-text">Twitter</div>
</div>
</div>
</div>
<div class="navbar-end">
<div v-if="!isMobile">
<!-- <div v-if="!connected" class="btn btn-immortal" @click="walletStore.connectWallet">connect</div> -->
<div v-if="!address" class="btn btn-immortal" @click="$emit('showPanel', true)">connect</div>
<span v-else @click="$emit('showPanel', true)"> {{ address }}</span>
</div>
<div v-else class="hamburger-menu">
<font-awesome-icon :icon="['fas', 'bars']" />
</div>
</div>
</div>
</div>
</header>
</template>
<style lang="sass" scoped>
header
.navbar
.navbar
position: fixed
z-index: 3
box-sizing: border-box
@@ -91,9 +115,9 @@ header
transition: transform .3s ease,visibility 0s .3s linear
height: 82px
@media (min-width: 992px)
height: 128px
&.navbar--hidden
transform: translate3d(0,-100%,0)
height: 80px
// &.navbar--hidden
// transform: translate3d(0,-100%,0)
.navbar-inner
display: flex
padding: 16px 24px
@@ -106,6 +130,10 @@ header
img
height: 50px
width: 50px
@media (min-width: 992px)
height: 56px
width: 56px
.navbar-text
font-family: 'Vampire', sans-serif
font-size: 36px
@@ -113,28 +141,60 @@ header
letter-spacing: 0.138em
line-height: 73.107px
@media (min-width: 992px)
font-size: 64px
font-size: 42px
a
text-decoration: none
color: white
.navbar-center
display: flex
margin-left: auto
.navbar-social-links
display: flex
gap: 18px
.social-bloodline-badge
font-size: 16px
padding: 8px 16px 8px 16px
border-radius: 14px
background-color: #0F0F0F
display: flex
&:hover,&:active,&:focus
background-color: lighten(#0F0F0F, 10%)
cursor: pointer
.social-bloodline-badge-icon
margin-right: 8px
.navbar-end
display: flex
margin-left: auto
.hamburger-menu
color: var(--purple)
font-size: 42px
gap: 80px
.navbar-navigation
display: flex
align-items: center
gap: 48px
.navbar-navigation-link
display: flex
gap: 8px
border-bottom: 2px solid transparent
&.active
border-bottom: 2px solid white
&:active, &:hover, &:focus
cursor: pointer
.icon
img
width: 20px
height: 20px
.login-icon
color: var(--white)
background-color: var(--purple)
padding: 8px
font-size: 25px
border-radius: 8px
width: 44px
height: 44px
display: flex
justify-content: center
align-items: center
img
width: 32px
height: 32px
border-radius: 8px
.login-icon-desktop
display: flex
padding: 8px
align-items: center
gap: 16px
border-radius: 16px
background: var(--Background-grey, #2D2D2D)
&:hover,&:active,&:focus
cursor: pointer
img
width: 32px
height: 32px
</style>
+20 -35
View File
@@ -1,54 +1,39 @@
<template>
<div class="rewards-wrapper">
<div class="rewards-header">
<div class="rewards-header-title">
{{ props.title }}
<div class="rewards-headline low-mid-text">
<div class="rewards-title">{{ props.title }}</div>
<div class="rewards-sub-title" v-if="props.subTitle">{{ props.subTitle }}</div>
</div>
<div class="rewards-header-info">{{ props.info }}</div>
</div>
<div class="rewards-sacrifice-wrapper bloodline-border bloodline-border--variant1">
<div class="rewards-body">
<div class="rewards-coin">$BLOOD</div>
<div class="rewards-amount">{{ props.amount }}</div>
</div>
<img class="bloodline-token" :src="props.image" alt="vampir" />
<div class="rewards-inner">
<token-name-price name="$BLOOD" :price="props.amount"></token-name-price>
<token-logo :img="props.image" :alt="'vampire'"></token-logo>
</div>
</div>
</template>
<script setup>
import TokenNamePrice from "@/components/TokenNamePrice.vue";
import TokenLogo from "@/components/TokenLogo.vue";
const props = defineProps({
title: String,
subTitle: String,
info: String,
amount: String,
amount: [String, Number],
image: String,
});
</script>
<style lang="sass">
.rewards-header
font-size: 16px
padding: 8px
.rewards-wrapper
display: flex
@media (min-width: 992px)
font-size: 24px
.rewards-header-info
margin-left: auto
.rewards-sacrifice-wrapper, .rewards-clan-wrapper
flex-direction: column
gap: 8px
padding: 6px 0
.rewards-inner
display: flex
.rewards-body
align-self: center
.rewards-coin
font-size: 16px
@media (min-width: 992px)
font-size: 24px
.rewards-amount
font-size: 24px
margin-top: 8px
@media (min-width: 992px)
font-size: 40px
margin-top: 0
img
margin-left: auto
align-self: center
padding: 0 6px 6px 6px
border-bottom: 1px solid var(--grey, #858585)
justify-content: space-between
box-sizing: content-box
</style>
+365 -131
View File
@@ -1,8 +1,5 @@
<template>
<div class="sacrifice-wrapper card bloodline-wrapper">
{{ activeToken.allowance }}
<div class="sacrifice-inner">
<div class="sacrifice-wrapper card card--glow">
<div class="sacrifice-headline">Select Sacrifice</div>
<div class="sacrifice-select-tokens">
<div class="sacrifice-tokens">
@@ -17,164 +14,363 @@
]"
v-for="token in props.data"
:key="token.contractAddress"
@click="tokenStore.changeActiveToken(token)"
@click="changeActiveToken(token)"
>
<div class="sacrifice-token-logo">
<img v-if="isMobile" :src="token.logoMobile" alt="token logo" />
<img v-if="!isMobile" :src="token.logo" alt="token logo" />
</div>
<div class="sacrifice-token-name">{{ token.name }}</div>
<div class="sacrifice-token-name mid-text">{{ token.name }}</div>
</div>
</div>
</div>
<div class="sacrifice-from-to-wrapper" v-if="activeToken.contractAddress">
<div
:class="{
'sacrifice-from-wrapper': true,
'bloodline-border': true,
'bloodline-border--variant1': true,
purple: isMobile,
}"
<div class="sacrifice-from-wrapper bloodline-border bloodline-border--variant1 purple">
<token-input
:modelValue="sacrificeStore.sacrificeNumber / 10n ** activeToken.decimals"
@input="
($event) => {
const value = BigInt($event.target.value) * 10n ** activeToken.decimals;
sacrificeStore.sacrificeNumber = value;
processChange(value);
}
"
:max="activeWalletToken?.balanceOf"
:logo="activeToken.logo"
>
<div class="sarcrifice-from-input">
<input @input="processChange" v-model="tokenNumber" :placeholder="0" />
<div class="sacrifice-logo">
<img :src="activeToken.logo" alt="vampir" />
<template v-slot:message>
<div
class="sacrifice-adder-step bloodline-badge"
v-for="steps in activeToken.addSteps"
:key="steps.name"
@click="addTokens(steps.amount)"
>
<template
v-if="
!walletStore.connected ||
sacrificeStore.sacrificeNumber < activeWalletToken?.balanceOf
"
>
+{{ steps.name }}
</template>
<template v-else> -{{ steps.name }} </template>
</div>
</template>
<template v-slot:message-end v-if="activeWalletToken?.balanceOf >= 0">
<div class="input-balance tiny-text">
Balance:
{{ formatNumber(activeWalletToken?.balanceOf, 10n ** activeToken.decimals) }}
</div>
<div class="value-adder">
<div class="sacrifice-adder-step bloodline-badge" @click="addTokens(10000000)">+10m</div>
<div class="sacrifice-adder-step bloodline-badge" @click="addTokens(100000000)">+100m</div>
<div class="sacrifice-adder-step bloodline-badge" @click="addTokens(1000000000)">+1b</div>
<!-- <div class="sacrifice-adder-balance">Balance: {{ parseFloat(activeToken.balance) }}</div>
<div class="sacrifice-adder-max" @click="tokenNumber = parseFloat(activeToken.balance)">
Max
</div> -->
<div class="input-max tiny-text" @click="addMaxTokens">Max</div>
</template>
</token-input>
</div>
</div>
<div class="sacrifice-divider bloodline-devider">
<div class="bloodline-devider">
<font-awesome-icon :icon="['fas', 'arrow-down']" />
</div>
<div
:class="{
'sacrifice-from-wrapper': true,
'sacrifice-to-wrapper': true,
'bloodline-border': true,
'bloodline-border--variant1': true,
purple: isMobile && output && output > 0,
purple: output && output > 0,
}"
>
<div class="sarcrifice-from-input">
<div class="sacrifice-to-output">
<div class="sacrifice-to-output-coin">$BLOOD</div>
<div class="sacrifice-to-output-rewards">{{ output }}</div>
<div class="sacrifice-to-body">
<token-name-price
name="$BLOOD"
:price="`≈${formatNumber(output, 10n ** activeToken.decimals)}`"
></token-name-price>
<token-logo :img="activeToken.vamp.logo" :size="64" :alt="activeToken.vamp.name"></token-logo>
</div>
<div class="sacrifice-logo">
<img :src="activeToken.vamp.logo" :alt="activeToken.vamp.name" />
<div class="sacrifice-staking-bonus">
<div
class="sacrifice-staking-bonus-inner"
@click="
(e) => {
showStakingMenu = !showStakingMenu;
}
"
>
<div class="mid-mid-text" v-if="!walletStore.connected">+ Staking Bonus</div>
<div
class="mid-mid-text"
v-else-if="walletStore.memeToken?.staked === 0 || cycleStore.currentCycle === 1"
>
No Staking Bonus
</div>
<div class="mid-mid-text" v-else>
+ {{ formatNumber(stakingOutput, 10n ** activeToken.decimals) }} Staking Bonus
</div>
<div class="icon">
<font-awesome-icon icon="chevron-down" />
</div>
</div>
<stake-component-v1 :variant="1" v-if="showStakingMenu">
<template v-slot:headline> {{ null }}</template>
</stake-component-v1>
</div>
<div class="sacrifice-fees-info-wrapper">
<div class="sacrifice-fees-img">
<img src="/assets/img/fuel-noozle.png" alt="fuel noozle" />
</div>
<div class="sacrifice-fees-body">
<div class="sacrifice-fees-body-header">
<div class="sacrifice-fees-body-header-title">Gas Support</div>
<div class="sacrifice-fees-body-header-amount">42Gwei</div>
</div>
<div class="sacrifice-fees-body-subheader">Increase amount to pay 97% less network fees.</div>
<div class="sacrificed-info" v-if="stateComputed === 4">
<div class="left low-mid-text">You can claim your $BLOOD when the cycle is finished.</div>
<div class="right">
<img src="/assets/img/moon.png" alt="moon" />
</div>
</div>
<div class="sacrifice-buttons-function-wrapper">
<div v-if="connected">
<template v-if="walletStore.connected">
<div class="btn btn-immortal sub-header" disabled v-if="stateComputed === 0">Enter Amount</div>
<div
class="btn btn-immortal"
v-if="activeToken.allowance > 0 && activeToken.allowance >= tokenNumber"
@click="approvalData = memeburnerStore.sacrificeMeme(tokenNumber)"
class="btn btn-immortal sub-header"
disabled
v-else-if="sacrificeStore.sacrificeNumber > activeWalletToken?.balanceOf"
>
<font-awesome-icon v-if="memeburnerStore.loading" icon="spinner" spin />
Sacrifce {{ activeToken.name }}
Insufficient Balance
</div>
<div
class="btn btn-immortal"
v-else
@click="approvalData = tokenStore.approveToken(tokenNumber)"
class="btn btn-immortal sub-header"
v-else-if="
activeToken.allowance > 0 &&
activeToken.allowance >= sacrificeStore.sacrificeNumber &&
(stateComputed === 1 || stateComputed === 4)
"
@click="sacrificeToken"
>
<font-awesome-icon v-if="loading" icon="spinner" spin />
Approve {{ activeToken.name }}
Sacrifice 🩸
</div>
<div
class="btn btn-immortal sub-header"
v-else-if="
(!activeToken.allowance || activeToken.allowance < sacrificeStore.sacrificeNumber) &&
(stateComputed === 1 || stateComputed === 4)
"
@click="approveToken(sacrificeStore.sacrificeNumber)"
>
Approve Token
</div>
<div v-else>
<div class="btn btn-immortal" @click="walletStore.connectWallet">Connect</div>
<div class="btn btn-immortal sub-header" disabled v-else-if="stateComputed === 2">
Sign Transaction
</div>
<div class="btn btn-immortal sub-header" disabled v-else-if="stateComputed === 3">
<loading-component></loading-component>
</div>
</template>
<template v-else>
<div class="btn btn-immortal sub-header" @click="showPanel = true">Connect</div>
</template>
</div>
</div>
</div>
</template>
<script setup>
import { ref, defineProps, watch, inject, computed } from "vue";
import { useWalletStore } from "@/stores/wallet";
import { ref, defineProps, watch, inject, nextTick, onMounted, onBeforeUnmount, computed, markRaw } from "vue";
import { useWalletStoreV2 } from "@/stores/walletV2";
import { useCycleStore } from "@/stores/cycles";
import { useTokenStore } from "@/stores/tokens";
import { useMemeburnerStore } from "@/stores/memeburner";
import { useUniswapStore } from "@/stores/uniswap";
import { useSacrificeStore } from "@/stores/sacrifice";
import StakeComponentV1 from "@/components/StakeComponentV1.vue";
import LoadingComponent from "@/components/LoadingComponent.vue";
import TokenInput from "@/components/TokenInput.vue";
import TokenNamePrice from "@/components/TokenNamePrice.vue";
import TokenLogo from "@/components/TokenLogo.vue";
import ApprovedToast from "@/components/toasts/ApprovedToast.vue";
import { useToast } from "vue-toastification";
import { storeToRefs } from "pinia";
import Helper from "@/utils/helper.js";
const isMobile = inject("isMobile");
import { waitForTransaction, readContract, watchBlockNumber, multicall } from "@wagmi/core";
const walletStore = useWalletStore();
const { contract, connected } = storeToRefs(walletStore);
const cycleStore = useCycleStore();
const sacrificeStore = useSacrificeStore();
const toast = useToast();
import { debounce, formatNumber } from "@/helper/helper.js";
const isMobile = inject("isMobile");
const showPanel = inject("showPanel");
const splashBlood = inject("splashBlood");
const walletStore = useWalletStoreV2();
const tokenStore = useTokenStore();
const { activeToken, loading } = storeToRefs(tokenStore);
const memeburnerStore = useMemeburnerStore();
const { activeToken } = storeToRefs(tokenStore);
const props = defineProps({
data: Array,
});
watch(
activeToken,
() => {
tokenNumber.value = null;
},
{ deep: true }
);
const tokenNumber = ref(0);
const output = ref(0);
const stakingOutput = ref(null);
const blockEvent = ref(null);
const approveToast = ref(null);
const addOperator = ref(true);
const splashesUsed = ref([]);
/**
* state 0 enter amount
* state 1 rdy to go
* state 2 signing
* state 3 loading
* state 4 sacrificed
*/
const showStakingMenu = ref(false);
const approvalData = ref(null);
const processChange = Helper.debounce((e) => getRewardsFor(e));
async function getRewardsFor(e) {
if (!e.target.value || isNaN(e.target.value)) {
output.value = 0;
return;
const activeWalletToken = computed(() => {
let returnedObject = {};
if (activeToken.value.contractAddress) {
returnedObject = walletStore.token.find((obj) => obj.contractAddress === activeToken.value.contractAddress);
}
return returnedObject;
});
const stateComputed = computed(() => {
let returnState = 0;
if (
sacrificeStore.sacrificeNumber === null ||
sacrificeStore.sacrificeNumber === "" ||
sacrificeStore.sacrificeNumber === 0n
) {
returnState = 0;
} else if (sacrificeStore.sacrificeState === 2) {
returnState = 2;
} else if (sacrificeStore.sacrificeState === 3) {
returnState = 3;
} else if (
sacrificeStore.sacrificeNumber !== null ||
sacrificeStore.sacrificeNumber !== "" ||
sacrificeStore.sacrificeNumber > 0
) {
returnState = 1;
}
return returnState;
});
const processChange = debounce(async (value) => {
const rewardValue = await sacrificeStore.getRewardsFor(value, activeToken.value);
console.log("rewardValue", rewardValue);
output.value = rewardValue.output;
stakingOutput.value = rewardValue.staking;
});
onMounted(() => {
blockEvent.value = watchBlockNumber(
{
listen: true,
},
async (blockNumber) => {
console.log("blockNumber", blockNumber);
var rewardValue = await sacrificeStore.getRewardsFor(sacrificeStore.sacrificeNumber, activeToken.value);
output.value = rewardValue.output;
stakingOutput.value = rewardValue.staking;
}
console.log("activeToken.value.decimals", activeToken.value.decimals);
const rewardsForResult = await memeburnerStore.getRewardsFor(
BigInt(e.target.value * Math.pow(10, activeToken.value.decimals))
);
// var test = await memeburnerStore.getRewardsFor(10000);
// console.log("test", test);
// const rewardsForResult = await tokenStore.getRewardsFor(10000);
console.log("rewardsForResult", rewardsForResult);
console.log("tokenStore.memeToken.decimals", tokenStore.memeToken.decimals);
console.log(
"Math.pow(10, tokenStore.memeToken.decimals)",
Math.pow(10, tokenStore.memeToken.decimals)
);
output.value =
rewardsForResult / Math.pow(10, tokenStore.memeToken.decimals);
});
onBeforeUnmount(() => {
console.log("blockEventunwatch", blockEvent.value);
blockEvent.value();
});
async function approveToken(amount) {
try {
console.log("amount", amount);
sacrificeStore.sacrificeState = 2;
const hash = await tokenStore.approveToken(amount);
sacrificeStore.sacrificeState = 3;
const data = await waitForTransaction({
hash: hash,
});
console.log("data", data);
activeToken.value.allowance = await tokenStore.allowance();
sacrificeStore.sacrificeState = 1;
showApprovedToast();
} catch (error) {
console.error(error);
throw new Error(error);
} finally {
sacrificeStore.sacrificeState = 0;
}
}
async function addTokens(value) {
tokenNumber.value = tokenNumber.value + value;
output.value = await memeburnerStore.getRewardsFor(
parseInt(tokenNumber.value)
);
if (!walletStore.connected || sacrificeStore.sacrificeNumber < activeWalletToken.value?.balanceOf) {
sacrificeStore.sacrificeNumber = BigInt(sacrificeStore.sacrificeNumber) + value;
} else {
sacrificeStore.sacrificeNumber = sacrificeStore.sacrificeNumber - value;
if (sacrificeStore.sacrificeNumber < 0n) {
sacrificeStore.sacrificeNumber = 0n;
}
}
const rewardValue = await sacrificeStore.getRewardsFor(sacrificeStore.sacrificeNumber, activeToken.value);
output.value = rewardValue.output;
stakingOutput.value = rewardValue.staking;
}
async function addMaxTokens() {
addOperator.value = !addOperator.value;
sacrificeStore.sacrificeNumber = activeWalletToken.value?.balanceOf;
const rewardValue = await sacrificeStore.getRewardsFor(sacrificeStore.sacrificeNumber, activeToken.value);
console.log("rewardValue", rewardValue);
output.value = rewardValue.output;
stakingOutput.value = rewardValue.staking;
}
function showApprovedToast(value, header, subheader, info) {
// Define the content object with the component, props and listeners
const content = {
component: ApprovedToast,
// Any prop can be passed, but don't expect them to be reactive
props: {
value: value,
header: header,
subheader: subheader,
info: info,
},
listeners: {
// sacrificed: showSplash,
},
};
// Render the toast and its contents
return toast(content, {
position: "top-right",
icon: false,
timeout: 5000,
closeOnClick: false,
// toastClassName: "modal-overlay",
hideProgressBar: true,
toastClassName: "approve-toast toast-card",
});
}
function showSplash() {
splashBlood.value++;
}
//call function in the store and remove icon,
async function sacrificeToken() {
console.log("activeToken.value", activeToken.value);
var result = await sacrificeStore.sacrificeToken(sacrificeStore.sacrificeNumber, activeToken.value);
if (result) {
showSplash();
}
toast.dismiss(approveToast.value);
}
async function changeActiveToken(token) {
console.log("changeActiveToken");
tokenStore.activeToken = token;
if (walletStore.connected) {
// //TODO, wenn connected, dann all diese Daten laden?
// tokenStore.activeToken.balance = await walletStore.getTokenBalance(token);
tokenStore.activeToken.allowance = Number(await tokenStore.allowance());
}
var rewards = await sacrificeStore.getRewardsFor(sacrificeStore.sacrificeNumber, token);
console.log("rewards", rewards);
output.value = rewards.output;
stakingOutput.value = rewards.staking;
}
</script>
@@ -185,8 +381,8 @@ async function addTokens(value) {
margin-left: auto
margin-right: auto
background-color: var(--primary)
.sacrifice-inner
padding: 48px 24px
padding: 24px
align-items: center
@media (min-width: 992px)
padding: 48px 64px
.sacrifice-headline
@@ -194,20 +390,21 @@ async function addTokens(value) {
font-size: 24px
margin-bottom: 32px
@media (min-width: 992px)
font-size: 36px
font-size: 32px
.sacrifice-select-tokens
display: flex
margin-bottom: 32px
width: 100%
.sacrifice-tokens
display: flex
width: 100%
justify-content: space-between
@media (min-width: 992px)
justify-content: space-evenly
flex-wrap: wrap
gap: 12px
.sacrifice-token
border-radius: 16px
padding: 12px
padding: 9px
cursor: pointer
background-color: #0F0F0F
text-align: center
@@ -215,63 +412,58 @@ async function addTokens(value) {
border: 4px solid transparent
.sacrifice-token-logo
pointer-events: none
// @media (min-width: 992px)
@media (min-width: 992px)
img
height: 100px
width: 100px
// padding: 0
// background-color: unset
&.sacrifice-token--active
border-color: var(--purple)
.sacrifice-token-name
padding: 5px 26px
font-size: 16px
@media (min-width: 992px)
font-size: 24px
padding: 5px 26px
.sacrifice-buttons-function-wrapper
text-align: center
justify-content: center
margin-top: 24px
display: block
@media (min-width: 992px)
display: flex
.btn
padding: 16px 64px
padding: 12px 48px
.sacrifice-fees-info-wrapper
display: flex
border: 2px dashed var(--grey)
border: 1px dashed var(--grey)
color: var(--grey)
border-radius: 16px
padding: 16px 24px
margin-top: 24px
font-size: 16px
padding: 12px
gap: 12px
.sacrifice-fees-img
flex: 0 0 15%
img
height: 46px
.sacrifice-fees-body
flex: 1 1 auto
display: flex
flex-direction: column
justify-content: space-between
.sacrifice-fees-body-header
display: flex
flex-direction: row
justify-content: space-between
margin-bottom: 8px
@media (min-width: 992px)
font-size: 24px
margin-bottom: 0
.sacrifice-from-to-wrapper
.sacrifice-from-wrapper,.sacrifice-to-wrapper
.sarcrifice-from-input
display: flex
margin-bottom: 8px
// height: 60px
input
flex-direction: column
gap: 16px
width: 100%
height: 45px
font-size: 24px
border-radius: 16px
padding: 0 16px
@media (min-width: 992px)
font-size: 32px
height: auto
gap: 32px
.sacrifice-from-wrapper
.sacrifice-logo
margin-left: 16px
img
@@ -280,7 +472,7 @@ async function addTokens(value) {
border-radius: 50%
pointer-events: none
@media (min-width: 992px)
height: 83px
height: 100%
width: auto
.sacrifice-to-output
flex: 1 1 auto
@@ -296,13 +488,19 @@ async function addTokens(value) {
.value-adder
display: flex
gap: 6px
flex-wrap: wrap
.sacrifice-adder-step
font-size: 14px
font-size: 12px
align-items: center
background: var(--grey, #858585)
color: var(--midnight-black, #0F0F0F)
&:hover,
&:active,
&:focus
background-color: var(--secondary)
background-color: var(--grey-light)
cursor: pointer
// @media (min-width: 992px)
// font-size: 12px
// .sacrifice-adder-balance
// margin-left: auto
// .sacrifice-adder-max
@@ -314,4 +512,40 @@ async function addTokens(value) {
// color: darken(red, 10%)
// transform: scale(1.1)
// transition: transform 0s
.sacrifice-to-wrapper
display: flex
flex-direction: column
gap: 18px
.sacrifice-to-body
display: flex
justify-content: space-between
.sacrificed-info
display: flex
padding: 8px 24px
justify-content: space-between
align-items: center
align-self: stretch
border-radius: 16px
background: var(--midnight-black, #0F0F0F)
text-align: left
.sacrifice-staking-bonus
display: flex
flex-direction: column
padding: 8px 16px
row-gap: 8px
border-radius: 10px
background: var(--midnight-black, #0F0F0F)
.sacrifice-staking-bonus-inner
display: flex
justify-content: space-between
.icon
margin-left: auto
.input-max
color: var(--grey, #858585)
font-weight: bold
&:hover, &:active, &:focus
color: var(--grey-light, #858585)
cursor: pointer
</style>
+26 -15
View File
@@ -1,7 +1,6 @@
<template>
<div class="slideout-overlay" :class="{'open': props.modelValue}" @click="$emit('update:modelValue', false)">
<div :class="{'slideout-wrapper': true, 'open': props.modelValue}" >
<div class="slideout-overlay" :class="{ open: props.modelValue }" @click="showPanel = false">
<div :class="{ 'slideout-wrapper': true, open: props.modelValue }">
<div class="slideout-panel" @click="testClick">
<slot></slot>
</div>
@@ -19,8 +18,6 @@ const props = defineProps({
defineEmits(["update:modelValue"]);
const showPanel = inject("showPanel");
console.log("showPanel.value", showPanel);
const isMobile = inject("isMobile");
function testClick(e) {
e.preventDefault();
@@ -30,29 +27,43 @@ function testClick(e) {
<style lang="sass">
.slideout-overlay
background-color: rgba(0,0,0,.5)
z-index: 100
&.open
height: 100%
width: 100%
position: fixed
background-color: rgb(15, 15, 15, 0.7)
.slideout-wrapper
z-index: 100
height: 100vh
right: 0
height: 100svh
position: fixed
display: flex
border: 1px solid rgba(152, 161, 192, 0.24)
box-shadow: rgba(0, 0, 0, 0.24) 12px 16px 24px, rgba(0, 0, 0, 0.24) 12px 8px 12px, rgba(0, 0, 0, 0.32) 4px 4px 8px
background-color: var(--midnight-black, #0F0F0F)
border-radius: 16px
transition: margin-bottom 250ms ease 0s
width: 100%
margin-bottom: -100vh
bottom: 0
overflow: auto
@media (min-width: 992px)
margin-right: -400px
transition: margin-right 250ms ease 0s
margin-right: -300px
background-color: #2D2D2D
width: auto
right: -30px
top: 0
&.open
margin-right: 0
margin-bottom: -82px
@media (min-width: 992px)
margin-right: 30px
.slideout-panel
width: 300px
width: 100%
height: 100%
padding: 24px
padding: 24px 24px 16px 24px
overflow: scroll
height: calc( 100svh - 82px )
@media (min-width: 992px)
width: 400px
overflow: unset
.slideout-icon
cursor: pointer
&:hover, &:active, &:focus
+378
View File
@@ -0,0 +1,378 @@
<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, 10n ** tokenStore.memeToken.decimals)"
></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 === 0n && !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">
Order 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="walletStore.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(walletStore.balanceOf, 10n ** tokenStore.memeToken.decimals) }}
</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 === 1">
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, 10n ** tokenStore.memeToken.decimals) }}
$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 = formatNumber(BigInt(rewardData.topics[3]), 10n ** tokenStore.memeToken.decimals);
showSuccessToast(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 = formatNumber(BigInt(rewardData.topics[3]), 10n ** tokenStore.memeToken.decimals);
showSuccessToast(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 = formatNumber(BigInt(rewardData.topics[3]), 10n ** tokenStore.memeToken.decimals);
console.log("data", data);
state.value = 0;
showSuccessToast(
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 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>
+141
View File
@@ -0,0 +1,141 @@
<template>
<div class="stake-menu">
<token-input :modelValue="props.modelValue" @input="emit('update:modelValue', Number($event.target.value))">
<template v-slot:message>
<div class="stake-adder-step bloodline-badge grey" @click="addTokensPercent(25n)">25%</div>
<div class="stake-adder-step bloodline-badge grey" @click="addTokensPercent(50n)">50%</div>
<div class="stake-adder-step bloodline-badge grey" @click="addTokensPercent(75n)">75%</div>
<div class="stake-adder-step bloodline-badge grey" @click="addTokensPercent(100n)">100%</div>
</template>
<template v-slot:message-end>
<slot name="message-end"> </slot>
</template>
</token-input>
<div class="stake-menu-actions">
<slot name="body">
<div class="input-balance">Balance: {{ walletStore.memeToken.balanceOf }}</div>
<div
class="btn btn-immortal stake-button"
@click="rewardLockerStore.stakeBloodline(tokenNumber)"
v-if="props.stake"
>
Stake
</div>
<div class="btn btn-immortal stake-button" @click="unstakeBloodline" v-else>Unstake for Next Cycle</div>
<div class="btn btn-immortal black" @click="emit('close')">Cancel</div>
</slot>
</div>
</div>
</template>
<script setup>
import { ref } from "vue";
import TokenInput from "./TokenInput.vue";
import { useWalletStoreV2 } from "@/stores/walletV2";
import { useRewardLockerStore } from "@/stores/rewardlocker";
import { useTokenStore } from "@/stores/tokens";
import { createPermitObject, getSignatureRSV } from "@/helper/blockchain.js";
import { formatNumber } from "@/helper/helper.js";
import { signTypedData } from "@wagmi/core";
const walletStore = useWalletStoreV2();
const rewardLockerStore = useRewardLockerStore();
const tokenStore = useTokenStore();
const props = defineProps({
stake: Boolean,
modelValue: [Number, BigInt],
amount: [Number, BigInt],
});
const emit = defineEmits(["close", "update:modelValue"]);
async function addTokensPercent(value) {
console.log("value", value);
console.log("props.amount", props.amount);
let amount;
if (props.amount !== undefined || props.amount !== null) {
//todo function to calculate correct bigInt value (maybe use string and split)
amount = (BigInt(props.amount) * value) / 100n;
} else if (props.stake) {
amount = (walletStore.memeToken.balanceOf * value) / 100n;
} else {
amount = (walletStore.memeToken.staked * value) / 100n;
}
console.log("amount123", amount);
amount = amount / 10n ** tokenStore.memeToken.decimals;
console.log("amount", amount);
emit("update:modelValue", amount);
}
async function unstakeBloodline() {
try {
const fromAddress = walletStore.address;
var unstakedOrdered = await rewardLockerStore.contract.read.unstakeOrdered([4, fromAddress]);
//check if states needed here
var hash = await rewardLockerStore.contract.write.orderUnstake();
console.log("hash", hash);
const data = await waitForTransaction({
hash: hash,
});
console.log("data", data);
} catch (error) {
console.error("unstakeBloodline", error);
}
}
async function stakeBloodline() {
try {
console.log("stakeBloodline");
const fromAddress = walletStore.address;
const spender = rewardLockerStore.config.contractAddress;
const deadline = Date.now() + 20 * 60;
const decimals = tokenStore.getToken(walletStore.memeToken.contractAddress).decimals;
const value = BigInt(tokenNumber.value) * 10n ** decimals;
const nonce = await tokenStore.memeToken.contract.read.nonces([fromAddress]);
const { types, message, domain, primaryType } = createPermitObject(
fromAddress,
spender,
nonce,
deadline,
value
);
const signature = await signTypedData({
domain: domain,
message: message,
primaryType: primaryType,
types: types,
});
const { r, s, v } = getSignatureRSV(signature);
var resultStake = await rewardLockerStore.contract.write.stakeToBeSecured([value, deadline, v, r, s]);
} catch (error) {
console.error("stakeBloodline", error);
}
}
</script>
<style lang="sass">
.btn
&.btn-immortal
&.stake-button
font-size: 18px
text-align: center
.input-balance
color: var(--grey, #858585)
margin-left: auto
.stake-menu
display: flex
flex-direction: column
gap: 32px
.stake-menu-actions
display: flex
flex-direction: column
gap: 8px
</style>
+322 -47
View File
@@ -1,10 +1,12 @@
<template>
<div class="claim bloodline-border">
<div class="rewards-wrapper" v-if="!isMobile">
<div class="claim bloodline-border bloodline-border__thin grey">
<div class="claim-headline sub-header">Your Cycle Rewards</div>
<!-- <div class="rewards-wrapper" v-if="!isMobile">
<rewards-wrapper
title="Sacrafice Reward"
coin="$BLOOD"
:amount="getCurrentRoundData?.rewards_sacrifice"
:amount="getCurrentCycleData?.rewards_sacrifice"
image="/assets/img/vampir.png"
/>
<div class="rewards-divider bloodline-devider">
@@ -13,38 +15,133 @@
<rewards-wrapper
title="Clan Reward"
coin="$BLOOD"
:amount="getCurrentRoundData?.rewards_clan"
:amount="getCurrentCycleData?.rewards_clan"
image="/assets/img/vampir.png"
/>
</div> -->
<div class="rewards-list">
<rewards-wrapper
title="Sacrafice Reward"
coin="$BLOOD"
:amount="formatNumber(rewardsSacrifice, 10n ** tokenStore.memeToken.decimals)"
image="/assets/img/vampir.png"
/>
<rewards-wrapper
title="Staking Bonus"
coin="$BLOOD"
:amount="formatNumber(rewardsStaking, 10n ** tokenStore.memeToken.decimals)"
image="/assets/img/vampir.png"
/>
<rewards-wrapper
title="Clan Bonus"
:subTitle="rewardsClan > 0 ? clanBonusPercentage : null"
coin="$BLOOD"
:amount="formatNumber(rewardsClan, 10n ** tokenStore.memeToken.decimals)"
:image="
activeCycle === currentCycle || !cycleStore.getCurrentCycleData?.winner.vamplogo
? '/assets/img/token/notoken.png'
: cycleStore.getCurrentCycleData?.winner.vamplogo
"
/>
</div>
<div class="rewards-total-wrapper">
<div class="rewards-total-headline sub-header">Total Reward</div>
<div
class="rewards-total-inner bloodline-border bloodline-border--variant1"
:class="{ purple: rewardsTotal > 0n && activeCycle !== currentCycle }"
>
<token-name-price
name="$BLOOD"
:price="formatNumber(rewardsTotal, 10n ** tokenStore.memeToken.decimals)"
></token-name-price>
<token-logo img="/assets/img/vampir.png" :size="64" :alt="'vampire'"></token-logo>
</div>
<div class="rewards-list" v-else>
<rewards-wrapper
title="Total Sacrafice Reward"
coin="$BLOOD"
amount="0"
image="/assets/img/vampir.png"
/>
<rewards-wrapper
title="Total Stake Reward"
coin="$BLOOD"
amount="0"
info="max: 312m"
image="/assets/img/vampir.png"
/>
<rewards-wrapper title="Clan Bonus" coin="$BLOOD" amount="0" image="/assets/img/vampir.png" />
<rewards-wrapper title="Total Reward" coin="$BLOOD" amount="0" image="/assets/img/vampir.png" />
</div>
<div class="claim-button">
<div v-if="activeRound === currentRound" class="btn btn-immortal btn--disabled">Cycle Active</div>
<div v-else-if="getCurrentRoundData?.rewards_total > 0" class="btn btn-immortal" @click="claimRewards">
<template v-if="!walletStore.connected">
<button class="btn btn-immortal sub-header" @click="showPanel = true">Connect</button>
</template>
<template v-else-if="activeCycle === currentCycle">
<template v-if="rewardsSacrifice > 0n">
<div class="stake-buttons">
<button class="btn btn-immortal sub-header btn--disabled">Claim</button>
<button class="btn btn-immortal sub-header btn--disabled">Stake</button>
</div>
<div>You can claim once the current cycle is finished and the clan bonus calculated</div>
</template>
<template v-else>
<button class="btn btn-immortal sub-header" @click="router.push({ name: 'home' })">
Sacrifice
</button>
</template>
</template>
<template v-else-if="rewardsTotal > 0">
<Transition name="smooth">
<div class="stake-buttons" v-show="!stakeMenu">
<div class="btn btn-immortal sub-header" v-if="stateClaimedComp === 0" @click="claimRewards">
Claim
</div>
<div v-else class="btn btn-immortal btn--disabled">Nothing to claim</div>
<div class="btn btn-immortal sub-header" disabled v-if="stateClaimedComp === 2">
Sign Transaction
</div>
<div class="stake-buttons">
<div class="btn btn-immortal">Stake</div>
<div class="btn btn-immortal">Unstake</div>
<div class="btn btn-immortal sub-header" disabled v-if="stateClaimedComp === 3">
<loading-component></loading-component>
</div>
<div class="btn btn-immortal sub-header" v-if="stateClaimedComp === 0" @click="openStake">
Stake
</div>
</div>
</Transition>
<Transition name="smooth">
<stake-menu
v-model="tokenNumber"
@close="stakeMenu = false"
:stake="stake"
:amount="rewardsTotal"
v-if="stakeMenu"
>
<template v-slot:body>
<div
class="btn btn-immortal sub-header stake-button"
disabled
v-if="stateStakeClaimComp === 0"
>
Enter Amount
</div>
<div
class="btn btn-immortal sub-header stake-button"
v-else-if="stateStakeClaimComp === 1"
@click="stakeAndClaim"
>
Stake & Claim Rest
</div>
<div
class="btn btn-immortal sub-header stake-button"
disabled
v-if="stateStakeClaimComp === 2"
>
Sign Transaction
</div>
<div
class="btn btn-immortal sub-header stake-button"
disabled
v-if="stateStakeClaimComp === 3"
>
<loading-component></loading-component>
</div>
<div
class="btn transparent small-text cancel-button text-center"
@click="stakeMenu = false"
>
Cancel
</div>
</template>
</stake-menu>
</Transition>
</template>
<template v-else>
<div class="btn btn-immortal btn--disabled sub-header">Nothing to claim</div>
</template>
</div>
</div>
</template>
@@ -52,48 +149,226 @@
<script setup>
import { storeToRefs } from "pinia";
import RewardsWrapper from "@/components/RewardsWrapper.vue";
import { inject, ref, onMounted } from "vue";
import { inject, ref, onMounted, computed } from "vue";
import { useRewardLockerStore } from "@/stores/rewardlocker";
import { useWalletStore } from "@/stores/wallet";
import { useRoundsStore } from "@/stores/rounds";
const clanRewards = ref(0);
const rewards = ref(0);
const isMobile = inject("isMobile");
import { useWalletStoreV2 } from "@/stores/walletV2";
import { useTokenStore } from "@/stores/tokens";
import { useCycleStore } from "@/stores/cycles";
import { useRouter } from "vue-router";
import StakeMenu from "@/components/StakeMenu.vue";
import { waitForTransaction } from "@wagmi/core";
import LoadingComponent from "@/components/LoadingComponent.vue";
import TokenNamePrice from "@/components/TokenNamePrice.vue";
import TokenLogo from "@/components/TokenLogo.vue";
import { formatNumber, formatBigIntDivision } from "@/helper/helper.js";
import { showSuccessToast } from "@/helper/toast.js";
const showPanel = inject("showPanel");
const rewardLockerStore = useRewardLockerStore();
const walletStore = useWalletStore();
const roundStore = useRoundsStore();
const { address } = storeToRefs(walletStore);
const { activeRound, currentRound, getCurrentRoundData } =
storeToRefs(roundStore);
const walletStore = useWalletStoreV2();
const tokenStore = useTokenStore();
const cycleStore = useCycleStore();
const router = useRouter();
const { activeCycle, currentCycle, getCurrentCycleData, rewardsSacrifice, rewardsStaking, rewardsClan, rewardsTotal } =
storeToRefs(cycleStore);
const stakeMenu = ref(false);
const stake = ref(null);
const tokenNumber = ref(null);
const stateClaim = ref(0);
const stateStakeClaim = ref(0);
async function stakeAndClaim() {
try {
console.log("stakeAndClaim");
console.log(tokenNumber.value);
console.log(rewardsTotal.value);
stateStakeClaim.value = 2;
console.log("hier1");
const coefficient = (10000n * BigInt(tokenNumber.value)) / rewardsTotal.value;
var hash = await rewardLockerStore.stakeAndClaimCycle(coefficient, cycleStore.activeCycle);
console.log("hier2");
stateStakeClaim.value = 3;
console.log("hash");
const data = await waitForTransaction({
hash: hash,
});
console.log("data", data);
stateStakeClaim.value = 4;
//ClaimedReward (address staker, uint256 reward)
var rewardData = data.logs.find((logObject) => {
return logObject.topics.find(
(topic) => topic === "0xd0813ff03c470dcc7baa9ce36914dc2febdfd276d639deffaac383fd3db42ba3"
);
});
var stakeData = data.logs.find((logObject) => {
return logObject.topics.find(
(topic) => topic === "0xf496bf2b14b1d178412b6f7a745900105b49b38b315cfdfbfabad31a6f995c6f"
);
});
//
console.log("rewardData", rewardData);
console.log("stakeData", stakeData);
const outputClaim = BigInt(rewardData?.topics[2]);
const outputStaked = BigInt(stakeData?.topics[3]);
showSuccessToast(
formatNumber(outputClaim + outputStaked, 10n ** tokenStore.memeToken.decimals),
"Success!",
"You just claimed and staked",
"Join the next cycle to increase your rewards and win with your clan."
);
tokenNumber.value = 0;
stakeMenu.value = false;
await walletStore.loadWalletData();
} catch (error) {
console.error("stakeAndClaim", error);
} finally {
const walletStore = useWalletStoreV2();
await walletStore.loadWalletData();
console.log("finally1");
await cycleStore.fillCycle(activeCycle.value, true);
console.log("finally2");
stateStakeClaim.value = 1;
}
}
function openStake() {
stake.value = true;
stakeMenu.value = true;
}
onMounted(async () => {});
async function claimRewards() {
console.log("getCurrentRoundData", getCurrentRoundData);
console.log("activeRound.value", activeRound.value);
var result = await rewardLockerStore.claim([activeRound.value]);
console.log("result", result);
try {
stateClaim.value = 2;
console.log("getCurrentCycleData", getCurrentCycleData);
console.log("activeCycle.value", activeCycle.value);
var hash = await rewardLockerStore.claim([activeCycle.value]);
stateClaim.value = 3;
console.log("hash", hash);
const data = await waitForTransaction({
hash: hash,
});
stateClaim.value = 4;
// ClaimedReward (address staker, uint256 reward)
var rewardData = data.logs.find((logObject) => {
return logObject.topics.find(
(topic) => topic === "0xd0813ff03c470dcc7baa9ce36914dc2febdfd276d639deffaac383fd3db42ba3"
);
});
//
console.log("rewardData", rewardData);
const outputClaim = formatNumber(BigInt(rewardData.topics[2]), 10n ** tokenStore.memeToken.decimals);
showSuccessToast(
outputClaim,
"Success!",
"You just claimed",
"Join the next cycle to increase your rewards and win with your clan."
);
await cycleStore.fillCycle(activeCycle.value, true);
await walletStore.loadWalletData();
} catch (error) {
stateClaim.value = 0;
throw Error(error);
}
}
const clanBonusPercentage = computed(() => {
return (
(
(formatBigIntDivision(rewardsClan.value, 10n ** tokenStore.memeToken.decimals, 8) /
formatBigIntDivision(rewardsTotal.value, 10n ** tokenStore.memeToken.decimals, 8)) *
100
).toFixed(2) + "%"
);
});
const stateClaimedComp = computed(() => {
let returnState = 0;
if (stateClaim.value === 2) {
returnState = 2;
} else if (stateClaim.value === 3) {
returnState = 3;
}
return returnState;
});
const stateStakeClaimComp = computed(() => {
console.log("stateStakeClaimComp");
let returnState = 0;
if (stateStakeClaim.value === 2) {
returnState = 2;
} else if (stateStakeClaim.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 ||
BigInt(tokenNumber.value) > walletStore.unclaimedRewards / 10n ** tokenStore.memeToken.decimals
) {
returnState = 0;
}
return returnState;
});
</script>
<style lang="sass">
.claim
display: flex
padding: 32px 20px
padding: 12px
flex-direction: column
gap: 16px
@media (min-width: 992px)
padding: 32px 40px
.claim-headline
text-align: left
.claim-button
text-align: center
margin: 32px 0
display: flex
flex-direction: column
gap: 24px
.stake-buttons
display: flex
text-align: center
gap: 8px
@media (min-width: 992px)
gap: 32px
div
flex: 1 1 50%
.rewards-wrapper
// div
// flex: 1 1 50%
margin-bottom: 16px
.rewards-divider
text-align: center
.rewards-total-wrapper
display: flex
flex-direction: column
gap: 8px
.rewards-total-headline
text-align: left
.rewards-total-inner
display: flex
justify-content: space-between
text-align: left
box-sizing: content-box
.rewards-left
display: flex
flex-direction: column
gap: 8px
.name
font-size: 16px
.amount
font-size: 24px
.rewards-right
img
height: 49px
width: 49px
border-radius: 50%
</style>
+90
View File
@@ -0,0 +1,90 @@
<template>
<div class="token-input">
<div class="sarcrifice-from-input">
<div class="left-side">
<input
@input="emit('update:modelValue', $event.target.value)"
:value="props.modelValue"
:placeholder="0"
type="number"
pattern="\d*"
/>
<div class="value-adder">
<slot class="value-adder" name="message"></slot>
<slot name="message-end"></slot>
</div>
</div>
<div class="right-side">
<token-logo v-if="props.logo" :img="props.logo" :alt="'vampir'"></token-logo>
</div>
</div>
</div>
</template>
<script setup>
import TokenLogo from "@/components/TokenLogo.vue";
const props = defineProps({
modelValue: [String, Number],
logo: String,
max: [BigInt, Number],
});
const emit = defineEmits(["update:modelValue"]);
</script>
<style lang="sass">
.sarcrifice-from-input
display: flex
margin-bottom: 8px
gap: 8px
.left-side
display: flex
flex-direction: column
gap: 12px
flex: 1 1 auto
input
width: 100%
height: 45px
font-size: 24px
border-radius: 16px
padding: 0 16px
&::-webkit-outer-spin-button,
&::-webkit-inner-spin-button
-webkit-appearance: none
margin: 0
&[type=number]
-moz-appearance: textfield
@media (min-width: 992px)
font-size: 24px
.value-adder
display: flex
gap: 8px
.stake-adder-step
padding: 4px 16px
color: var(--black)
font-size: 12px
border-width: 1px
border-color: transparent
border-style: solid
@media (min-width: 992px)
font-size: 14px
&:hover,&:active, &:focus
background-color: var(--grey-light)
cursor: pointer
.right-side
display: flex
flex-direction: column
height: 45px
.sacrifice-logo
margin-left: 16px
height: 45px
img
width: 45px
height: 45px
border-radius: 50%
pointer-events: none
@media (min-width: 992px)
height: 100%
width: auto
</style>
+27
View File
@@ -0,0 +1,27 @@
<template>
<div class="token-logo">
<img :src="props.img" :alt="props.alt" :style="{ height: `${size}px`, width: `${size}px` }" />
</div>
</template>
<script setup>
const props = defineProps({
img: String,
alt: String,
size: {
type: Number,
default: 45,
},
});
</script>
<style lang="sass">
.token-logo
height: 100%
img
border-radius: 50%
pointer-events: none
@media (min-width: 992px)
width: auto
height: 100%
</style>
+28
View File
@@ -0,0 +1,28 @@
<template>
<div class="token-price-wrapper">
<div class="token-name tiny-text">{{ props.name }}</div>
<div class="token-price" :class="{ 'sub-header-2': !props.variant, 'sub-header': props.variant }">
{{ props.price }}
</div>
</div>
</template>
<script setup>
const props = defineProps({
name: String,
price: [Number, String],
variant: {
type: Boolean,
required: false,
default: false,
},
});
</script>
<style lang="sass">
.token-price-wrapper
display: flex
flex-direction: column
gap: 6px
text-align: left
</style>
+53
View File
@@ -0,0 +1,53 @@
<template>
<div class="approve-card">
<div class="left-side low-mid-text">Transaction Successful</div>
</div>
</template>
<script setup>
import LoadingComponent from "@/components/LoadingComponent.vue";
import { getCurrentInstance, computed, watch, inject } from "vue";
import { useTokenStore } from "@/stores/tokens";
import { useSacrificeStore } from "@/stores/sacrifice";
import CardComponent from "@/components/CardComponent.vue";
import { useToast } from "vue-toastification";
const emit = defineEmits(["sacrificed"]);
const props = defineProps({
value: String,
header: String,
subheader: String,
info: String,
});
const toast = useToast();
const tokenStore = useTokenStore();
const sacrificeStore = useSacrificeStore();
const instance = getCurrentInstance();
const id = instance.attrs["toast-id"];
const splashBlood = inject("splashBlood");
function closeToast() {
toast.dismiss(id);
}
</script>
<style lang="sass">
.Vue-Toastification__container
.Vue-Toastification__toast--default
&.approve-toast
background: transparent
&.toast-card
padding: 24px 16px
border-radius: 10px
border: 2px solid var(--dark-purple, #4B0082)
background: var(--midnight-black, #0F0F0F)
.Vue-Toastification__toast-component-body
.approve-card
display: flex
flex-direction: row
display: flex
align-items: center
gap: 29px
</style>
+102
View File
@@ -0,0 +1,102 @@
<template>
<card-component class="modal-card">
<div class="body">
<div class="header">
<img alt="logo" class="logo" src="/assets/img/vampir.png" />
</div>
<div class="subheader toast-header">
{{ props.header }}<br />
{{ props.subheader }}
</div>
<div class="amount-number">
<div class="token-amount number-mobile">{{ props.value }}</div>
<div class="token-name">$BLOOD</div>
</div>
<div class="info toast-body">
{{ props.info }}
</div>
</div>
<div class="btn btn-immortal" @click="closeToast">Okay</div>
</card-component>
</template>
<script setup>
import { getCurrentInstance } from "vue";
import CardComponent from "@/components/CardComponent.vue";
import { useToast } from "vue-toastification";
const props = defineProps({
value: String,
header: String,
subheader: String,
info: String,
});
// element.classList.add("toast-open");
const toast = useToast();
const instance = getCurrentInstance();
instance.parent.parent.vnode.el.classList.add("toast-open");
const id = instance.attrs["toast-id"];
function closeToast() {
instance.parent.parent.vnode.el.classList.remove("toast-open");
toast.dismiss(id);
}
console.log("instance", instance.attrs["toast-id"]);
</script>
<style lang="sass">
.Vue-Toastification__container
&.toast-open
background-color: rgb(15, 15, 15, 0.7)
height: 100vh
width: 100vw
position: fixed
left: 0
bottom: 0
z-index: 10
@media (min-width: 992px)
background-color: unset
&.top-center
@media (min-width: 600px)
left: unset
margin-left: unset
.Vue-Toastification__toast
max-width: unset
min-width: unset
max-height: unset
min-height: unset
font-family: unset
margin-bottom: unset
box-shadow: unset
padding: unset
&.modal-overlay
background-color: unset
.modal-card
width: 342px
text-align: center
position: absolute
top: 50%
left: 50%
transform: translate(-50%, -50%)
border: 2px solid var(--dark-purple, #4B0082)
background: var(--midnight-black, #0F0F0F)
z-index: 100
gap: 16px
@media (min-width: 992px)
top: 142px
right: 24px
left: unset
transform: unset
.body
display: flex
flex-direction: column
gap: 8px
.amount-number
display: flex
justify-content: center
align-items: end
gap: 8px
img
width: 74px
height: 74px
</style>
@@ -0,0 +1,86 @@
<template>
<div class="network-switch-card">
<div>Please switch Network to</div>
<div>
<b>{{ props.network.chains[0].name }}</b>
</div>
</div>
</template>
<script setup>
import LoadingComponent from "@/components/LoadingComponent.vue";
import { getCurrentInstance, computed, watch, inject } from "vue";
import { useTokenStore } from "@/stores/tokens";
import { useSacrificeStore } from "@/stores/sacrifice";
import CardComponent from "@/components/CardComponent.vue";
import { useToast } from "vue-toastification";
const emit = defineEmits(["sacrificed"]);
const props = defineProps({
network: Object,
});
const toast = useToast();
const tokenStore = useTokenStore();
const sacrificeStore = useSacrificeStore();
const instance = getCurrentInstance();
const id = instance.attrs["toast-id"];
const splashBlood = inject("splashBlood");
function closeToast() {
toast.dismiss(id);
}
const stateComputed = computed(() => {
let returnState = 0;
if (
sacrificeStore.sacrificeNumber === null ||
sacrificeStore.sacrificeNumber === "" ||
sacrificeStore.sacrificeNumber === 0
) {
returnState = 0;
} else if (sacrificeStore.sacrificeState === 2) {
returnState = 2;
} else if (sacrificeStore.sacrificeState === 3) {
returnState = 3;
} else if (
sacrificeStore.sacrificeNumber !== null ||
sacrificeStore.sacrificeNumber !== "" ||
sacrificeStore.sacrificeNumber > 0
) {
returnState = 1;
}
return returnState;
});
async function sacrificeClick() {
try {
var result = await sacrificeStore.sacrificeToken(sacrificeStore.sacrificeNumber, tokenStore.activeToken);
if (result) {
emit("sacrificed");
}
} catch (error) {
console.error("error", error);
} finally {
closeToast();
}
}
</script>
<style lang="sass">
.Vue-Toastification__container
.Vue-Toastification__toast--default
&.approve-toast
background: transparent
&.toast-card
padding: 24px 16px
border-radius: 10px
border: 2px solid var(--dark-purple, #4B0082)
background: var(--midnight-black, #0F0F0F)
.Vue-Toastification__toast-component-body
.network-switch-card
display: flex
flex-direction: column
display: flex
</style>
+72
View File
@@ -0,0 +1,72 @@
import { useTokenStore } from "@/stores/tokens";
export function createPermitObject(fromAddress, spender, nonce, deadline, value) {
const tokenStore = useTokenStore();
const message = {
owner: fromAddress,
spender: spender,
nonce: nonce,
deadline: deadline,
value: value,
};
const domainType = [
{ name: "name", type: "string" },
{ name: "version", type: "string" },
{ name: "chainId", type: "uint256" },
{ name: "verifyingContract", type: "address" },
];
const primaryType = "Permit";
const types = {
EIP712Domain: domainType,
Permit: [
{
name: "owner",
type: "address",
},
{
name: "spender",
type: "address",
},
{
name: "value",
type: "uint256",
},
{
name: "nonce",
type: "uint256",
},
{
name: "deadline",
type: "uint256",
},
],
}
const domain = {
name: "Bloodline",
version: "1",
chainId: 5,
verifyingContract: tokenStore.memeToken.contractAddress,
};
return {
types,
message,
domain,
primaryType,
};
}
export function getSignatureRSV(sig) {
// splits the signature to r, s, and v values.
// const pureSig = sig.replace("0x", "");
const r = sig.slice(0, 66);
const s = "0x" + sig.slice(66, 130);
const v = Number("0x" + sig.slice(130, 132));
return { v, r, s };
};
+72 -9
View File
@@ -1,18 +1,81 @@
export function getImageUrl(url) {
return new URL(url, import.meta.url).href;
}
export function getPercentage(amount, goal) {
console.log("amount", amount);
console.log("goal", goal);
return ((amount / goal) * 100).toFixed(2);
return ((Number(amount) / Number(goal)) * 100).toFixed(2);
}
export function compactNumber(number) {
return Intl.NumberFormat("en-US", {
notation: "compact",
maximumFractionDigits: 2,
}).format(parseInt(number));
}).format(number);
}
export function formatNumber(nominator, denominator) {
let number = formatBigIntDivision(nominator, denominator);
number = InsertCommaNumber(number).toString();
return number;
}
export function formatBigIntDivision(nominator, denominator, digits = 2) {
console.log("nominator", nominator);
console.log("denominator", denominator);
if (!nominator) {
return 0n
}
let integer = Number(nominator / denominator);
// pick how much digits after point to show
const fraction = (nominator % denominator).toString().substring(0, digits);
// output type number
return Number(integer + "." + fraction);
}
export function InsertCommaNumber(number) {
if (!number) {
return 0
}
const formattedWithOptions = number.toLocaleString("en-US");
return formattedWithOptions;
}
export function getAddressShortName(address) {
// const address = "0x66422602B2f4885c57EE794174f98d9E4DDBBBC6";
const addressBegin = address.substring(0, 6);
const addressEnd = address.substring(address.length - 4, address.length)
return addressBegin + "..." + addressEnd;
}
export function getblocky(address) {
var blockiesData = blockies
.create({
seed: address.toLowerCase(),
size: 8,
scale: 4,
})
.toDataURL();
return blockiesData;
}
export function debounce(func, timeout = 300) {
let timer;
return (...args) => {
clearTimeout(timer);
timer = setTimeout(() => {
return func.apply(this, args);
}, timeout);
};
}
export function createDebounce() {
let timeout = null;
return function (fnc, delayMs) {
clearTimeout(timeout);
timeout = setTimeout(() => {
fnc();
}, delayMs || 500);
};
}
+32
View File
@@ -0,0 +1,32 @@
import StakeSuccessToast from "@/components/toasts/StakeSuccessToast.vue";
import { useToast } from "vue-toastification";
const toast = useToast();
export function showSuccessToast(value, header, subheader, info) {
// Define the content object with the component, props and listeners
const content = {
component: StakeSuccessToast,
// Any prop can be passed, but don't expect them to be reactive
props: {
value: value,
header: header,
subheader: subheader,
info: info,
},
// Listen and react to events using callbacks. In this case we listen for
// the "click" event emitted when clicking the toast button
listeners: {},
};
// Render the toast and its contents
toast(content, {
position: "top-center",
icon: false,
closeOnClick: false,
toastClassName: "modal-overlay",
closeButton: false,
hideProgressBar: true,
timeout: false,
});
}
+230 -2
View File
@@ -1,9 +1,33 @@
import './assets/sass/main.sass'
import { useWalletStoreV2 } from "@/stores/walletV2";
import { useTokenStore } from "@/stores/tokens";
import { useMemeburnerStore } from "@/stores/memeburner";
import { useRewardLockerStore } from "@/stores/rewardlocker";
import { useUniswapStore } from "@/stores/uniswap";
import { useCycleStore } from "@/stores/cycles";
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import piniaPluginPersistedstate from "pinia-plugin-persistedstate";
import {
createConfig,
configureChains,
getNetwork,
watchAccount,
watchContractEvent,
watchNetwork,
getWalletClient,
} from "@wagmi/core";
import { WalletConnectConnector } from "@wagmi/core/connectors/walletConnect";
import { MetaMaskConnector } from "@wagmi/core/connectors/metaMask";
import { CoinbaseWalletConnector } from "@wagmi/core/connectors/coinbaseWallet";
import { InjectedConnector } from "@wagmi/core/connectors/injected";
import { goerli, mainnet } from "@wagmi/core/chains";
import { publicProvider } from "@wagmi/core/providers/public";
import { alchemyProvider } from "@wagmi/core/providers/alchemy";
import App from './App.vue'
import router from './router'
@@ -14,13 +38,20 @@ import { library } from '@fortawesome/fontawesome-svg-core'
import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'
/* import specific icons */
import { faArrowDown, faSpinner ,faPlus, faCaretLeft, faCaretRight, faBars, faAnglesRight } from "@fortawesome/free-solid-svg-icons";
import { faArrowDown, faArrowRight, faSpinner, faPlus, faCaretLeft, faCaretRight, faBars, faAnglesRight, faChevronDown, faChevronUp, faArrowRightToBracket, faArrowRightFromBracket, faDroplet, faMoon, faPerson, faWallet, faBlog } from "@fortawesome/free-solid-svg-icons";
import { faDiscord, faTwitter, faTelegram } from "@fortawesome/free-brands-svg-icons";
import Toast from "vue-toastification";
// Import the CSS or use your own!
import "vue-toastification/dist/index.css";
import SwitchNetworkToast from "@/components/toasts/SwitchNetworkToast.vue";
import { useToast } from "vue-toastification";
/* add icons to the library */
library.add(
faArrowDown,
faArrowRight,
faDiscord,
faTwitter,
faTelegram,
@@ -29,16 +60,213 @@ library.add(
faCaretLeft,
faCaretRight,
faBars,
faAnglesRight
faAnglesRight,
faArrowRightToBracket,
faArrowRightFromBracket,
faChevronDown,
faChevronUp,
faDroplet,
faMoon,
faPerson,
faWallet,
faBlog
);
var logging = localStorage.getItem("LOGGING");
if (logging === "true") {
} else {
if (!window.console) window.console = {};
var methods = ["log", "debug", "warn", "info"];
for (let i = 0; i < methods.length; i++) {
console[methods[i]] = function () {};
}
}
const app = createApp(App)
const pinia = createPinia();
pinia.use(piniaPluginPersistedstate);
app.use(pinia);
app.use(Toast, {
transition: "Vue-Toastification__fade",
containerClassName: "bloodline-toast-container",
});
function showSwitchNetworkToast(network) {
const toast = useToast();
// Define the content object with the component, props and listeners
const content = {
component: SwitchNetworkToast,
// Any prop can be passed, but don't expect them to be reactive
props: {
network
},
// Listen and react to events using callbacks. In this case we listen for
// the "click" event emitted when clicking the toast button
listeners: {},
};
// Render the toast and its contents
return toast(content, {
position: "top-right",
icon: false,
closeOnClick: false,
// toastClassName: "modal-overlay",
hideProgressBar: true,
timeout: false,
toastClassName: "approve-toast toast-card",
});
}
try {
const walletStore = useWalletStoreV2();
const tokenStore = useTokenStore();
const memeBurnerStore = useMemeburnerStore();
const rewardLockerStore = useRewardLockerStore();
const cycleStore = useCycleStore();
const uniswapStore = useUniswapStore();
const goerliKey = import.meta.env.VITE_GOERLI_KEY;
const projectId = "d8e5ecb0353c02e21d4c0867d4473ac5";
console.log("hier chains");
const { chains, publicClient, webSocketPublicClient } = configureChains(
// [goerli, mainnet],
[goerli],
[alchemyProvider({ apiKey: goerliKey }), publicProvider()]
);
walletStore.config = createConfig({
autoConnect: true,
connectors: [
new CoinbaseWalletConnector({
chains,
options: {
appName: "wagmi demo",
},
}),
// new MetaMaskConnector({ chains }),
new InjectedConnector({
chains,
getProvider: () => (typeof window !== "undefined" ? window.myInjectedWallet : undefined),
}),
new WalletConnectConnector({
chains,
options: {
projectId: projectId,
showQrModal: true,
metadata: {
name: "Bloodline-App",
description: "TODO Bloodline Description",
url: "https://gitea.loseyourip.com/",
icons: ["https://gitea.loseyourip.com/assets/img/vampir.png"],
},
},
}),
],
publicClient,
webSocketPublicClient,
});
walletStore.publicClient = publicClient;
watchContractEvent(
{
address: memeBurnerStore.config.contractAddress,
abi: memeBurnerStore.config.abi,
eventName: "MemeSacrificed",
},
async (log) => {
console.log("memeSacrificedEvent", log);
const token = log[0].args.sacrificedToken;
await cycleStore.updateCurrentCycle(token);
}
);
watchContractEvent(
{
address: rewardLockerStore.config.contractAddress,
abi: rewardLockerStore.config.abi,
eventName: "CycleCompleted",
},
async (log) => {
console.log("CycleCompleted", log);
await cycleStore.fillCycle(cycleStore.currentCycle, true);
cycleStore.currentCycle++;
await cycleStore.fillCycle(cycleStore.currentCycle, true);
}
);
watchAccount(async (account) => {
console.log("watchAccount", account);
// {chainId: }
if (account.address) {
walletStore.address = account.address;
walletStore.connected = true;
let chainObject = walletStore.chain;
if (!walletStore.chain) {
const { chain, chains } = getNetwork();
chainObject = chain;
}
var walletClient = await getWalletClient({
account: account.address,
chainId: chainObject.id,
});
walletStore.walletClient = walletClient;
await memeBurnerStore.init();
await tokenStore.initV2();
await rewardLockerStore.init();
await walletStore.loadWalletData();
await cycleStore.fillCycle(cycleStore.currentCycle, true);
await uniswapStore.init();
} else {
walletStore.address = null;
walletStore.connected = false;
walletStore.walletClient = null;
}
});
watchNetwork((network) => {
if (!network.chain?.network) {
return;
}
const chainAllowed = network.chains?.find((obj) => {
return obj.network === network.chain.network;
});
if (!chainAllowed) {
console.log("chain not allowed", network.chain);
showSwitchNetworkToast(network);
return
} else {
console.log("chain allowed", network.chain);
}
if (network.chain) {
walletStore.chain = network.chain;
}
});
await walletStore.init();
await tokenStore.initV2();
await memeBurnerStore.init();
await rewardLockerStore.init();
await memeBurnerStore.init();
} catch (error) {
console.error("main-init", error)
}
app.use(router)
app.component('font-awesome-icon', FontAwesomeIcon)
app.mount('#app')
View File
+32 -5
View File
@@ -1,5 +1,7 @@
import { createRouter, createWebHistory } from 'vue-router'
import HomeView from '../views/HomeView.vue'
import { useWalletStoreV2 } from "@/stores/walletV2";
const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
@@ -22,17 +24,42 @@ const router = createRouter({
name: "Test",
component: () => import("../views/TestView.vue"),
},
{
path: "/walletconnect",
name: "WalletConnect",
component: () => import("../views/WalletConnectView.vue"),
},
{
path: "/wagmi",
name: "Wagmi",
component: () => import("../views/WagmiView.vue"),
},
{
path: "/profile",
name: "profile",
meta: {
middleware: ["connected"],
},
component: () => import("../views/ProfileView.vue"),
},
{
path: "/cycle",
name: "cycle",
meta: {
middleware: ["connected"],
},
component: () => import("../views/CycleView.vue"),
},
],
});
router.beforeEach(async (to, from) => {
//init
const walletStore = useWalletStoreV2();
//middleware
// if (to.meta.middleware) {
// if (!walletStore.connected) {
// return '/';
// }
// }
return true;
});
export default router
-12
View File
@@ -1,12 +0,0 @@
import { defineStore } from "pinia";
export const useContractStore = defineStore("contracts", {
state: () => ({
list: {
}
}),
getters: {
},
actions: {
}
});
+230
View File
@@ -0,0 +1,230 @@
import { defineStore } from "pinia";
import { useMemeburnerStore } from "./memeburner";
import { useTokenStore } from "./tokens";
import { useRewardLockerStore } from "./rewardlocker";
import { useWalletStoreV2 } from "./walletV2";
import { multicall } from "@wagmi/core";
export const useCycleStore = defineStore("cycles", {
state: () => ({
cycles: [],
activeCycle: null,
currentCycle: null,
}),
getters: {
//cycle winner is the token who reached the goal
//todo winner is now in the cycle object, no reason for that function anymore
getCycleWinner() {
const goal = this.getCurrentCycleData?.goal;
if (!goal) {
return;
}
const winnerCoin = this.cycles[this.activeCycle]?.token.find((token) => token.amount === goal);
if (winnerCoin) {
return winnerCoin;
} else {
return false;
}
},
getCurrentCycleData() {
return this.cycles[this.activeCycle];
},
rewardsSacrifice() {
const tokenStore = useTokenStore();
if (!this.cycles[this.activeCycle]?.rewards_sacrifice) {
return 0n;
}
return this.cycles[this.activeCycle]?.rewards_sacrifice;
},
rewardsSacrificeCurrentCycle() {
const tokenStore = useTokenStore();
if (!this.cycles[this.currentCycle]?.rewards_sacrifice) {
return 0n;
}
return this.cycles[this.currentCycle]?.rewards_sacrifice;
},
rewardsStaking() {
const tokenStore = useTokenStore();
if (!this.cycles[this.activeCycle]?.rewards_staking) {
return 0n;
}
return this.cycles[this.activeCycle]?.rewards_staking;
},
rewardsClan() {
const tokenStore = useTokenStore();
if (!this.cycles[this.activeCycle]?.rewards_clan) {
return 0n;
}
return this.cycles[this.activeCycle]?.rewards_clan;
},
rewardsTotal() {
const tokenStore = useTokenStore();
if (!this.cycles[this.activeCycle]?.rewards_total) {
return 0n;
}
return this.cycles[this.activeCycle]?.rewards_total;
},
},
actions: {
//todo check if still needed
// async loadRewardsCycles() {
// const walletStore = useWalletStoreV2();
// const rewardLockerStore = useRewardLockerStore();
// console.log("this.currentCycle", this.currentCycle);
// const contracts = [];
// for (let index = 0; index < this.currentCycle; index++) {
// console.log("load cycle: " + index);
// console.log({ index, address: walletStore.address });
// contracts.push({
// ...rewardLockerStore.contract,
// functionName: "getTotalRewardsOf",
// args: [walletStore.address, [index + 1]],
// });
// }
// const data = await multicall({
// contracts,
// });
// for (let index = 0; index < data.length; index++) {
// const element = data[index];
// if (!this.cycles[index]) {
// this.cycles[index] = {};
// }
// }
// },
//todo check if needed, or use fillcycle
async updateCurrentCycle(sacrificedToken) {
console.log("updateCurrentCycle");
const memeBurnerStore = useMemeburnerStore();
const rewardLockerStore = useRewardLockerStore();
var data = await memeBurnerStore.getSacrificedCycle(this.currentCycle);
var tokenTotalSacrificed = await rewardLockerStore.getTotalSacrificeRewardsForAllToken(this.currentCycle);
console.log("this.currentCycle", this.currentCycle);
console.log("this.cycles", this.cycles);
if (this.cycles[this.currentCycle]) {
var tokenIndex = this.cycles[this.currentCycle].token.findIndex(
(tokenData) => tokenData.contractAddress === sacrificedToken
);
this.cycles[this.currentCycle].token[tokenIndex].amount = data[tokenIndex].result[1];
this.cycles[this.currentCycle].token[tokenIndex].amountInBLD = tokenTotalSacrificed[tokenIndex].result;
}
},
/**
* main function to fill a round, will not be filled when already loaded
* you can use the refillcycle to overwrite information, because if you claim or stake the values will change
*/
async fillCycle(cycleNumber, refillCycle = false) {
console.log("fillCycle", cycleNumber);
const memeBurnerStore = useMemeburnerStore();
const tokenStore = useTokenStore();
const walletStore = useWalletStoreV2();
const rewardLockerStore = useRewardLockerStore();
if (!this.cycles[cycleNumber]?.goal || refillCycle || !this.cycles[cycleNumber]?.connected) {
console.log("fill cycle");
//multicall getSacrificedMeme for each token for this cycle
var data = await memeBurnerStore.getSacrificedCycle(cycleNumber);
let rewardData = null;
if (walletStore.connected) {
//getRewards multicall for all tokens
rewardData = await rewardLockerStore.getRewardsForAllToken(cycleNumber);
}
console.log("hier");
//getTotalSacrificeRewardsForToken multicall for all tokens
const tokenTotalSacrificed = await rewardLockerStore.getTotalSacrificeRewardsForAllToken(cycleNumber);
console.log("hier1");
var goal = await memeBurnerStore.getGoal(cycleNumber);
console.log("hier123");
var tokenArray = [];
var rewards_clan = 0n;
var rewards_sacrifice = 0n;
var rewards_staking = 0n;
console.log("hier123");
for (let index = 0; index < data.length; index++) {
var tokenData = {};
const token = tokenStore.token[index];
//why no multicall? todo
var coefficent = await rewardLockerStore.getSacrificedTokenCoefficient(
cycleNumber,
token.contractAddress
);
console.log("coefficent", coefficent);
tokenData.name = token.name;
tokenData.contractAddress = token.contractAddress;
tokenData.vamplogo = token.vamp.logo;
tokenData.vampwinner = token.vamp.winner;
tokenData.vampwinner2 = token.vamp.winner2;
tokenData.vampname = token.vamp.name;
tokenData.amount = data[index].result[1];
tokenData.amountInBLD = tokenTotalSacrificed[index].result;
if (walletStore.connected) {
//if user is connected fill user specific data for the token
const sacrificeClanReward = rewardData[index].result[1];
let clanwin = 0n;
if (cycleNumber !== this.currentCycle) {
clanwin = (sacrificeClanReward * coefficent) / 10000n - sacrificeClanReward;
console.log("clanwin", clanwin);
}
const sacrificeRewards = sacrificeClanReward;
tokenData.rewards_ges = rewardData[index].result[1] + rewardData[index].result[0];
tokenData.rewards_clan = clanwin;
tokenData.rewards_staking = rewardData[index].result[0];
tokenData.rewards_sacrifice = sacrificeRewards;
console.log("rewards_clan", rewards_clan);
console.log("tokenData.rewards_clan", tokenData.rewards_clan);
console.log("tokenData.rewards_sacrifice", tokenData.rewards_sacrifice);
rewards_clan = rewards_clan + tokenData.rewards_clan;
rewards_sacrifice = rewards_sacrifice + tokenData.rewards_sacrifice;
rewards_staking = rewards_staking + tokenData.rewards_staking;
}
tokenArray.push(tokenData);
}
const goalDecimal = goal[0];
const winner = tokenArray.find((token) => token.amount === goalDecimal);
const goalInBLD = await memeBurnerStore.getGoalInBLOOD(cycleNumber);
//replace vamplogo cause it will automatically change the token for the cycle view (new design)
// if (winner) {
// winner.vamplogo = winner.vampwinner;
// }
this.cycles[cycleNumber] = {
goal: goal[0],
goalInBLD: goalInBLD,
expirationTimestamp: goal[2],
rewards_clan: rewards_clan,
rewards_staking: rewards_staking,
rewards_sacrifice: rewards_sacrifice,
rewards_total: rewards_clan + rewards_sacrifice + rewards_staking,
token: tokenArray,
connected: walletStore.connected,
winner: winner,
};
console.log("this.cycles[cycleNumber]", this.cycles[cycleNumber]);
} else {
console.log("cycle already filled");
}
},
async getFinshedCycleNumbers() {
const array = [];
const rewardLockerStore = useRewardLockerStore();
const lastCompletedCycle = await rewardLockerStore.lastCompletedCycle();
for (let index = 1; index <= Number(lastCompletedCycle); index++) {
array.push(index);
}
console.log("array123", array);
return array;
},
},
});
+75 -63
View File
@@ -1,83 +1,77 @@
import { defineStore } from "pinia";
import MemeBurnerJson from "@/assets/contracts/MemeBurner.json";
import MemeAltarJson from "@/assets/contracts/MemeAltar.json";
import { useTokenStore } from "./tokens";
import { useMultiCallStore } from "./multicall";
import { useWalletStore } from "./wallet";
import { useRoundsStore } from "@/stores/rounds";
import { useWalletStoreV2 } from "./walletV2";
import { useCycleStore } from "@/stores/cycles";
import { multicall, getContract, fetchToken, waitForTransaction, getWalletClient } from "@wagmi/core";
export const useMemeburnerStore = defineStore("memeburner", {
state: () => ({
config: MemeBurnerJson,
config: MemeAltarJson,
contract: null,
loading: false,
}),
getters: {},
actions: {
async init() {
console.log("-----------init memeburner-------------");
const walletStore = useWalletStore();
const roundsStore = useRoundsStore();
this.contract = new walletStore.web3.eth.Contract(this.config.abi, this.config.contractAddress);
const websocketMemeBurner = new walletStore.web3socket.eth.Contract(
this.config.abi,
this.config.contractAddress
);
websocketMemeBurner.events
.MemeSacrificed()
.on("data", async (event) => {
console.log("sacrificedAmount", event.returnValues.sacrificedAmount);
console.log("sacrificedToken", event.returnValues.sacrificedToken);
await roundsStore.updateCurrentRound(
event.returnValues.sacrificedToken,
event.returnValues.sacrificedAmount
);
})
.on("error", (error) => console.log("MemeSacrificederror", error));
const walletStore = useWalletStoreV2();
// const cycleStore = useCycleStore();
console.log("walletStore.walletClient", walletStore.walletClient);
this.contract = getContract({
address: this.config.contractAddress,
abi: this.config.abi,
walletClient: walletStore.walletClient || walletStore.publicClient,
});
console.log("this.contract", this.contract);
},
async getRewardsFor(amount) {
async getRewardFor(amount) {
const tokenStore = useTokenStore();
var rewards = await this.contract.methods
.getRewardFor(tokenStore.activeToken.contractAddress, amount)
.call();
const rewards = await this.contract.read.getRewardForSacrifice([
tokenStore.activeToken.contractAddress,
amount,
]);
console.log("amount", amount);
console.log("rewards", rewards);
return rewards;
},
async getCurrentRound() {
return await this.contract.methods.currentRound().call();
async getCurrentCycle() {
return await this.contract.read.currentCycle();
},
async getGoal(roundnumber) {
return await this.contract.methods.rounds(roundnumber).call();
async getGoal(cycleNumber) {
console.log("hier123", cycleNumber);
return await this.contract.read.cycles([cycleNumber]);
},
//returns participated, amount achieved
async getSacrificedMeme(roundnumber, tokenAddress) {
return await this.contract.methods.getSacrificedMeme(roundnumber, tokenAddress).call();
async getSacrificedMeme(cycleNumber, tokenAddress) {
return await this.contract.read.getSacrificedMeme([cycleNumber, tokenAddress]);
},
async getAmountToReachGoal(tokenAddress) {
return await this.contract.methods.getAmountToReachGoal(tokenAddress).call();
return await this.contract.read.getAmountToReachGoal([tokenAddress]);
},
async getSacrificedRound(roundnumber) {
console.log("getSacrificedRound", roundnumber);
async getSacrificedCycle(cycleNumber) {
console.log("getSacrificedCycle", cycleNumber);
const tokenStore = useTokenStore();
const calls = [];
// const calls1 = [];
for (let index = 0; index < tokenStore.token.length; index++) {
const token = tokenStore.token[index];
console.log("token.contractAddress", token.contractAddress);
console.log("roundnumber", roundnumber);
var test = await this.getSacrificedMeme(roundnumber, token.contractAddress);
console.log(token.name, test);
calls.push(this.contract.methods.getSacrificedMeme(roundnumber, token.contractAddress));
// calls1.push(this.contract.methods.getAmountToReachGoal(token.contractAddress));
const contracts = [];
for (let index = 0; index < tokenStore.sacrificeToken.length; index++) {
const token = tokenStore.sacrificeToken[index];
contracts.push({
...this.contract,
functionName: "getSacrificedMeme",
args: [cycleNumber, token.contractAddress],
});
}
console.log("this.contract", this.contract);
const multicallStore = useMultiCallStore();
return await multicallStore.aggregate(calls);
// console.log("this.contract", this.contract);
// const multicallStore = useMultiCallStore();
// return await multicallStore.aggregate(calls);
const data = await multicall({
contracts,
});
return data;
},
async sacrificeMeme(amount) {
const walletStore = useWalletStore();
async sacrificeMeme(amount, minETH) {
const tokenStore = useTokenStore();
try {
if (!amount || amount == 0) {
@@ -86,20 +80,38 @@ export const useMemeburnerStore = defineStore("memeburner", {
return;
}
this.loading = true;
const amountDecimal = BigInt(amount * Math.pow(10, tokenStore.activeToken.decimals));
var reward = await this.contract.methods
.sacrificeMeme(tokenStore.activeToken.contractAddress, amountDecimal)
.send({ from: walletStore.address });
console.log("reward", reward);
tokenStore.activeToken.allowance = await tokenStore.allowance();
var hash = await this.contract.write.sacrificeMeme([
tokenStore.activeToken.contractAddress,
amount,
minETH
]);
return hash;
} catch (error) {
console.error(error);
throw new Error(error);
} finally {
this.loading = false;
}
},
async getGoalInBLD(roundNumber) {
return await this.contract.methods.getGoalInBLD(roundNumber).call();
async sacrificeMemeAndBuyBLOOD(amount, minBLOOD) {
const tokenStore = useTokenStore();
var hash = await this.contract.write.sacrificeMemeAndBuyBLOOD([
tokenStore.activeToken.contractAddress,
amount,
minBLOOD,
]);
return hash;
},
async getGoalInBLOOD(cycleNumber) {
return await this.contract.read.getGoalInBLOOD([cycleNumber]);
},
async getAmountETHBase(amount) {
console.log("getAmountETHBase");
const tokenStore = useTokenStore();
return await this.contract.read.getAmountETHBase([tokenStore.activeToken.contract.address, amount, true]);
}
},
-49
View File
@@ -1,49 +0,0 @@
import { defineStore } from "pinia";
import MulticallJson from "@/assets/contracts/Multicall.json";
import { useWalletStore } from "./wallet";
export const useMultiCallStore = defineStore("multicall", {
state: () => ({
config: MulticallJson,
contract: null,
}),
getters: {},
actions: {
async init() {
console.log("-----------init multicall-------------");
const walletStore = useWalletStore();
this.contract = new walletStore.web3.eth.Contract(
this.config.abi,
this.config.contractAddress
);
},
async aggregate(calls, parameters = {}) {
const callRequests = calls.map((call) => {
const callData = call.encodeABI();
return {
target: call._parent._address,
callData,
};
});
const { returnData } = await this.contract.methods.aggregate(callRequests).call(parameters);
return returnData.map((hex, index) => {
const types = calls[index]._method.outputs.map((o) =>
o.internalType !== o.type && o.internalType !== undefined ? o : o.type
);
const walletStore = useWalletStore();
let result = walletStore.web3.eth.abi.decodeParameters(types, hex);
delete result.__length__;
result = Object.values(result);
return result.length === 1 ? result[0] : result;
});
}
}
}
);
+172 -34
View File
@@ -1,9 +1,11 @@
import { defineStore } from "pinia";
import RewardLockerJson from "@/assets/contracts/RewardLocker.json";
import { useTokenStore } from "./tokens";
import { useMultiCallStore } from "./multicall";
import { useWalletStore } from "./wallet";
import { ethers } from "ethers";
import { useWalletStoreV2 } from "./walletV2";
import { useCycleStore } from "@/stores/cycles";
import { createPermitObject, getSignatureRSV } from "@/helper/blockchain.js";
import { multicall, getContract, signTypedData, getAccount, waitForTransaction } from "@wagmi/core";
export const useRewardLockerStore = defineStore("rewardlocker", {
state: () => ({
@@ -15,47 +17,183 @@ export const useRewardLockerStore = defineStore("rewardlocker", {
actions: {
async init() {
console.log("-----------init rewardlocker-------------");
const walletStore = useWalletStore();
this.contract = new walletStore.web3.eth.Contract(this.config.abi, this.config.contractAddress);
const walletStore = useWalletStoreV2();
this.contract = getContract({
address: this.config.contractAddress,
abi: this.config.abi,
walletClient: walletStore.walletClient || walletStore.publicClient,
});
},
/*
* @param {*} walletAddress
* @param {*} roundNumber
* @param {*} cycleNumber
* @param {*} tokenAddress
* @returns Rewards for specific token and specific round
* @returns Rewards for specific token and specific cycle
*/
async getRewards(walletAddress, roundNumber, tokenAddress) {
return await this.contract.methods.rewards(walletAddress, roundNumber, tokenAddress).call();
async getRewards(walletAddress, cycleNumber, tokenAddress) {
try {
return await this.contract.read.getRewards([walletAddress, cycleNumber, tokenAddress]);
} catch (error) {
console.error("getRewards", error);
}
},
async getRewardsForAllToken(roundNumber) {
async getRewardsForAllToken(cycleNumber) {
console.log("getRewardsForAllToken");
const tokenStore = useTokenStore();
const walletStore = useWalletStore();
const calls = [];
for (let index = 0; index < tokenStore.token.length; index++) {
const token = tokenStore.token[index];
calls.push(this.contract.methods.rewards(walletStore.address, roundNumber, token.contractAddress));
const walletStore = useWalletStoreV2();
const contracts = [];
for (let index = 0; index < tokenStore.sacrificeToken.length; index++) {
const token = tokenStore.sacrificeToken[index];
// calls.push(this.contract.methods.rewards(walletStore.address, cycleNumber, token.contractAddress));
contracts.push({
...this.contract,
functionName: "getRewards",
args: [walletStore.address, cycleNumber, token.contractAddress],
});
}
const multicallStore = useMultiCallStore();
return await multicallStore.aggregate(calls);
const data = await multicall({
contracts,
});
return data;
},
async getSacrificedTokenCoefficient(roundNumber, sacrificedToken) {
return await this.contract.methods.getSacrificedTokenCoefficient(roundNumber, sacrificedToken).call();
},
async lastCompletedRound() {
return await this.contract.methods.lastCompletedRound().call();
},
async claim(round) {
const walletStore = useWalletStore();
// return await this.contract.methods.claim(round).call();
console.log(this.contract.methods.claim(round));
return await this.contract.methods.claim(round).send({from: walletStore.address, to: this.contractAddress});
},
async getTotalRewardsOf(address, rounds) {
return await this.contract.methods.getTotalRewardsOf(address, rounds).call();
},
async stakeToBeSecured(amount, deadline, v, r, s) {
return await this.contract.methods.stakeToBeSecured(amount, deadline, v,r,s)
async getTotalSacrificeRewardsForAllToken(cycleNumber) {
try {
const tokenStore = useTokenStore();
const contracts = [];
for (let index = 0; index < tokenStore.sacrificeToken.length; index++) {
const token = tokenStore.sacrificeToken[index];
contracts.push({
...this.contract,
functionName: "getTotalSacrificeRewardsForToken",
args: [cycleNumber, token.contractAddress],
});
}
const data = await multicall({
contracts,
});
// const multicallStore = useMultiCallStore();
return data;
} catch (error) {
throw new Error(error);
}
},
async getSacrificedTokenCoefficient(cycleNumber, sacrificedToken) {
return await this.contract.read.getSacrificedTokenCoefficient([cycleNumber, sacrificedToken]);
},
async getStakeRewardForSacrificeReward(sacrificedToken, reward) {
const walletStore = useWalletStoreV2();
const cycleStore = useCycleStore();
return await this.contract.read.getStakeRewardForSacrificeReward([
walletStore.address,
sacrificedToken,
reward,
]);
},
async lastCompletedCycle() {
return await this.contract.read.lastCompletedCycle();
},
async claim(cycle) {
console.log("claim");
return await this.contract.write.claim([cycle]);
},
async claimAll() {
console.log("claimAll");
const cycleStore = useCycleStore();
const account = getAccount();
console.log("acocunt", account);
const cycles = await cycleStore.getFinshedCycleNumbers();
return await this.contract.write.claim([cycles]);
},
async getTotalRewardsOf(address, cycles) {
return await this.contract.read.getTotalRewardsOf([address, cycles]);
},
async getTotalRewards(address) {
const cycleStore = useCycleStore();
const cycles = await cycleStore.getFinshedCycleNumbers();
return await this.contract.read.getTotalRewardsOf([address, cycles]);
},
async getStaked(address) {
return await this.contract.read.staked([address]);
},
async orderUnstake() {
return await this.contract.write.orderUnstake();
},
async unstake() {
const walletStore = useWalletStoreV2();
const cycleStore = useCycleStore();
var cycleList = walletStore.memeToken.orderedUnstakedCycles.findIndex((obj) => obj.result > 0n);
if (cycleList && cycleList + 1 <= cycleStore.currentCycle) {
console.log("cycleList", cycleList);
const hash = await this.contract.write.unstake([cycleList + 1]);
return hash;
}
},
async stakeBloodline(tokenNumber) {
console.log("tokenNumber", tokenNumber);
const walletStore = useWalletStoreV2();
const tokenStore = useTokenStore();
const fromAddress = walletStore.address;
const spender = this.config.contractAddress;
const deadline = BigInt(Date.now()) / 1000n + 1200n;
const decimals = tokenStore.getToken(walletStore.memeToken.contractAddress).decimals;
const value = BigInt(tokenNumber) * 10n ** decimals;
const nonce = await tokenStore.memeToken.contract.read.nonces([fromAddress]);
console.log("nonce", nonce);
const { types, message, domain, primaryType } = createPermitObject(
fromAddress,
spender,
nonce,
deadline,
value
);
const signature = await signTypedData({
domain: domain,
message: message,
primaryType: primaryType,
types: types,
});
const { r, s, v } = getSignatureRSV(signature);
console.log("value, deadline, v, r, s", value, deadline, v, r, s);
const hash = await this.contract.write.stakeToBeSecured([value, deadline, v, r, s]);
return hash;
},
async stakeAndClaimCycle(stakeCoefficient, cycle) {
// stakeCoefficient 25% = 2500, 50% = 5000
const tokenStore = useTokenStore();
const addresses = tokenStore.sacrificeToken.map((obj) => obj.contractAddress);
const hash = await this.contract.write.stakeAndClaim([stakeCoefficient, [cycle], addresses]);
return hash;
},
async stakeAndClaimAllCycles(stakeCoefficient) {
console.log("stakeAndClaimAllCycles", stakeCoefficient);
const tokenStore = useTokenStore();
const cycleStore = useCycleStore();
const cycles = await cycleStore.getFinshedCycleNumbers();
const addresses = tokenStore.sacrificeToken.map((obj) => obj.contractAddress);
const hash = await this.contract.write.stakeAndClaim([stakeCoefficient, cycles, addresses]);
return hash;
},
async unstakeOrdered() {
const cycleStore = useCycleStore();
const walletStore = useWalletStoreV2();
const contracts = [];
for (let index = 1; index < cycleStore.currentCycle + 2; index++) {
contracts.push({
...this.contract,
functionName: "unstakeOrdered",
args: [index, walletStore.address],
});
}
const data = await multicall({
contracts,
});
console.log("data123", data);
return data;
},
},
});
-100
View File
@@ -1,100 +0,0 @@
import { defineStore } from "pinia";
import { useMemeburnerStore } from "./memeburner";
import { useTokenStore } from "./tokens";
import { useRewardLockerStore } from "./rewardlocker";
import { useWalletStore } from "./wallet";
export const useRoundsStore = defineStore("rounds", {
state: () => ({
rounds: [
],
activeRound: null,
currentRound: null
}),
getters: {
getCurrentRoundData() {
return this.rounds[this.activeRound];
}
},
actions: {
async init() {
//fill initial round
},
async updateCurrentRound(sacrificedToken, sacrificedAmount) {
const tokenStore = useTokenStore();
const memeBurnerStore = useMemeburnerStore();
var data = await memeBurnerStore.getSacrificedRound(this.currentRound)
console.log("data123", data);
var tokenIndex = this.rounds[this.currentRound].token.findIndex((tokenData) => tokenData.contractAddress === sacrificedToken);
this.rounds[this.currentRound].token[tokenIndex].amount = data[tokenIndex][1];
},
async fillRound() {
console.log("fillRound");
const memeBurnerStore = useMemeburnerStore();
const tokenStore = useTokenStore();
const walletStore = useWalletStore();
const rewardLockerStore = useRewardLockerStore();
// if (this.activeRound === this.currentRound) {
// console.log("activeRound is not completed");
// } else
if (!this.rounds[this.activeRound]) {
console.log("round not filled --> fill round");
console.log("vor error");
var data = await memeBurnerStore.getSacrificedRound(this.activeRound)
let rewardData = null;
if (await walletStore.isConnected()) {
rewardData = await rewardLockerStore.getRewardsForAllToken(this.activeRound);
}
console.log("rewardData123", rewardData);
var goal = await memeBurnerStore.getGoal(this.activeRound);
var tokenArray = []
var rewards_clan = BigInt(0);
var rewards_sacrifice = BigInt(0);
for (let index = 0; index < data.length; index++) {
var tokenData = {};
const token = tokenStore.token[index];
var testcoef = await rewardLockerStore.getSacrificedTokenCoefficient(this.activeRound, token.contractAddress);
tokenData.name = token.name;
tokenData.contractAddress = token.contractAddress;
tokenData.vamplogo = token.vamp.logo;
tokenData.vampname = token.vamp.name;
tokenData.amount = data[index][1];
tokenData.getAmountToReachGoal= await memeBurnerStore.getAmountToReachGoal(token.contractAddress);
if (this.currentRound !== this.activeRound && await walletStore.isConnected()) {
const clanwin = BigInt((testcoef / 10000 - 1) * rewardData[index]);
const sacrificeRewards = BigInt(rewardData[index]) - clanwin;
tokenData.rewards_ges = rewardData[index];
tokenData.rewards_clan = clanwin;
tokenData.rewards_sacrifice = sacrificeRewards;
rewards_clan = rewards_clan + BigInt(clanwin / BigInt(Math.pow(10, token.decimals)));
rewards_sacrifice =
rewards_sacrifice + BigInt(sacrificeRewards / BigInt(Math.pow(10, token.decimals)));
}
tokenArray.push(tokenData);
}
const goalInBLD = await memeBurnerStore.getGoalInBLD(this.activeRound);
this.rounds[this.activeRound] = {
goal: goal.goal,
goalInBLD: goalInBLD /Math.pow(10, tokenStore.memeToken.decimals),
expirationTimestamp: goal.expirationTimestamp,
rewards_clan: rewards_clan,
rewards_sacrifice: rewards_sacrifice,
rewards_total: rewards_clan + rewards_sacrifice,
token: tokenArray,
};
} else {
console.log("round already filled");
}
console.log("this.rounds123", this.rounds);
},
},
});
+214
View File
@@ -0,0 +1,214 @@
import { defineStore } from "pinia";
import { useMemeburnerStore } from "@/stores/memeburner";
import { useUniswapStore } from "@/stores/uniswap";
import { useWalletStoreV2 } from "@/stores/walletV2";
import { useCycleStore } from "@/stores/cycles";
import { useRewardLockerStore } from "@/stores/rewardlocker";
import { useTokenStore } from "@/stores/tokens";
import { waitForTransaction, readContract, watchBlockNumber, multicall } from "@wagmi/core";
import { showSuccessToast } from "@/helper/toast.js";
import { formatNumber } from "@/helper/helper.js";
export const useSacrificeStore = defineStore("sacrifice", {
state: () => ({
sacrificeNumber: 0n,
sacrificeState: 0,
}),
getters: {},
actions: {
async sacrificeToken(amount, token) {
console.log("sacrificeToken", { amount, token });
const memeburnerStore = useMemeburnerStore();
const walletStore = useWalletStoreV2();
const tokenStore = useTokenStore();
const cycleStore = useCycleStore();
try {
this.sacrificeState = 2;
const getRewards = await this.getRewardsFor(amount, token);
console.log("getRewards", getRewards);
let hash = null;
if (getRewards.variant === "sacrifice") {
console.log("sacrifice");
hash = await memeburnerStore.sacrificeMeme(amount, getRewards.minETH);
console.log("hash", hash);
} else {
console.log("buy");
hash = await memeburnerStore.sacrificeMemeAndBuyBLOOD(amount, getRewards.minBLOOD);
console.log("hash", hash);
}
this.sacrificeState = 3;
const data = await waitForTransaction({
hash: hash,
onReplaced: (transaction) => console.log("check transaction canceled", transaction),
});
console.log("data", data);
// var rewardData = data.logs.find((logObject) => {
// return logObject.topics.find(
// (topic) => topic === "0x5e60ccd3c81486143d815dce24867a494d7fee585a0a44282cf479b19a5186ee"
// );
// });
var rewardData = data.logs.filter((logObject) => {
return logObject.topics.find(
(topic) => topic === "0x5e60ccd3c81486143d815dce24867a494d7fee585a0a44282cf479b19a5186ee"
);
});
console.log("rewardData", rewardData);
//output
let outputSacrifice = rewardData.reduce((x, y) => {
return x + BigInt(y.data);
}, 0n);
outputSacrifice = formatNumber(outputSacrifice, 10n ** token.decimals);
console.log("outputSacrifice", outputSacrifice);
token.allowance = await tokenStore.allowance();
this.sacrificeState = 4;
showSuccessToast(
outputSacrifice,
"Success!",
"You turned your meme into:",
"You can claim once the current cycle is finished and your clan bonus was calculated."
);
await walletStore.loadWalletData();
console.log("cycleStore.currentCycle", cycleStore.currentCycle);
await cycleStore.fillCycle(cycleStore.currentCycle, true);
return true;
} catch (error) {
//we should show the user an issue
throw new Error(error);
} finally {
this.sacrificeState = 0;
}
},
async getRewardsFor(amount, token) {
console.log("getRewardsFor", { amount, token });
const memeburnerStore = useMemeburnerStore();
const uniswapStore = useUniswapStore();
const walletStore = useWalletStoreV2();
const rewardLockerStore = useRewardLockerStore();
let output = 0n;
let minBLOOD;
try {
if (!amount) {
this.sacrificeState = 0;
return {
output: 0n,
};
}
const amountETHBase = await memeburnerStore.getAmountETHBase(amount);
// take 99.5% of amount ETH got for selling meme, 0.5% allowed slippage
const minETH = (amountETHBase[1] * 995n) / 1000n;
const rewardsForResult = await memeburnerStore.getRewardFor(amount);
const rewardsForResultSum = rewardsForResult[0] + rewardsForResult[1];
// quote blood amount against ETH base amount
var quoteRewards = await uniswapStore.quoteExactInputSingle(amountETHBase[0]);
let variant = "sacrifice";
// here you are setting only variant, let's show by default rewardsForResultSum
output = rewardsForResultSum;
if (quoteRewards.result) {
// take 99.5% of quoted amount, 0.5% allowed slippage
minBLOOD = (quoteRewards.amount * 995n) / 1000n;
if ((quoteRewards.amount * 95n) / 100n > rewardsForResultSum) {
variant = "buy";
console.log("use Buy-function", {
quoteRewardsNumber: quoteRewards.amount,
rewardsForResultSum,
});
} else {
console.log("use sacrifice-function", {
quoteRewardsNumber: quoteRewards.amount,
rewardsForResultSum,
});
}
}
console.log("variant", variant);
console.log("amount", amount);
if (!walletStore.connected || (walletStore.connected && token.allowance < amount)) {
/**
* case 1
* user is not logged in or Allowance is less than Input, then I show getRewardsForSacrifice Value
* variante not relevant
*/
output = rewardsForResultSum;
if (variant === "buy") {
output = quoteRewards.amount;
}
} else if (walletStore.connected && variant === "sacrifice" && token.allowance >= amount) {
/**
* case 2
* user is logged in and allowance is greater or equal input and variant is sacrifice
*/
// in this case you should use eth_call, so you are showing exact reward in cases of completing cycles
const amountSacrifice = await readContract({
address: memeburnerStore.contract.address,
abi: memeburnerStore.contract.abi,
functionName: "sacrificeMeme",
args: [token.contractAddress, amount.toString(), minETH.toString()],
account: walletStore.address,
});
output = amountSacrifice;
} else if (walletStore.connected && variant === "buy" && token.allowance >= amount) {
/**
* case 3
* user is logged in and allowance is greater or equal input and variant is buy
* compare sacrificeMeme-result and sacrificeMemeAndBuyBLOOD-result
*/
const amountSacrifice = await readContract({
address: memeburnerStore.contract.address,
abi: memeburnerStore.contract.abi,
functionName: "sacrificeMeme",
args: [token.contractAddress, amount.toString(), minETH.toString()],
account: walletStore.address,
});
const amountBuy = await readContract({
address: memeburnerStore.contract.address,
abi: memeburnerStore.contract.abi,
functionName: "sacrificeMemeAndBuyBLOOD",
args: [token.contractAddress, amount.toString(), minBLOOD.toString()],
account: walletStore.address,
});
if ((amountBuy * 95n) / 100n > amountSacrifice) {
variant = "buy";
output = amountBuy;
console.log("use buy after comparison sacrificeMemeAndBuyBLOOD and sacrificeMeme");
} else {
variant = "sacrifice";
output = amountSacrifice;
console.log("use sacrifice after comparison sacrificeMemeAndBuyBLOOD and sacrificeMeme");
}
}
//potential staking rewards
let stakingRewardsNumber = 0;
if (output > 0 && walletStore.connected) {
const stakingReward = await rewardLockerStore.getStakeRewardForSacrificeReward(
token.contractAddress,
output
);
stakingRewardsNumber = stakingReward;
}
return {
output: output,
variant: variant,
minETH: minETH,
minBLOOD: minBLOOD,
staking: stakingRewardsNumber,
};
} catch (error) {
console.error("getRewardsFor", error);
}
},
},
});
+146 -70
View File
@@ -1,17 +1,19 @@
import { defineStore } from "pinia";
import { markRaw } from "vue";
import Web3 from "web3";
import { useWalletStore } from "./wallet";
import { useContractStore } from "./contracts";
import { ethers } from "ethers";
import { useWalletStoreV2 } from "./walletV2";
import { useMemeburnerStore } from "./memeburner";
import Meme1Json from "@/assets/contracts/Meme1.json";
import Meme2Json from "@/assets/contracts/Meme2.json";
import MemeToken from "@/assets/contracts/MemeToken.json";
import MemeBurnerJson from "@/assets/contracts/MemeBurner.json";
import Meme3Json from "@/assets/contracts/Meme3.json";
import Meme4Json from "@/assets/contracts/Meme4.json";
import Meme5Json from "@/assets/contracts/Meme5.json";
import BloodlineJson from "@/assets/contracts/Bloodline.json";
import { multicall, getContract, fetchToken, getWalletClient, waitForTransaction } from "@wagmi/core";
export const useTokenStore = defineStore("token", {
state: () => ({
//some static data for the coin
token: [
{
name: "$PEPE",
@@ -20,11 +22,26 @@ export const useTokenStore = defineStore("token", {
vamp: {
logo: "/assets/img/token/pepevamp.png",
name: "$PEPE Vamp Token",
winner: "/assets/img/token/pepewinner.png",
winner2: "/assets/img/token/pepewinnerborder.png",
},
backgroundColor: "#4b8501",
abi: Meme1Json.abi,
contractAddress: Meme1Json.contractAddress,
ethcontract: null,
addSteps: [
{
amount: 10000000000000000000000000n,
name: "10m",
},
{
amount: 100000000000000000000000000n,
name: "100m",
},
{
amount: 1000000000000000000000000000n,
name: "1b",
},
],
},
{
name: "$SHIB",
@@ -33,21 +50,83 @@ export const useTokenStore = defineStore("token", {
vamp: {
logo: "/assets/img/token/shibvamp.png",
name: "$SHIBA Vamp Token",
winner: "/assets/img/token/shibwinner.png",
winner2: "/assets/img/token/shibwinnerborder.png",
},
abi: Meme2Json.abi,
contractAddress: Meme2Json.contractAddress,
addSteps: [
{
amount: 1000000000000000000000000n,
name: "1m",
},
{
amount: 10000000000000000000000000n,
name: "10m",
},
{
amount: 100000000000000000000000000n,
name: "100m",
},
],
},
{
name: "$ELON",
logo: "/assets/img/token/elon.png",
logoMobile: "/assets/img/token/elonMobile.png",
vamp: {
logo: "/assets/img/token/elonvamp.png",
name: "$ELON Vamp Token",
winner: "/assets/img/token/elonwinner.png",
winner2: "/assets/img/token/elonwinnerborder.png",
},
abi: Meme3Json.abi,
contractAddress: Meme3Json.contractAddress,
addSteps: [
{
amount: 10000000000000000000000000n,
name: "10m",
},
{
amount: 100000000000000000000000000n,
name: "100m",
},
{
amount: 1000000000000000000000000000n,
name: "1b",
},
],
},
// {
// name: "$ELON",
// logo: "/assets/img/token/elon.png",
// logoMobile: "/assets/img/token/elonMobile.png",
// name: "$BITCOIN",
// logo: "/assets/img/token/bitcoin.png",
// logoMobile: "/assets/img/token/bitcoin.png",
// vamp: {
// logo: "/assets/img/token/shibvamp.png",
// logo: "/assets/img/token/bitcoin.png",
// name: "$ELON Vamp Token",
// winner: "/assets/img/token/bitcoinwinner.png"
// winner2: "/assets/img/token/bitcoinwinnerborder.png"
// },
// abi: Meme4Json.abi,
// contractAddress: Meme4Json.contractAddress,
// },
// {
// name: "$BAD",
// logo: "/assets/img/token/bad.png",
// logoMobile: "/assets/img/token/bad.png",
// vamp: {
// logo: "/assets/img/token/bad.png",
// name: "$ELON Vamp Token",
// },
// abi: null,
// contractAddress: null,
// abi: Meme5Json.abi,
// contractAddress: Meme5Json.contractAddress,
// },
{
name: "$BLOOD",
abi: BloodlineJson.abi,
contractAddress: BloodlineJson.contractAddress,
logo: "/assets/img/token/bloodline.png",
},
],
activeToken: {
address: null,
@@ -55,85 +134,82 @@ export const useTokenStore = defineStore("token", {
balance: null,
contract: null,
allowance: null,
rewards: null,
},
loading: false,
memeToken: {
config: {
abi: MemeToken.abi,
contractAddress: MemeToken.contractAddress,
},
},
}),
getters: {},
actions: {
async init() {
console.log("-----------init token-------------");
const walletStore = useWalletStore();
for (let index = 0; index < this.token.length; index++) {
const token = this.token[index];
token.contract = new walletStore.web3.eth.Contract(token.abi, token.contractAddress);
token.decimals = parseInt(await token.contract.methods.decimals().call());
}
//MemeToken init
this.memeToken.contract = new walletStore.web3.eth.Contract(
this.memeToken.config.abi,
this.memeToken.config.contractAddress
);
this.memeToken.decimals = parseInt(await this.memeToken.contract.methods.decimals().call());
getters: {
memeToken: (state) => state.token.find((obj) => obj.contractAddress === BloodlineJson.contractAddress),
sacrificeToken: (state) => state.token.filter((obj) => obj.contractAddress !== BloodlineJson.contractAddress),
},
async changeActiveToken(token) {
this.activeToken = token;
const web3 = new Web3(window.ethereum);
this.contract = new web3.eth.Contract(token.abi, token.contractAddress);
const walletStore = useWalletStore();
if (walletStore.connected) {
this.activeToken.balance = await walletStore.getTokenBalance(token);
this.activeToken.allowance = await this.allowance();
actions: {
getToken(address) {
console.log("address", address);
const token = this.token.find((obj) => obj.contractAddress === address);
return token;
},
async initV2() {
console.log("-----------init token-------------");
try {
const walletStore = useWalletStoreV2();
for (let index = 0; index < this.token.length; index++) {
const contracts = [];
const token = this.token[index];
token.contract = getContract({
address: token.contractAddress,
abi: token.abi,
walletClient: walletStore.walletClient || walletStore.publicClient,
});
contracts.push({ ...token.contract, functionName: "decimals" });
// contracts.push({ ...token.contract, functionName: "name" });
contracts.push({ ...token.contract, functionName: "symbol" });
contracts.push({ ...token.contract, functionName: "totalSupply" });
const data = await multicall({
contracts,
});
token.decimals = BigInt(data[0].result);
// token.name = data[1].result;
token.symbol = data[1].result;
token.totalSupply = data[2].result;
}
} catch (error) {
console.error("initV2", error);
}
},
async allowance() {
console.log("allowance");
const walletStore = useWalletStore();
const walletStore = useWalletStoreV2();
const memeBurnerStore = useMemeburnerStore();
var allowance = await this.contract.methods
.allowance(walletStore.address, memeBurnerStore.config.contractAddress)
.call();
var decimals = await this.contract.methods.decimals().call();
console.log("decimals", decimals);
console.log("Math.pow(10, decimals)", Math.pow(10, decimals));
allowance = BigInt(allowance / Math.pow(10, decimals));
var allowance = await this.activeToken.contract.read.allowance([
walletStore.address,
memeBurnerStore.config.contractAddress,
]);
console.log("allowance", allowance);
return allowance;
},
async approveToken(amount) {
try {
console.log("amount", amount);
this.loading = true;
const walletStore = useWalletStore();
const memeBurnerStore = useMemeburnerStore();
var approve = await this.contract.methods
.approve(memeBurnerStore.config.contractAddress, amount)
.send({ from: walletStore.address});
//todo parameter value übergeben in eth web3.utils.toHex(web3.utils.toWei(amount, 'ether'))
var approveHash = await this.activeToken.contract.write.approve([
memeBurnerStore.config.contractAddress,
amount,
]);
console.log("approveHash", approveHash);
// .send({ from: walletStore.address, value: 0.5 });
this.activeToken.allowance = await this.allowance();
return approve;
return approveHash;
} catch (error) {
console.error(error);
throw new Error(error);
} finally {
this.loading = false;
}
},
getTokenContract(token) {
console.log("token", token);
const contractAddress = token.contractAddress;
const activeToken = this.token.find((obj) => obj.contractAddress === contractAddress);
const web3 = new Web3(window.ethereum);
const contract = new web3.eth.Contract(activeToken.abi, contractAddress);
return contract;
},
async nonces(userAddress) {
return this.memeToken.contract.methods.nonces(userAddress).call();
}
return this.BloodlineJson.contract.read.nonces([userAddress]);
},
},
});
+56
View File
@@ -0,0 +1,56 @@
import { defineStore } from "pinia";
import { useWalletStoreV2 } from "@/stores/walletV2";
import QuoterJson from "@/assets/contracts/Quoter.json";
import WethJson from "@/assets/contracts/WETH.json";
import BloodlineJson from "@/assets/contracts/Bloodline.json";
import { getContract, multicall } from "@wagmi/core";
export const useUniswapStore = defineStore("uniswap", {
state: () => ({
quoateV3Contract: {},
tokenIn: WethJson.contractAddress,
tokenOut: BloodlineJson.contractAddress,
fee: 10000n,
}),
getters: {},
actions: {
init() {
console.log("init uniswap");
const walletStore = useWalletStoreV2();
this.quoateV3Contract = getContract({
address: QuoterJson.contractAddress,
abi: QuoterJson.abi,
walletClient: walletStore.walletClient || walletStore.publicClient,
});
},
async quoteExactInputSingle(ethBase) {
try {
console.log("quoteExactInputSingle");
console.log("quoteExactInputSingle-parameter", {
tokenIn: this.tokenIn, // WETH
tokenOut: this.tokenOut, // BLOOD
fee: this.fee,
amountEthBase: ethBase,
pricelimit: 0n, //sqrtPriceLimitX96
});
const quotedAmountOut = await this.quoateV3Contract.read.quoteExactInputSingle([
this.tokenIn, //weth
this.tokenOut, //bloodline
this.fee,
ethBase,
0n, //sqrtPriceLimitX96
]);
console.log("quotedAmountOut", quotedAmountOut);
return {result: true, amount: quotedAmountOut};
} catch (error) {
return { result: false, amount: null };
}
}
}
});
-119
View File
@@ -1,119 +0,0 @@
import { defineStore } from "pinia";
import { markRaw } from "vue";
import { useTokenStore } from "./tokens";
import Web3 from "web3";
export const useWalletStore = defineStore("wallet", {
state: () => ({
count: 0,
alchemy: null,
connected: false,
address: null,
web3: null,
provider: null
}),
getters: {
},
actions: {
async init() {
console.log("wallet init");
await this.isConnected();
const goerliKey = import.meta.env.VITE_GOERLI_KEY;
if (this.connected) {
const web3 = new Web3(window.ethereum);
this.web3 = markRaw(web3);
console.log("hierabc");
window.ethereum.on("accountsChanged", async (data) => {
console.log("accountsChanged", data);
console.log("data", data);
if (data.length > 0) {
this.address = data[0]
this.connected = true;
} else {
this.address = null;
this.connected = false;
}
});
// provider = new ethers.BrowserProvider(window.ethereum);
} else {
const url = `https://eth-goerli.g.alchemy.com/v2/${goerliKey}`;
this.web3 = new Web3(url);
// provider = new ethers.AlchemyProvider("goerli", goerliKey);
}
//Websocket
this.web3socket = new Web3(
new Web3.providers.WebsocketProvider(`wss://eth-goerli.g.alchemy.com/v2/${goerliKey}`)
);
},
// connectWalletV2(connector) {
// this.address = data[0];
// },
connectWallet() {
window.ethereum
.request({ method: "eth_requestAccounts" })
.then((data) => {
console.log("data", data);
this.address = data[0];
this.connected = true;
this.init();
})
.catch((error) => {
if (error.code === 4001) {
// EIP-1193 userRejectedRequest error
console.log("Please connect to MetaMask.");
} else {
console.error(error);
}
});
// }
},
async getTokenBalance(token) {
const tokenStore = useTokenStore();
const contract = tokenStore.getTokenContract(token);
const result = await contract.methods.balanceOf(this.address).call();
return result;
},
async isConnected() {
try {
this.loading = true;
if (!window.ethereum) {
console.warn("Metamask not installed"),
this.connected = false;
return;
}
const accounts = await window.ethereum.request({ method: "eth_accounts" });
if (accounts.length) {
this.connected = true;
this.address = accounts[0];
console.log(`You're connected to: ${accounts[0]}`);
// const web3 = new Web3(window.ethereum);
// const tokenStore = useTokenStore();
// console.log("tokenStore.activeToken", tokenStore.activeToken);
// if (tokenStore.activeToken.contractAddress) {
// tokenStore.activeToken.balance = await this.getTokenBalance(
// tokenStore.activeToken
// );
// tokenStore.activeToken.allowance = await tokenStore.allowance();
// }
// tokenStore.memeBurner.contract = new web3.eth.Contract(
// tokenStore.memeBurner.config.abi,
// tokenStore.memeBurner.config.contractAddress
// );
} else {
console.log("Metamask is not connected");
this.connected = false;
}
} catch (error) {
console.log("error", error);
} finally {
this.loading = false;
return this.connected
}
}
},
persist: true,
});
+105 -114
View File
@@ -1,167 +1,158 @@
import { defineStore } from "pinia";
import { markRaw } from "vue";
import { useTokenStore } from "./tokens";
import { useRewardLockerStore } from "./rewardlocker";
import { formatNumber } from "@/helper/helper.js";
import {
createConfig,
configureChains,
mainnet,
getAccount,
getContract,
connect,
getWalletClient,
disconnect,
InjectedConnector,
watchAccount,
getWalletClient,
fetchBalance,
multicall,
getNetwork,
} from "@wagmi/core";
import { WalletConnectConnector } from "@wagmi/core/connectors/walletConnect";
import { MetaMaskConnector } from "@wagmi/core/connectors/metaMask";
import { CoinbaseWalletConnector } from "@wagmi/core/connectors/coinbaseWallet";
import { goerli } from "@wagmi/core/chains";
import { goerli, mainnet } from "@wagmi/core/chains";
import { publicProvider } from "@wagmi/core/providers/public";
import { alchemyProvider } from "@wagmi/core/providers/alchemy";
export const useWalletStoreV2 = defineStore("walletV2", {
state: () => ({
count: 0,
alchemy: null,
connected: false,
address: null,
web3: null,
provider: null,
client: null,
pubilcClient: null,
publicClient: null,
walletClient: null,
config: null
config: null,
chain: null,
token: [],
}),
getters: {},
getters: {
sacrificeToken: (state) =>
state.token.filter((obj) => {
const tokenStore = useTokenStore();
return obj.contractAddress !== tokenStore.memeToken.contractAddress;
}),
memeToken: (state) =>
state.token.find((obj) => {
const tokenStore = useTokenStore();
return obj.contractAddress === tokenStore.memeToken.contractAddress;
}),
unclaimedRewards() {
if (!this.memeToken?.unclaimedRewards) {
return 0n;
}
return this.memeToken.unclaimedRewards;
},
orderedUnstakedAmount() {
if (!this.memeToken?.orderedUnstakedAmount) {
return 0n;
}
return this.memeToken?.orderedUnstakedAmount;
},
staked() {
if (!this.memeToken?.staked) {
return 0n;
}
return this.memeToken?.staked;
},
balanceOf() {
if (!this.memeToken?.balanceOf) {
return 0n;
} else {
return this.memeToken?.balanceOf;
}
},
},
actions: {
async init() {
console.log("wallet init");
const goerliKey = import.meta.env.VITE_GOERLI_KEY;
const projectId = "d8e5ecb0353c02e21d4c0867d4473ac5";
const { chains, publicClient, webSocketPublicClient } = configureChains(
[goerli],
[alchemyProvider({ apiKey: goerliKey }), publicProvider()]
);
const account = getAccount();
this.config = createConfig({
autoConnect: true,
connectors: [
new CoinbaseWalletConnector({
chains,
options: {
appName: "wagmi demo",
if (account.address) {
this.address = account.address;
this.connected = true;
}
},
}),
new MetaMaskConnector({ chains }),
new WalletConnectConnector({
chains,
options: {
projectId: projectId,
showQrModal: true,
metadata: {
name: "Bloodline-App",
description: "TODO Bloodline Description",
url: "https://gitea.loseyourip.com/",
icons: ["https://gitea.loseyourip.com/assets/img/vampir.png"],
},
},
}),
],
publicClient,
webSocketPublicClient,
});
// await this.isConnected();
// const goerliKey = import.meta.env.VITE_GOERLI_KEY;
// if (this.connected) {
// const web3 = new Web3(window.ethereum);
// this.web3 = markRaw(web3);
// console.log("hierabc");
// window.ethereum.on("accountsChanged", async (data) => {
// console.log("accountsChanged", data);
// console.log("data", data);
// if (data.length > 0) {
// this.address = data[0];
// this.connected = true;
// } else {
// this.address = null;
// this.connected = false;
// }
// });
// // provider = new ethers.BrowserProvider(window.ethereum);
// } else {
// const url = `https://eth-goerli.g.alchemy.com/v2/${goerliKey}`;
// this.web3 = new Web3(url);
// // provider = new ethers.AlchemyProvider("goerli", goerliKey);
// }
// //Websocket
// this.web3socket = new Web3(
// new Web3.providers.WebsocketProvider(`wss://eth-goerli.g.alchemy.com/v2/${goerliKey}`)
// );
},
// connectWalletV2(connector) {
// this.address = data[0];
// },
async connectWallet(connector) {
try {
console.log("connector.name", connector.name);
// if (!account.isConnected) {
const connection = await connect({
chainId: goerli.id,
connector: connector,
});
console.log("connection", connection);
} catch (error) {
if (error.message.includes("Connector not found")) {
console.warn("Connector not found");
}
console.error(error);
}
// this.address = connection.account;
},
async getTokenBalance(token) {
const tokenStore = useTokenStore();
const contract = tokenStore.getTokenContract(token);
const result = await contract.methods.balanceOf(this.address).call();
const result = await token.contract.read.balanceOf([this.address]);
return result;
},
async isConnected() {
try {
this.loading = true;
if (!window.ethereum) {
console.warn("Metamask not installed"), (this.connected = false);
async getTokenBalances() {
console.log("getTokenBalances");
this.token = [];
const tokenStore = useTokenStore();
var contracts = [];
for (let index = 0; index < tokenStore.token.length; index++) {
const token = tokenStore.token[index];
contracts.push({ ...token.contract, functionName: "balanceOf", args: [this.address] });
}
const data = await multicall({
contracts,
});
for (let index = 0; index < tokenStore.token.length; index++) {
const token = tokenStore.token[index];
this.token.push({
contractAddress: token.contractAddress,
balanceOf: data[index].result,
});
}
},
async loadWalletData() {
if (!this.connected) {
return;
}
const accounts = await window.ethereum.request({ method: "eth_accounts" });
if (accounts.length) {
this.connected = true;
this.address = accounts[0];
console.log(`You're connected to: ${accounts[0]}`);
// const web3 = new Web3(window.ethereum);
// const tokenStore = useTokenStore();
// console.log("tokenStore.activeToken", tokenStore.activeToken);
// if (tokenStore.activeToken.contractAddress) {
// tokenStore.activeToken.balance = await this.getTokenBalance(
// tokenStore.activeToken
// );
// tokenStore.activeToken.allowance = await tokenStore.allowance();
// }
// tokenStore.memeBurner.contract = new web3.eth.Contract(
// tokenStore.memeBurner.config.abi,
// tokenStore.memeBurner.config.contractAddress
// );
} else {
console.log("Metamask is not connected");
this.connected = false;
}
} catch (error) {
console.log("error", error);
} finally {
this.loading = false;
return this.connected;
}
console.log("loadWalletData");
const rewardlockerStore = useRewardLockerStore();
await this.getTokenBalances();
//MemeToken Staked
const tokenStore = useTokenStore();
this.memeToken.staked = await rewardlockerStore.getStaked(this.address);
const unclaimedRewardsArray = await rewardlockerStore.getTotalRewards(this.address);
const unclaimedRewards = unclaimedRewardsArray[0] + unclaimedRewardsArray[1];
this.memeToken.unclaimedRewards = unclaimedRewards;
this.memeToken.orderedUnstakedCycles = await rewardlockerStore.unstakeOrdered();
console.log("this.memeToken.orderedUnstakedCycles", this.memeToken.orderedUnstakedCycles);
this.memeToken.orderedUnstakedAmount = this.memeToken.orderedUnstakedCycles.reduce((x, y) => {
return x + y.result;
}, 0n);
},
},
persist: true,
// persist: true,
});
-22
View File
@@ -1,22 +0,0 @@
export default class Helper {
static debounce(func, timeout = 300) {
let timer;
return (...args) => {
clearTimeout(timer);
timer = setTimeout(() => {
func.apply(this, args);
}, timeout);
};
}
static createDebounce() {
let timeout = null;
return function (fnc, delayMs) {
clearTimeout(timeout);
timeout = setTimeout(() => {
fnc();
}, delayMs || 500);
};
}
}
+338
View File
@@ -0,0 +1,338 @@
<template>
<div class="cycle-page">
<div class="cycle-header container container--variant1">
<div class="bloodline-page-headline header" ref="observerElement">Bloodline Cycle</div>
<div class="bloodline-page-description mid-mid-text">
Claim and trade your $BLOOD at each cycle's end. Become the most powerful bloodline and win extra
rewards.
</div>
</div>
<div class="slider-wrapper" :class="{ sticking: sticking }" ref="target">
<font-awesome-icon
:class="{ 'slider-prev': true, disabled: cycleStore.activeCycle <= 1 }"
@click="prevSlide"
:icon="['fas', 'caret-left']"
/>
<div class="slider-text sub-header">Cycle {{ cycleStore.activeCycle }}</div>
<font-awesome-icon
:class="{ 'slider-next': true, disabled: cycleStore.currentCycle === cycleStore.activeCycle }"
@click="nextSlide"
:icon="['fas', 'caret-right']"
/>
</div>
<div class="cycle card card--glow container container--variant1 bloodline-wrapper">
<div
class="bloodline-border round-finish-info low-mid-text"
:class="{ loading: difference <= 0 }"
v-if="cycleStore.currentCycle === cycleStore.activeCycle"
>
<template v-if="difference > 0">
<div class="round-finish-info-key">Sacrifice Goal:</div>
<div class="round-finish-info-value">
{{ cycleStore.getCurrentCycleData?.goalInBLD / 10n ** tokenStore.memeToken.decimals }} $BLOOD
</div>
<div class="round-finish-info-key">Time left:</div>
<div class="round-finish-info-value">{{ days }} {{ hours }} {{ minutes }}</div>
</template>
<template v-else>
<loading-component></loading-component>
</template>
</div>
<template v-if="cycleStore.currentCycle !== cycleStore.activeCycle">
<div class="bloodline-border bloodline-border purple cycle-winner" v-if="cycleStore.getCycleWinner">
<div class="cycle-winner-left">
<div class="cycle-winner-headline">Cycle Winner</div>
<div class="cycle-winner-subheadline">
+ Clan Bonus on {{ cycleStore.getCycleWinner.name }} Sacrifice
</div>
</div>
<div class="cycle-winner-right">
<div class="cycle-winner-logo">
<img class="logo" :src="cycleStore.getCycleWinner.vamplogo" alt="" />
<img class="crown" src="/assets/img/winnerCrown.png" alt="" />
</div>
<div class="cycle-winner-name">{{ cycleStore.getCycleWinner.name }}</div>
</div>
</div>
<div class="bloodline-border bloodline-border__thin grey cycle-winner" v-else>
<template v-if="cycleStore.getCycleWinner">
<div class="cycle-winner-left">
<div class="cycle-winner-headline">No Clan Winner</div>
<div class="cycle-winner-subheadline">time limit has been reached</div>
</div>
<div class="cycle-winner-right">
<div class="cycle-winner-logo inactive">
<img src="/assets/img/token/bloodline.png" alt="" />
</div>
</div>
</template>
<div class="cycle-winner-loading" v-else>
<loading-component></loading-component>
</div>
</div>
</template>
<token-claim></token-claim>
<div class="bloodline-clan">
<div class="sub-header">Bloodline Clan</div>
<p class="mid-text">
Claim extra rewards when your clan wins the cycle. Increase the strength of your bloodline by
sacrificing more memes.
</p>
<div class="bloodline-container">
<div class="bloodline-border purple">Get up to +25% Clan Bonus on your sacrifice.</div>
</div>
<template v-if="!cycleStore.cycles[cycleStore.activeCycle]">
<Vue3Lottie :animationData="ChartLoading" :height="400" :width="400" />
</template>
<template v-else>
<blood-chart :data="cycleStore.cycles[cycleStore.activeCycle]"></blood-chart>
</template>
</div>
</div>
</div>
</template>
<script setup>
import { inject, ref, onMounted, onBeforeUnmount } from "vue";
import BloodChart from "@/components/BloodChart.vue";
import TokenClaim from "@/components/TokenClaim.vue";
import { useTokenStore } from "@/stores/tokens";
import { useMemeburnerStore } from "@/stores/memeburner";
import LoadingComponent from "@/components/LoadingComponent.vue";
import { useCycleStore } from "@/stores/cycles";
import { useRewardLockerStore } from "@/stores/rewardlocker";
import { Vue3Lottie } from "vue3-lottie";
import ChartLoading from "@/assets/lottie/ChartLoading.json";
const cycleStore = useCycleStore();
const tokenStore = useTokenStore();
const days = ref(null);
const hours = ref(null);
const minutes = ref(null);
const seconds = ref(null);
const timer = ref(null);
const difference = ref(null);
const target = ref();
const sticking = ref(false);
const observer = ref(null);
const observerElement = ref(null);
const memeBurnerStore = useMemeburnerStore();
onMounted(async () => {
//check if that still needed or old stuff
if (!cycleStore.currentCycle) {
cycleStore.currentCycle = parseInt(await memeBurnerStore.getCurrentCycle());
console.log("cycleStore.currentCycle", cycleStore.currentCycle);
cycleStore.activeCycle = cycleStore.currentCycle;
}
await cycleStore.fillCycle(cycleStore.activeCycle);
if (cycleStore.currentCycle === cycleStore.activeCycle) {
const expirationTimestamp = cycleStore.getCurrentCycleData.expirationTimestamp;
timer.value = setInterval(function () {
timeBetweenDates(expirationTimestamp);
}, 1000);
}
const headerEl = document.querySelector(".slider-wrapper");
//if cycle header is getting sticky than grey the background
const handler = (entries) => {
if (!entries[0].isIntersecting) {
headerEl.classList.add("stuck");
} else {
headerEl.classList.remove("stuck");
}
};
// create the observer
observer.value = new window.IntersectionObserver(handler);
if (observerElement.value) {
observer.value.observe(observerElement.value);
}
});
onBeforeUnmount(() => {
clearInterval(timer.value);
if (observer.value) {
observer.value.unobserve(observerElement.value);
}
});
async function prevSlide() {
if (cycleStore.activeCycle > 1) {
cycleStore.activeCycle--;
await cycleStore.fillCycle(cycleStore.activeCycle);
}
}
async function nextSlide() {
if (cycleStore.activeCycle < cycleStore.currentCycle) {
cycleStore.activeCycle++;
await cycleStore.fillCycle(cycleStore.activeCycle);
}
}
function timeBetweenDates(expirationTimestamp) {
const dateEntered = new Date(expirationTimestamp * 1000);
if (dateEntered) {
var now = new Date();
difference.value = dateEntered.getTime() - now.getTime();
if (difference.value <= 0) {
clearInterval(timer.value);
days.value = "0d";
hours.value = "0h";
minutes.value = "0m";
} else {
var _seconds = Math.floor(difference.value / 1000);
var _minutes = Math.floor(_seconds / 60);
var _hours = Math.floor(_minutes / 60);
var _days = Math.floor(_hours / 24);
days.value = _days;
hours.value = _hours % 24;
minutes.value = _minutes % 60;
seconds.value = _seconds % 60;
days.value = ("0" + days.value).slice(-2) + "d";
hours.value = ("0" + hours.value).slice(-2) + "h";
minutes.value = ("0" + minutes.value).slice(-2) + "m";
}
}
}
</script>
<style lang="sass">
.cycle-header
.bloodline-page-headline
text-align: center
margin-bottom: 32px
.bloodline-page-description
text-align: center
.slider-wrapper
display: flex
justify-content: center
font-size: 24px
user-select: none
position: sticky
top: 82px
z-index: 3
padding: 16px 0
&.stuck
background: #2D2D2D
@media (min-width: 992px)
top: 80px
.slider-text
margin: 0 24px
margin-top: auto
margin-bottom: auto
.slider-prev, .slider-next
color: var(--purple)
font-size: 40px
@media (min-width: 992px)
font-size: 60px
cursor: pointer
&:hover,&:active, &:focus
filter: brightness(0.80)
&.disabled
opacity: .35
pointer-events: none
.bloodline-wrapper
background: var(--dark-grey, #202020)
padding-top: 24px
gap: 24px
display: flex
flex-direction: column
text-align: center
border-bottom-left-radius: unset
border-bottom-right-radius: unset
@media (min-width: 992px)
border-radius: 16px
.cycle-winner
padding: 8px 24px
display: flex
text-align: left
justify-content: space-between
.cycle-winner-left
display: flex
flex-direction: column
justify-content: center
.cycle-winner-headline
font-size: 24px
.cycle-winner-subheadline
font-size: 14px
.cycle-winner-right
display: flex
flex-direction: column
justify-content: space-between
align-items: center
.cycle-winner-logo
height: 72px
width: 72px
position: relative
img
&.logo
height: 100%
width: 100%
border: 1px solid yellow
border-radius: 50%
img
&.crown
position: absolute
top: -10px
transform: translate(-50%, -50%)
left: 50%
// height: 72px
// width: 72px
// border-radius: 50%
// position: absolute
// left: 50%
// top: 10px
// transform: translate(-50%, -50%)
&.inactive
img
height: 100%
width: 100%
top: unset
left: unset
transform: unset
position: unset
opacity: 0.3
.cycle-winner-name
font-size: 16px
.cycle-winner-loading
width: 100%
.bloodline-clan
display: flex
flex-direction: column
gap: 16px
.round-finish-info
gap: 10px
display: grid
grid-template-columns: 1fr 1fr
text-align: right
&.loading
grid-template-columns: 1fr
.round-finish-info-key
text-align: right
.round-finish-info-value
text-align: left
</style>
+66 -209
View File
@@ -1,212 +1,80 @@
<script setup>
import { ref, computed, inject, onMounted, onBeforeUnmount } from "vue";
import { storeToRefs } from "pinia";
import SacrificeToken from "@/components/SacrificeToken.vue";
import BloodChart from "@/components/BloodChart.vue";
import TokenClaim from "@/components/TokenClaim.vue";
// import Web3 from "web3";
// import { useWalletStore } from "@/stores/wallet";
import { useTokenStore } from "@/stores/tokens";
import { useRoundsStore } from "@/stores/rounds";
const tokenStore = useTokenStore();
const roundsStore = useRoundsStore();
const { token } = storeToRefs(tokenStore);
const { getCurrentRoundData } = storeToRefs(roundsStore);
const { currentRound, activeRound, rounds } = storeToRefs(roundsStore);
const days = ref(null);
const hours = ref(null);
const minutes = ref(null);
const seconds = ref(null);
const timer = ref(null);
const modules = [Navigation];
const isMobile = inject("isMobile");
async function prevSlide() {
if (activeRound.value > 1) {
activeRound.value--;
await roundsStore.fillRound();
}
}
async function nextSlide() {
if (activeRound.value < currentRound.value) {
activeRound.value++;
await roundsStore.fillRound();
}
}
onMounted(() => {
console.log("getCurrentRoundData", getCurrentRoundData);
timer.value = setInterval(function () {
timeBetweenDates();
}, 1000);
});
onBeforeUnmount(() => {
clearInterval(timer.value);
});
function timeBetweenDates() {
const dateEntered = new Date(
getCurrentRoundData.value?.expirationTimestamp * 1000
);
if (dateEntered) {
var now = new Date();
var difference = dateEntered.getTime() - now.getTime();
if (difference <= 0) {
clearInterval(timer.value);
} else {
var _seconds = Math.floor(difference / 1000);
var _minutes = Math.floor(_seconds / 60);
var _hours = Math.floor(_minutes / 60);
var _days = Math.floor(_hours / 24);
days.value = _days;
hours.value = _hours % 24;
minutes.value = _minutes % 60;
seconds.value = _seconds % 60;
days.value = ("0" + days.value).slice(-2) + "d";
hours.value = ("0" + hours.value).slice(-2) + "h";
minutes.value = ("0" + minutes.value).slice(-2) + "m";
}
}
}
</script>
<template>
<main>
<div>
<div class="sacrifice-page" :class="{ container: !isMobile }">
<section id="bloodline-header">
<div class="header-text">
Turn your meme.<br />
Join the bloodline scheme.
</div>
</section>
<section id="sacrifice" class="container">
<sacrifice-token :data="token"></sacrifice-token>
<section id="sacrifice">
<sacrifice-token :data="tokenStore.sacrificeToken"></sacrifice-token>
</section>
<div class="container section-header-container">
<h3>Bloodline Cycle</h3>
Become the most powerful clan each cycle and claim extra rewards.<br />Claim and trade your $BLOOD at
each cycle's end.
</div>
<section id="cycle-section" class="container">
<div class="slider-wrapper">
<font-awesome-icon
:class="{ 'slider-prev': true, disabled: roundsStore.activeRound <= 1 }"
@click="prevSlide"
:icon="['fas', 'caret-left']"
/>
<div class="slider-text">Cycle {{ roundsStore.activeRound }}</div>
<font-awesome-icon
:class="{ 'slider-next': true, disabled: currentRound === roundsStore.activeRound }"
@click="nextSlide"
:icon="['fas', 'caret-right']"
/>
</div>
<div class="cycle card bloodline-wrapper">
<div class="bloodline-inner">
<token-claim></token-claim>
</div>
<div class="bloodline-clan">
<h3>Bloodline Clan</h3>
<p>
Win extra rewards for you and your clan. Increase the strength of your bloodline by
sacrificing more memes.
</p>
<table class="bonus-table" v-if="!isMobile">
<tbody>
<tr>
<th scope="row">1st</th>
<td>100% Bonus</td>
</tr>
<tr>
<th scope="row">2nd</th>
<td>50% Bonus</td>
</tr>
<tr>
<th scope="row">3rd</th>
<td>No Bonus</td>
</tr>
</tbody>
</table>
<div class="bloodline-container" v-else>
<div class="bloodline-border purple">
Get up to +100% Clan Bonus <br />on your sacrifice.
<section id="cycle-section"></section>
<div id="section-header-container">
<div class="tutorial-header sub-header">
<div class="tutorial-headline">Tutorial</div>
<div class="tutorial-more" @click="openTutorialFunc">
<font-awesome-icon v-if="openTutorial" icon="chevron-up" />
<font-awesome-icon v-else icon="chevron-down" />
</div>
</div>
<div class="blood-chart">
<blood-chart :data="rounds[activeRound]"></blood-chart>
</div>
<div class="cycle-end-wrapper">
<div class="cycle-end-inner">
<h2>Cycle End</h2>
<div class="cycle-end-text">A cycle ends when only one of these goals is reached.</div>
<div class="bloodline-border">
<table>
<tr>
<td>Sacrifice:</td>
<td class="divider"></td>
<td>{{ getCurrentRoundData?.goalInBLD?.toFixed(2) }} $BDL</td>
</tr>
<tr>
<td>Time left:</td>
<td class="divider"></td>
<td v-if="currentRound === roundsStore.activeRound">
{{ days }} {{ hours }} {{ minutes }}
</td>
<td v-else>0</td>
</tr>
</table>
</div>
</div>
</div>
</div>
</div>
</section>
<div class="container section-header-container">
<h2>Tutorial</h2>
<Collapse :when="openTutorial" class="tutorial-wrapper" ref="tutorialWrapper">
<div class="tutorial-text container mid-mid-text">
When you sacrifice your meme, the $ETH is put into an immutable $BLOOD/ETH liquidity position.
<br /><br />When your clan wins, you get extra $BLOOD rewards that you can trade.
</div>
<section id="tokenomics" class="container">
<div class="card">
<h2>Tokenomics</h2>
<p>100% clan owned. No team %, no pre-mine</p>
<section id="tokenomics">
<div class="card card--glow">
<img v-if="isMobile" src="/assets/img/tokenomics_footer.png" alt="tokenomics" />
<img v-else src="/assets/img/tokenomics.png" alt="tokenomics" />
</div>
</section>
<div class="tutorial-footer mid-text">Only 3% elders fee upon sacrifice.</div>
</Collapse>
</div>
</div>
</main>
</template>
<style lang="sass">
.blood-chart
margin-top: 56px
display: flex
justify-content: center
margin-bottom: 80px
<script setup>
import { ref, inject } from "vue";
import { storeToRefs } from "pinia";
import SacrificeToken from "@/components/SacrificeToken.vue";
import { Collapse } from "vue-collapsed";
// import { useWalletStore } from "@/stores/wallet";
import { useTokenStore } from "@/stores/tokens";
const tokenStore = useTokenStore();
const tutorialWrapper = ref(null);
const openTutorial = ref(false);
const isMobile = inject("isMobile");
function openTutorialFunc(e) {
openTutorial.value = !openTutorial.value;
setTimeout(function () {
let element = document.getElementById("section-header-container");
element.scrollIntoView({ behavior: "smooth" });
}, 200);
}
</script>
<style lang="sass">
.header-text
text-shadow: 0px 4px 4px rgba(0, 0, 0, 0.25)
font-size: 32px
text-align: center
margin-top: 64px
margin-bottom: 100px
margin-top: 24px
margin-bottom: 48px
padding: 0 12px
@media (min-width: 992px)
font-size: 64px
font-size: 48px
margin-top: 0px
line-height: unset
text-shadow: unset
line-height: 80px
font-weight: 600
padding: 0
.chart-wrapper-coin
display: flex
@@ -231,9 +99,8 @@ function timeBetweenDates() {
th
padding-right: 16px
#tokenomics
background-color: var(--darkgrey)
padding-bottom: 32px
>div
background-color: var(--darkgrey)
text-align: center
img
display: block
@@ -241,6 +108,7 @@ function timeBetweenDates() {
margin-right: auto
pointer-events: none
user-select: none
width: 100%
.chart-wrapper
width: 600px
height: 600px
@@ -259,41 +127,27 @@ function timeBetweenDates() {
text-align: center
padding-top: 10px
.slider-wrapper
#section-header-container
margin: 48px 0
scroll-margin: 150px
.tutorial-header
display: flex
justify-content: center
font-size: 24px
user-select: none
.slider-text
margin: 0 24px
margin-top: auto
margin-bottom: auto
.slider-prev, .slider-next
color: var(--purple)
font-size: 40px
cursor: pointer
&:hover,&:active, &:focus
filter: brightness(0.80)
&.disabled
opacity: .35
pointer-events: none
.section-header-container
gap: 16px
margin-bottom: 24px
.tutorial-wrapper
display: flex
flex-direction: column
gap: 24px
.tutorial-text
text-align: center
font-size: 24px
margin-top: 64px
margin-bottom: 64px
@media (min-width: 992px)
width: 655px
.bloodline-wrapper
.bloodline-inner
padding: 4px
@media (min-width: 992px)
padding: 20px
.bloodline-clan
.tutorial-footer
text-align: center
.cycle-end-wrapper
.cycle-end-inner
text-align: center
@@ -311,4 +165,7 @@ function timeBetweenDates() {
h2
font-size: 40px
.content
background: grey
</style>
+313
View File
@@ -0,0 +1,313 @@
<template>
<div class="profile-page container">
<div class="profile-header">
<div class="profile-headline header">Profile</div>
<div class="profile-subheader" v-if="walletStore.connected">
<div class="profile-subheader-logo"><img :src="getblocky(walletStore.address)" alt="" /></div>
<div class="mid-mid-text">{{ getAddressShortName(walletStore.address) }}</div>
</div>
</div>
<template v-if="!walletStore.connected">
<div class="profile-not-connected low-mid-text">
Connect your wallet to see your profile.
<div class="btn btn-immortal" @click="showPanel = true">Connect</div>
</div>
</template>
<template v-else>
<div class="total-rewards-wrapper">
<div class="total-rewards-headline mid-text text-center">Total Rewards</div>
<claim-component></claim-component>
</div>
<template v-if="!isMobile">
<stake-component-v1 :variant="2"> </stake-component-v1>
</template>
<template v-else>
<stake-component-v1> </stake-component-v1>
</template>
<div class="most-sacrificed-wrapper" v-if="false">
<div class="most-sacrificed-inner">
<div class="most-sacrificed-left">
<div class="most-sacrificed-header">Bloodline Clan</div>
<div class="most-sacrificed-subheader">Most sacrificed</div>
</div>
<div class="most-sacrificed-right">
<div class="most-sacrificed-coin-logo">
<img src="/assets/img/token/pepevamp.png" alt="" />
</div>
<div class="most-sacrificed-coin-name">$PEPE</div>
</div>
</div>
</div>
<div class="total-sacrificed-wrapper" v-if="false">
<div class="total-sacrificed-inner">
<div class="total-sacrificed-header">Total Sacrifice</div>
<div class="total-sacrificed-coins">
<div class="total-sacrificed-coin">
<div class="total-sacrificed-coin-amount">1,2b</div>
<div class="total-sacrificed-coin-logo">
<img src="/assets/img/token/pepevamp.png" alt="" />
</div>
<div class="total-sacrificed-coin-name">$PEPE</div>
</div>
<div class="total-sacrificed-coin">
<div class="total-sacrificed-coin-amount">139m</div>
<div class="total-sacrificed-coin-logo">
<img src="/assets/img/token/shibvamp.png" alt="" />
</div>
<div class="total-sacrificed-coin-name">$SHIB</div>
</div>
<div class="total-sacrificed-coin">
<div class="total-sacrificed-coin-amount">0</div>
<div class="total-sacrificed-coin-logo">
<img src="/assets/img/token/elonvamp.png" alt="" />
</div>
<div class="total-sacrificed-coin-name">$ELON</div>
</div>
</div>
</div>
</div>
</template>
</div>
</template>
<script setup>
import { ref, onMounted, computed, inject } from "vue";
import { useCycleStore } from "@/stores/cycles";
import { useWalletStoreV2 } from "@/stores/walletV2";
import { getblocky, getAddressShortName } from "@/helper/helper.js";
import StakeComponentV1 from "@/components/StakeComponentV1.vue";
import ClaimComponent from "@/components/ClaimComponent.vue";
import { useMemeburnerStore } from "@/stores/memeburner";
const cycleStore = useCycleStore();
const walletStore = useWalletStoreV2();
const memeBurnerStore = useMemeburnerStore();
const isMobile = inject("isMobile");
const showPanel = inject("showPanel");
onMounted(async () => {
//todo check that code, probably old stuff
if (!cycleStore.currentCycle) {
cycleStore.currentCycle = parseInt(await memeBurnerStore.getCurrentCycle());
console.log("cycleStore.currentCycle", cycleStore.currentCycle);
cycleStore.activeCycle = cycleStore.currentCycle;
}
console.log("cycleStore.cycles", cycleStore.cycles);
});
</script>
<style lang="sass">
.profile-page
display: flex
flex-direction: column
gap: 24px
.profile-header
display: flex
flex-direction: column
gap: 8px
.profile-headline
color: #FFF
text-align: center
.profile-subheader
display: flex
justify-content: center
gap: 12px
align-items: center
.profile-subheader-logo
img
width: 21px
height: 21px
border-radius: 20%
@media (min-width: 992px)
width: 32px
height: 32px
.total-rewards-wrapper
border-radius: 16px
background: var(--darkgrey, #202020)
display: flex
flex-direction: column
gap: 18px
padding: 8px
@media (min-width: 992px)
padding: 24px 48px
.total-rewards-inner
border-radius: 16px
border: 2px solid var(--grey, #858585)
background: var(--darkgrey, #202020)
padding: 8px 12px
gap: 16px
display: flex
flex-direction: column
.claim-wrapper
.claim-inner
display: flex
flex-direction: row
.claim-header
color: var(--white, #F9F9FA)
font-size: 18px
text-align: center
.claim-body
display: flex
flex-direction: column
gap: 4px
.bloodline-token
margin-left: auto
.claim-hr
background-color: #858585
margin: 16px 0
height: 1px
.total-rewards-buttons
display: flex
text-align: center
gap: 16px
justify-content: space-between
div
flex: 1 1 auto
font-size: 18px
.profile-stake
padding: 0 8px
.most-sacrificed-wrapper
.most-sacrificed-inner
padding: 8px
border-radius: 16px
border: 1px solid var(--grey, #858585)
background: var(--dark-grey, #202020)
gap: 34px
display: flex
justify-content: center
.most-sacrificed-left
display: flex
flex-direction: column
justify-content: center
.most-sacrificed-header
font-size: 24px
.most-sacrificed-subheader
font-size: 12px
.most-sacrificed-right
display: flex
flex-direction: column
.most-sacrificed-coin-logo
img
width: 49px
height: 49px
border-radius: 50%
.total-sacrificed-wrapper
background-color: var(--dark-grey, #202020)
border-radius: 16px
border: 1px solid var(--grey, #858585)
padding: 8px
.total-sacrificed-inner
display: flex
flex-direction: column
align-items: center
gap: 16px
.total-sacrificed-header
font-size: 18px
.total-sacrificed-coins
display: flex
gap: 27px
.total-sacrificed-coin
display: flex
flex-direction: column
gap: 8px
text-align: center
.total-sacrificed-coin-logo
img
height: 49px
width: 49px
border-radius: 50%
.cycle-wrapper
margin-top: 24px
.cycle-inner
.cycle-headline
font-size: 24px
margin-bottom: 8px
text-align: center
.cycle-header
display: flex
justify-content: space-between
padding: 8px 16px
font-size: 18px
.cycle-cycles
gap: 8px
display: flex
flex-direction: column
.cycle-round
border-radius: 16px
border: 3px solid var(--grey, #858585)
background: var(--dark-grey, #202020)
padding: 12px
min-height: 55px
.cycle-round-inner
display: flex
font-size: 18px
gap: 8px
align-items: center
// .cycle-round-number
.cycle-round-badget
border-radius: 14px
border: 1px solid var(--grey, #858585)
padding: 8px 16px
height: 25px
color: var(--grey, #858585)
text-align: center
font-size: 14px
display: flex
align-items: center
margin-left: auto
.cycle-round-reward
margin-left: auto
.cycle-round-more
font-size: 16px
.cycle-round-detail
.cycle-round-detail-inner
.sacrifice-reward-wrapper
border-radius: 16px
border: 0.5px solid var(--grey, #858585)
margin-top: 12px
.sacrifice-reward-inner
padding: 8px 16px
.sacrifice-reward-header
display: flex
font-size: 18px
justify-content: space-between
margin-bottom: 16px
.sacrifice-coins
margin-left: auto
border-collapse: separate
border-spacing: 0 12px
.sacrifice-coin
td
text-align: right
img
height: 40px
width: 40px
border-radius: 50%
.arrow
width: 14px
padding: 0 16px
.profile-not-connected
border-radius: 16px
padding: 16px
gap: 16px
display: flex
flex-direction: column
text-align: center
background: var(--darkgrey, #202020)
</style>
+151 -81
View File
@@ -2,93 +2,145 @@
<div>
<button @click="mintToken">mint</button>
<button @click="mintToken2">mint2</button>
<button @click="mintToken3">mint3</button>
<button @click="sacrificeMeme">sacrifice Meme</button>
<button @click="approveMeme1">approve Meme1</button>
<button @click="tokenStore.approveToken(MemeBurnerJson, 10)">wallet approve</button>
<button @click="stake">stake</button>
<button @click="stake">z</button>
<button @click="">unstake</button>
<button @click="fetchBalance">fetchBalance</button>
<button @click="claimView">claimview</button>
<button @click="testQuoter(token0, token1, fee)">quoater</button>
</div>
</template>
<script setup>
import { onMounted, ref } from "vue";
import Web3 from "web3";
import Meme1Json from "@/assets/contracts/Meme1.json";
import Meme2Json from "@/assets/contracts/Meme2.json";
import MemeBurnerJson from "@/assets/contracts/MemeBurner.json";
import MemeTokenJson from "@/assets/contracts/MemeToken.json";
import MemeBurnerJson from "@/assets/contracts/Bloodline.json";
import RewardLockerJson from "@/assets/contracts/RewardLocker.json";
import QuoterJson from "@/assets/contracts/Quoter.json";
import UniswapPoolJson from "@/assets/contracts/UniswapPool.json";
import MemeAltarJson from "@/assets/contracts/MemeAltar.json";
import { useTokenStore } from "@/stores/tokens";
import { useWalletStoreV2 } from "@/stores/walletV2";
import { useRewardLockerStore } from "@/stores/rewardlocker";
import { useMemeburnerStore } from "@/stores/memeburner";
import { signTypedData, getContract } from "@wagmi/core";
const tokenStore = useTokenStore();
const walletV2Store = useWalletStoreV2();
const rewardLockerStore = useRewardLockerStore();
const memeBurnerStore = useMemeburnerStore();
console.log("Meme1Json", Meme1Json);
console.log("Meme2Json", Meme2Json);
console.log("MemeBurnerJson", MemeBurnerJson);
console.log("MemeTokenJson", MemeTokenJson);
console.log("RewardLockerJson", RewardLockerJson);
// let web3 = new Web3(
// "https://eth-goerli.g.alchemy.com/v2/0-W9tOm6v_QP1PfRV8RuBCpWr-qoEbkN"
// );
// console.log("balanceOf", balanceOf);
const web3 = ref(null);
const contractMeme2 = ref(null);
const contractMeme1 = ref(null);
const contractBurner = ref(null);
const contractBloodline = ref(null);
const rewardlocker = ref(null);
const contractQuoter = ref(null);
const poolContract = ref(null);
const memeAltarContract = ref(null);
const token0 = ref(null);
const token1 = ref(null);
const fee = ref(null);
const amountETHBase = ref(null);
const amount = 100 * Math.pow(10, 18);
onMounted(async () => {
web3.value = new Web3(window.ethereum);
// const contract = new web3.value.eth.Contract(Meme1Json.abi, Meme1Json.contractAddress);
console.log("web3", web3.value);
const accounts = await web3.value.eth.getAccounts();
console.log("accounts", accounts);
web3.value.eth.Contract.defaultAccount = accounts[0];
contractQuoter.value = getContract({
address: QuoterJson.contractAddress,
abi: QuoterJson.abi,
walletClient: walletV2Store.walletClient || walletV2Store.publicClient,
});
contractMeme1.value = new web3.value.eth.Contract(
Meme1Json.abi,
Meme1Json.contractAddress
);
contractMeme2.value = new web3.value.eth.Contract(
Meme2Json.abi,
Meme2Json.contractAddress
);
contractBloodline.value = new web3.value.eth.Contract(
MemeTokenJson.abi,
MemeTokenJson.contractAddress
);
contractBurner.value = new web3.value.eth.Contract(
MemeBurnerJson.abi,
MemeBurnerJson.contractAddress
);
poolContract.value = getContract({
address: UniswapPoolJson.contractAddress,
abi: UniswapPoolJson.abi,
walletClient: walletV2Store.walletClient || walletV2Store.publicClient,
});
rewardlocker.value = new web3.value.eth.Contract(
RewardLockerJson.abi,
RewardLockerJson.contractAddress
);
memeAltarContract.value = getContract({
address: MemeAltarJson.contractAddress,
abi: MemeAltarJson.abi,
walletClient: walletV2Store.walletClient || walletV2Store.publicClient,
});
console.log("poolContract.value", poolContract.value);
token0.value = await poolContract.value.read.token0();
token1.value = await poolContract.value.read.token1();
fee.value = await poolContract.value.read.fee();
console.log("input-amountEthBASE", {
memeToSacrifice: "0x4435ABC578136e2Eca50b5EFf950F17CAF42485b",
amountToSacrifice: amount,
roundParticipant: true,
});
amountETHBase.value = await memeAltarContract.value.read.getAmountETHBase([
"0x4435ABC578136e2Eca50b5EFf950F17CAF42485b",
amount,
true,
]);
console.log("amountETHBase123", amountETHBase.value);
// web3.value = new Web3(window.ethereum);
// // const contract = new web3.value.eth.Contract(Meme1Json.abi, Meme1Json.contractAddress);
// console.log("web3", web3.value);
// const accounts = await web3.value.eth.getAccounts();
// console.log("accounts", accounts);
// web3.value.eth.Contract.defaultAccount = accounts[0];
// rewardlocker.value = new web3.value.eth.Contract(
// RewardLockerJson.abi,
// RewardLockerJson.contractAddress
// );
});
async function approveMeme1() {
var approve = await contractMeme1.value.methods
.approve(MemeBurnerJson.contractAddress, 10)
.send({ from: web3.value.eth.Contract.defaultAccount });
console.log("approve", approve);
async function testQuoter(token0, token1, fee) {
console.log("inputQuote", {
token1: token1,
token0: token0,
fee: fee,
amountETHBase: amountETHBase.value,
sqrtPriceLimitX96: 0,
});
const quotedAmountOut = await contractQuoter.value.read.quoteExactInputSingle([
token1,
token0,
fee,
amountETHBase.value,
0,
]);
//rewardsUniswap3
//if getrewardforsacrifice 5% less than quoater amount
//buy below issuanceprice
//0 should be the issuanceprice (memealtar.issuanceprice)
//if input 0 not allow sacrifice
//before allowance just compare quoater with getrewardforsacrifice
//after allowance eth_call sacrificememe and sacrificebuyblood
//if error quoater --> usesacrificememe
//on sacrificememe calculate minEthAmount )
//on bloodbuy calculate minBloodamount (quoatedAmount * 0,995) - 100
//0,995 Schlupf (siehe app.uniswap (0,5%))
//if the price move more like this Schlupf (0,5%), dann revert
//uniswapv2 quoater for sacrificememe
console.log("quotedAmountOut", quotedAmountOut);
}
// async function approveMeme2() {
// var approve = await contractMeme1.value.methods.approve(web3.value.eth.Contract.defaultAccount, 10).send({ from: web3.value.eth.Contract.defaultAccount })
// console.log("approve", approve);
// }
async function claimView() {
var resultStake = await rewardLockerStore.contract.read.claim([[0, 1, 2]]);
console.log("resultStake", resultStake);
}
// change this value to make yourself rich quick
async function mintToken() {
try {
var mint = await contractMeme1.value.methods
.mint("100000000000000000000000")
.send({ from: web3.value.eth.Contract.defaultAccount });
var mint = await tokenStore.token[0].contract.write.mint(["100000000000000000000000"]);
// .send({ from: web3.value.eth.Contract.defaultAccount });
console.log("mint", mint);
} catch (error) {
console.log(error);
@@ -101,9 +153,21 @@ async function mintToken() {
async function mintToken2() {
try {
var mint = await contractMeme2.value.methods
.mint("100000000000000000000")
.send({ from: web3.value.eth.Contract.defaultAccount });
var mint = await tokenStore.token[1].contract.write.mint(["100000000000000000000000"]);
// .send({ from: web3.value.eth.Contract.defaultAccount });
console.log("mint", mint);
} catch (error) {
console.log(error);
}
// var balanceOf = await contract.methods.balanceOf("0x66422602B2f4885c57EE794174f98d9E4DDBBBC6").call();
// console.log("balanceOf", balanceOf);
// var totalSupply = await contract.methods.totalSupply().call();
// console.log("totalSupply", totalSupply);
}
async function mintToken3() {
try {
var mint = await tokenStore.token[2].contract.write.mint(["100000000000000000000000"]);
// .send({ from: web3.value.eth.Contract.defaultAccount });
console.log("mint", mint);
} catch (error) {
console.log(error);
@@ -114,14 +178,15 @@ async function mintToken2() {
// console.log("totalSupply", totalSupply);
}
async function fetchBalance() {
var result = await walletV2Store.fetchBalance();
console.log("result", result);
}
// 100 Meme will be sacrificed
async function sacrificeMeme() {
const allowance = await contractMeme1.value.methods
.allowance(
web3.value.eth.Contract.defaultAccount,
MemeBurnerJson.contractAddress
)
.allowance(web3.value.eth.Contract.defaultAccount, MemeBurnerJson.contractAddress)
.call();
console.log("allowance", allowance);
var reward = await contractBurner.value.methods
@@ -139,37 +204,46 @@ async function stake() {
const spender = "0x7C3D5a19878d550D0c6c2b0BFC884ef410F6e440";
console.log("deadline", deadline);
var nonceTest = await contractBloodline.value.methods
.nonces(fromAddress)
.call();
var nonceTest = await contractBloodline.value.methods.nonces(fromAddress).call();
console.log("type", typeof nonceTest);
console.log("nonceTest", nonceTest);
const value = (1 * Math.pow(10, 18)).toString();
console.log("value", value);
const messageData = createPermitMessageData(
fromAddress,
spender,
nonceTest,
deadline,
value
);
const messageData = createPermitMessageData(fromAddress, spender, nonceTest, deadline, value);
console.log("messageData", messageData);
console.log("messageData.message", messageData.message);
console.log("messageData.domain", messageData.domain);
console.log("messageData.primaryType", messageData.primaryType);
// const sig = await signData(fromAddress, messageData.typedData);
const signature = await signTyped(fromAddress, messageData.typedData);
// const signature = await signTyped(fromAddress, messageData.typedData);
const typedData = JSON.parse(messageData.typedData);
console.log("typedData", typedData);
const signature = await signTypedData({
domain: messageData.domain,
message: messageData.message,
primaryType: messageData.primaryType,
types: typedData.types,
});
// console.log("sig", sig);
console.log("signature", signature);
const split = splitSig(signature);
console.log("split", split);
var resultStake = await rewardlocker.value.methods
.stakeToBeSecured(value, deadline, split.v, split.r, split.s)
.send({ from: fromAddress });
// var resultStake = await rewardlocker.value.methods
// .stakeToBeSecured(value, deadline, split.v, split.r, split.s)
// .send({ from: fromAddress });
console.log("rewardLockerStore.contract", rewardLockerStore.contract);
var resultStake = await rewardLockerStore.contract.write.stakeToBeSecured([
value,
deadline,
split.v,
split.r,
split.s,
]);
console.log("resultStake", resultStake);
var allowance = await contractBloodline.value.methods
.allowance(fromAddress, spender)
.call();
var allowance = await tokenStore.memeToken.contract.read.allowance([fromAddress, spender]);
console.log("allowance", allowance);
// return Object.assign({}, sig, messageData.message);
}
@@ -215,13 +289,7 @@ const signData = async function (fromAddress, typeData) {
return { v, r, s };
};
const createPermitMessageData = function (
fromAddress,
spender,
nonce,
deadline,
value
) {
const createPermitMessageData = function (fromAddress, spender, nonce, deadline, value) {
const message = {
owner: fromAddress,
spender: spender,
@@ -276,6 +344,8 @@ const createPermitMessageData = function (
return {
typedData,
message,
domain: JSON.parse(typedData).domain,
primaryType: JSON.parse(typedData).primaryType,
};
};
// console.log("balanceOf", contract.mint(10));
+3 -10
View File
@@ -3,32 +3,27 @@
<div v-if="!fromAddress" @click="showConnectors = true">Connect</div>
<div v-if="showConnectors">
<div v-for="connector in config.connectors" @click="connectWallet(connector)">
{{ connector.name}}
{{ connector.name }}
</div>
</div>
<div v-if="fromAddress" @click="disconnectWallet">Disconnect</div>
</div>
</template>
<script setup >
<script setup>
import { ref, toRaw, onMounted, onUnmounted } from "vue";
import Meme1Json from "@/assets/contracts/Meme1.json";
import { useWalletStore } from "@/stores/wallet";
const walletStore = useWalletStore();
const fromAddress = ref(null);
const showConnectors = ref(false);
import {
createConfig,
configureChains,
mainnet,
getAccount,
getContract,
connect,
disconnect,
InjectedConnector,
getWalletClient,
watchAccount,
} from "@wagmi/core";
import { WalletConnectConnector } from "@wagmi/core/connectors/walletConnect";
@@ -77,9 +72,7 @@ config.value = createConfig({
name: "Bloodline-App",
description: "TODO Bloodline Description",
url: "https://gitea.loseyourip.com/",
icons: [
"https://gitea.loseyourip.com/assets/img/vampir.png",
],
icons: ["https://gitea.loseyourip.com/assets/img/vampir.png"],
},
},
}),
-223
View File
@@ -1,223 +0,0 @@
<template>
{{ activeWallet }}
{{ fromAddressWC }}
<div class="connect-overview" v-if="!activeWallet && !fromAddressWC">
<div v-for="wallet in wallets">
<img :src="wallet.icon" :alt="wallet.name" @click="connectWallet($event, wallet)">
</div>
</div>
<div v-else>
<button @click="disconnectWallet">disconnect</button>
</div>
</template>
<script setup>
import { ref, onMounted } from "vue";
import { WalletConnectModalSign } from "@walletconnect/modal-sign-html";
import {
EthereumProvider,
OPTIONAL_EVENTS,
REQUIRED_EVENTS,
REQUIRED_METHODS,
OPTIONAL_METHODS,
} from "@walletconnect/ethereum-provider";
import Web3 from "web3";
// const modal = new WalletConnectModal({
// projectId: "d8e5ecb0353c02e21d4c0867d4473ac5",
// chains: ["goerli"],
// });
const activeWallet = ref(null);
const fromAddressWC = ref(null);
const provider = ref(null);
const wallets = [
{
name: "MetaMask",
icon: "https://cdn.iconscout.com/icon/free/png-512/metamask-2728406-2261817.png",
},
{
name: "WalletConnect",
icon: "https://time.com/img/icons/wallet-connect.png",
},
];
const disableConnectButton = ref(false);
// const web3Modal = new WalletConnectModalSign({
// projectId,
// metadata: {
// name: "Bloodline-App",
// description: "TODO Bloodline Description",
// url: "https://gitea.loseyourip.com/",
// icons: ["https://gitea.loseyourip.com/assets/img/vampir.png"],
// },
// });
onMounted(async () => {
const projectId = "d8e5ecb0353c02e21d4c0867d4473ac5";
const showQrModal = true;
const metadata = {
name: "Bloodline-App",
description: "TODO Bloodline Description",
url: "https://gitea.loseyourip.com/",
icons: ["https://gitea.loseyourip.com/assets/img/vampir.png"],
};
provider.value = await EthereumProvider.init({
projectId, // REQUIRED your projectId
chains: [1], // chains added to required namespaces
optionalChains: [5], // chains added to optional namespaces
showQrModal, // REQUIRED set to "true" to use @walletconnect/modal
REQUIRED_METHODS, // REQUIRED ethereum methods
OPTIONAL_METHODS, // OPTIONAL ethereum methods
REQUIRED_EVENTS, // REQUIRED ethereum events
OPTIONAL_EVENTS, // OPTIONAL ethereum events
// rpcMap, // OPTIONAL rpc urls for each chain
metadata, // OPTIONAL metadata of your app
// qrModalOptions, // OPTIONAL - `undefined` by default, see https://docs.walletconnect.com/2.0/web3modal/options
});
console.log("provider.value", provider.value);
if (provider.value.accounts.length > 0) {
fromAddressWC.value = provider.value.accounts[0];
} else {
fromAddressWC.value = null;
}
});
async function disconnectWallet() {
activeWallet.value = null;
fromAddressWC.value = null;
provider.value.disconnect();
}
async function connectWallet(event, wallet) {
try {
disableConnectButton.value = true;
if (wallet.name === "MetaMask") {
window.ethereum
.request({ method: "eth_requestAccounts" })
.then((data) => {
console.log("data", data);
activeWallet.value = { ...wallet, address: data };
})
.catch((error) => {
if (error.code === 4001) {
// EIP-1193 userRejectedRequest error
console.log("Please connect to MetaMask.");
} else {
console.error(error);
}
});
} else if (wallet.name === "WalletConnect") {
const methods = [
"eth_signTypedData",
"eth_signTypedData_v4",
"eth_sign",
];
const optionalMethods = [];
const events = [];
console.log("OPTIONAL_EVENTS", OPTIONAL_EVENTS);
console.log("REQUIRED_EVENTS", REQUIRED_EVENTS);
console.log("REQUIRED_METHODS", REQUIRED_METHODS);
console.log("OPTIONAL_METHODS", OPTIONAL_METHODS);
console.log("provider", provider.value);
// await provider.value.connect();
await provider.value.enable();
provider.value.on("accountsChanged", function (account) {
console.log("accountschanged", { account });
fromAddressWC.value = account;
});
const result = await provider.value.request({
method: "eth_requestAccounts",
});
console.log("result", result);
fromAddressWC.value = result[0];
// const session = await web3Modal.connect({
// requiredNamespaces: {
// eip155: {
// methods: ["eth_sendTransaction", "personal_sign"],
// chains: ["eip155:1"],
// events: ["chainChanged", "accountsChanged"],
// },
// },
// });
// console.log("session", session);
// const web3 = new Web3(session);
// console.log("web3", web3);
// try {
// // console.log("web3Modal", web3Modal);
// // var test = await web3Modal.request({
// // method: "eth_requestAccounts",
// // });
// // console.log("test", test);
// console.log("getAccounts");
// const accounts = await web3.eth.getAccounts();
// console.log("Got accounts", accounts);
// } catch (error) {
// console.log("error", error);
// }
// // MetaMask does not give you all accounts, only the selected account
// const fromAddress = session.namespaces.eip155.accounts[0].slice(9);
// console.log("Web3 instance is", web3);
// try {
// var balance = web3.eth.getBalance(fromAddress);
// console.log("balance", balance);
// } catch (error) {
// console.log("error", error);
// }
// // var accounts = await web3.eth.getAccounts();
// console.log("accounts", accounts);
// var userAccount = accounts[0];
// console.log("userAccount", userAccount);
// session.on("accountsChanged", (accounts) => {
// console.log("ACCOUNTS CHANGED" + accounts[0]);
// });
}
} catch (error) {
} finally {
disableConnectButton.value = false;
}
}
async function onConnect() {
try {
disableConnectButton.value = true;
const session = await web3Modal.connect({
requiredNamespaces: {
eip155: {
methods: ["eth_sendTransaction", "personal_sign"],
chains: ["eip155:1"],
events: ["chainChanged", "accountsChanged"],
},
},
});
console.info(session);
} catch (err) {
console.error(err);
} finally {
disableConnectButton.value = false;
}
}
async function disconnect() {
modal.closeModal();
}
</script>
<style lang="sass">
.connect-overview
display: flex
div
background-color: black
width: 100px
height: auto
img
width: 100%
height: auto
</style>
+5 -1
View File
@@ -1,4 +1,5 @@
import { fileURLToPath, URL } from 'node:url'
import svgLoader from "vite-svg-loader";
import { defineConfig } from 'vite'
import GlobalsPolyfills from "@esbuild-plugins/node-globals-polyfill";
@@ -9,7 +10,7 @@ import vue from '@vitejs/plugin-vue'
// https://vitejs.dev/config/
export default defineConfig({
base: "./",
plugins: [vue()],
plugins: [vue(), svgLoader()],
optimizeDeps: {
esbuildOptions: {
plugins: [
@@ -29,4 +30,7 @@ export default defineConfig({
"@": fileURLToPath(new URL("./src", import.meta.url)),
},
},
build: {
target: "esnext",
},
});
+2159 -2216
View File
File diff suppressed because it is too large Load Diff