Skip to content

Commit

Permalink
align wallet and teerdays (#71)
Browse files Browse the repository at this point in the history
* modularize account selection

* flow works

* cosmetics
  • Loading branch information
brenzi authored Oct 23, 2024
1 parent 8f2e845 commit 9a933f7
Show file tree
Hide file tree
Showing 8 changed files with 903 additions and 755 deletions.
138 changes: 138 additions & 0 deletions components/ui/ChooseWalletOverlay.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
<template>
<OverlayDialog :show="show" :close="close" title="Access Your Wallet!">
<div class="mt-2">
<p class="text-sm text-gray-400">How would you like to connect?</p>
<div v-if="hasCreateTestingAccountFn" class="mt-4">
<button
@click="createTestingAccount"
class="incognitee-bg btn btn_gradient rounded-md px-3.5 py-2.5 text-sm font-semibold text-white shadow-sm hover:bg-indigo-400 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-400"
>
Create a New Account for Testing
</button>
<p class="mt-4">or</p>
</div>
<div v-if="extensionAccounts.length < 1" class="mt-4 flex flex-col">
<div
class="mx-auto grid max-w-lg grid-cols-2 gap-x-3 gap-y-3 sm:max-w-xl sm:grid-cols-4 sm:gap-x-3 lg:mx-0 lg:max-w-none lg:grid-cols-4"
>
<a href="https://talisman.xyz/download"
><img
class="col-span-1 max-h-10 w-full object-contain lg:col-span-1"
src="/img/index/talisman-logo.svg"
alt="talisman"
/></a>
<a href="https://novawallet.io/"
><img
class="col-span-1 max-h-7 w-full object-contain lg:col-span-1"
src="/img/index/nova-wallet-logo.svg"
alt="nova wallet"
/></a>
<a href="https://www.subwallet.app/"
><img
class="col-span-1 max-h-10 w-full object-contain lg:col-span-1"
src="/img/index/sub-wallet-logo.svg"
alt="sub wallet"
/></a>
<a href="https://polkadot.js.org/extension/"
><img
class="col-span-1 max-h-7 w-full object-contain lg:col-span-1"
src="/img/index/polkadotjs-logo.svg"
alt="polkajs"
/></a>
</div>
<div class="mt-10">
<button
@click="connectExtension"
class="incognitee-bg btn btn_gradient rounded-md px-3.5 py-2.5 text-sm font-semibold text-white shadow-sm hover:bg-indigo-400 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-400"
>
Connect Signer Extension
</button>
</div>
</div>
<div
v-if="extensionAccounts.length > 0"
ref="walletSection"
id="wallet"
class="py-12 sm:py-16"
>
<p class="text-sm text-gray-400">
Choose one of your extension accounts
</p>
<select
v-model="selectedExtensionAccount"
id="account.address"
name="account.address"
placeholder="account.address"
class="w-full rounded-md border-0 bg-gray-800 py-1.5 text-white shadow-sm ring-1 ring-inset ring-gray-700 focus:ring-1 focus:ring-inset focus:ring-incognitee-green sm:text-sm sm:leading-6"
>
<option disabled value="">choose...</option>
<option
v-for="account in extensionAccounts"
:key="account.address"
:value="account.address"
>
{{ account.meta.name }}
</option>
</select>
</div>
<div
v-if="accountStore.hasInjector && showTrustedGetterHint"
class="mt-10"
>
<p>
please allow this app to read your balance by signing the upcoming
request in your extension
</p>
<p>this window will close once a balance could be fetched</p>
</div>
</div>
</OverlayDialog>
</template>

<script setup lang="ts">
import {
connectExtension,
extensionAccounts,
injectorForAddress,
} from "@/lib/signerExtensionUtils";
import OverlayDialog from "@/components/ui/OverlayDialog.vue";
import { defineProps, computed, ref, watch } from "vue";
import { useAccount } from "@/store/account.ts";
const accountStore = useAccount();
const selectedExtensionAccount = ref("");
const props = defineProps({
createTestingAccount: {
type: Function,
required: false,
},
show: {
type: Boolean,
required: true,
},
close: {
type: Function,
required: true,
},
onExtensionAccountChange: {
type: Function,
required: true,
},
showTrustedGetterHint: {
type: Boolean,
required: false,
},
});
const hasCreateTestingAccountFn = computed(
() => typeof props.createTestingAccount === "function",
);
watch(selectedExtensionAccount, async (selectedAddress) => {
if (selectedAddress) {
props.onExtensionAccountChange(selectedAddress);
}
});
</script>

<style scoped></style>
24 changes: 18 additions & 6 deletions layouts/default.vue
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,24 @@
d="M21 12.75H3M21 9.75h-4.5M3 12.75V7.5a2.25 2.25 0 0 1 2.25-2.25h13.5A2.25 2.25 0 0 1 21 7.5v5.25m-18 0h18m-18 0V16.5A2.25 2.25 0 0 0 5.25 18.75h13.5A2.25 2.25 0 0 0 21 16.5v-3.75"
/>
</svg>
<p class="address cursor-pointer" @click="emitAddressClicked">
<div class="address cursor-pointer" @click="emitAddressClicked">
<!-- Full address on larger screens and short address on mobile -->
<span class="hidden md:inline">{{ accountStore.getAddress }}</span>
<span class="inline md:hidden">{{
accountStore.getShortAddress
}}</span>
</p>
<div v-if="accountStore.getAddress === 'none'">
<button
class="mr-5 incognitee-bg btn btn_gradient rounded-md px-3.5 py-2.5 text-sm font-semibold text-white shadow-sm hover:bg-indigo-400 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-400"
>
Connect Wallet
</button>
</div>
<div v-else>
<span class="hidden md:inline">{{
accountStore.getAddress
}}</span>
<span class="inline md:hidden">{{
accountStore.getShortAddress
}}</span>
</div>
</div>
</div>
</div>
</header>
Expand Down Expand Up @@ -126,6 +137,7 @@ import Incognitee from "@/assets/img/incognitee-mask.svg";
import TEERdays from "@/public/img/index/TEERdays-icon-white.svg";
import { useAccount } from "@/store/account.ts";
import { eventBus } from "@/helpers/eventBus";
import { connectExtension } from "~/lib/signerExtensionUtils";
const accountStore = useAccount();
const emitAddressClicked = () => {
eventBus.emit("addressClicked");
Expand Down
80 changes: 80 additions & 0 deletions lib/environmentConfig.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import { useRuntimeConfig } from "#app";
import { ChainId } from "@/configs/chains";
import { ref } from "vue";

export const shieldingTarget = ref(ChainId.PaseoRelay);
export const shieldingLimit = ref(Infinity);
export const incogniteeSidechain = ref(ChainId.IncogniteePaseoRelay);
export const incogniteeShard = ref(null);
export const isLive = ref(true);

export const integriteeNetwork = ref(ChainId.IntegriteeKusama);

export const loadEnv = () => {
const shieldingTargetEnv = useRuntimeConfig().public.SHIELDING_TARGET;
const shieldingLimitEnv = useRuntimeConfig().public.SHIELDING_LIMIT;
const incogniteeSidechainEnv = useRuntimeConfig().public.INCOGNITEE_SIDECHAIN;
const incogniteeShardEnv = useRuntimeConfig().public.SHARD;
const isLiveEnv = useRuntimeConfig().public.LIVE;
const integriteeNetworkEnv = useRuntimeConfig().public.INTEGRITEE_NETWORK;

// apply sane defaults and fallbacks
incogniteeShard.value =
incogniteeShardEnv.length > 0
? incogniteeShardEnv
: "5wePd1LYa5M49ghwgZXs55cepKbJKhj5xfzQGfPeMS7c";

if (ChainId[shieldingTargetEnv]) {
shieldingTarget.value = ChainId[shieldingTargetEnv];
}
if (ChainId[incogniteeSidechainEnv]) {
incogniteeSidechain.value = ChainId[incogniteeSidechainEnv];
}
if (shieldingLimitEnv > 0) {
shieldingLimit.value = Number(shieldingLimitEnv);
}
isLive.value = toBoolean(isLiveEnv);
if (ChainId[integriteeNetworkEnv]) {
integriteeNetwork.value = ChainId[integriteeNetworkEnv];
}

console.log(
"SHIELDING_TARGET: env:" +
shieldingTargetEnv +
". using " +
ChainId[shieldingTarget.value],
);
console.log(
"SHIELDING_LIMIT: env:" +
shieldingLimitEnv +
". using " +
shieldingLimit.value,
);
console.log(
"INCOGNITEE_SIDECHAIN: env:" +
incogniteeSidechainEnv +
". using " +
ChainId[incogniteeSidechain.value],
);
console.log(
"SHARD: env:" +
useRuntimeConfig().public.SHARD +
". using " +
incogniteeShard.value,
);
console.log("LIVE: env:" + isLiveEnv + ". using " + isLive.value);
console.log(
"INTEGRITEE_NETWORK: env:" +
integriteeNetworkEnv +
". using " +
ChainId[integriteeNetwork.value],
);
};

const toBoolean = (value: string | number | boolean): boolean => {
if (typeof value === "boolean") return value;
if (typeof value === "number") return value === 1;
if (typeof value === "string")
return value.toLowerCase() === "true" || value === "1";
return false;
};
53 changes: 53 additions & 0 deletions lib/signerExtensionUtils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// utils/connectExtension.ts

import {
web3Enable,
web3Accounts,
web3FromAddress,
} from "@polkadot/extension-dapp";
import { ref } from "vue";

export const extensionAccounts = ref([]);
export const selectedExtensionAccount = ref(null);
export const connectExtension = () => {
return web3Enable("Integritee Dapp")
.then((extensions) => {
console.log("Enabled extensions:", extensions);

if (extensions.length === 0) {
console.error(
"No wallet extensions found. Please install or enable a wallet.",
);
alert("No wallet extensions found. Please install or enable a wallet.");
return;
}

return web3Accounts();
})
.then((accountsList) => {
if (!accountsList) {
console.error("No accounts found. Please unlock your wallet.");
alert("No accounts found. Please unlock your wallet.");
return;
}

extensionAccounts.value = accountsList;
console.log("Found accounts:", accountsList);

if (accountsList.length < 1) {
console.error(
"No accounts detected in extension. Please unlock your wallet, check visibility or create an account.",
);
alert(
"No accounts detected in extension. Please unlock your wallet, check visibility or create an account.",
);
}
});
};

export const injectorForAddress = async (address) => {
const injector = await web3FromAddress(address);
console.debug(`setting injector: ${JSON.stringify(injector)}`);
console.debug(`setting injector: ${JSON.stringify(injector.signer)}`);
return injector;
};
52 changes: 52 additions & 0 deletions lib/teerDays.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
export class Bond {
teerBonded: number;
lastUpdated: Date;
accumulatedTeerDays: number;

constructor(
teerBonded: number = 0,
lastUpdated: Date = new Date(),
accumulatedTeerDays: number = 0,
) {
this.teerBonded = teerBonded;
this.lastUpdated = lastUpdated;
this.accumulatedTeerDays = accumulatedTeerDays;
}

updateTeerDays() {
const now = new Date();
const elapsed = now.getTime() - this.lastUpdated.getTime(); //milliseconds
this.accumulatedTeerDays += (this.teerBonded * elapsed) / 86400 / 1000;
this.lastUpdated = now;
}

getTeerDays() {
return this.accumulatedTeerDays.toFixed(4);
}

getTeerBonded() {
return this.teerBonded.toFixed(4);
}
}

export class PendingUnlock {
teerToUnlock: number;
due: Date;

constructor(teerToUnlock: number = 0, due: Date = new Date()) {
this.teerToUnlock = teerToUnlock;
this.due = due;
}

getDueDateStr() {
return this.due.toISOString();
}

getTeerToUnlock() {
return this.teerToUnlock > 0 ? this.teerToUnlock.toFixed(4) : null;
}

canWithdraw() {
return this.due < new Date();
}
}
Loading

0 comments on commit 9a933f7

Please sign in to comment.