add faucet feature

This commit is contained in:
liangping 2024-06-01 11:23:12 +08:00
parent a6691efb01
commit 036df51d6e
4 changed files with 184 additions and 3 deletions

View File

@ -25,6 +25,7 @@ export const UNITS: Record<string, Record<string, string>> = {
"localhost": {
"banner": "3a094192-4c7b-4761-a50c-bd9b6a67e987",
"banner_mobile": "e6b82a11-6a94-46c0-a9d2-cf730159a5e6",
"popup": "e6b82a11-6a94-46c0-a9d2-cf730159a5e6"
},
"ping.pub": {
"banner": "6883877a-ccae-4a08-b457-7e30b3465a8c",
@ -33,6 +34,7 @@ export const UNITS: Record<string, Record<string, string>> = {
"testnet.ping.pub": {
"banner": "1644951b-5022-4544-8a85-11aef8a8f645",
"banner_mobile": "81e0527f-475a-42a4-bb9a-ed9967c5d06f",
"popup": "bd77a47c-30fc-4592-9d37-616d4f66964d"
},
}

View File

@ -8,7 +8,7 @@ import NavbarThemeSwitcher from '@/layouts/components/NavbarThemeSwitcher.vue';
import NavbarSearch from '@/layouts/components/NavbarSearch.vue';
import ChainProfile from '@/layouts/components/ChainProfile.vue';
import { useDashboard } from '@/stores/useDashboard';
import { NetworkType, useDashboard } from '@/stores/useDashboard';
import { useBaseStore, useBlockchain } from '@/stores';
import NavBarI18n from './NavBarI18n.vue';
@ -143,7 +143,7 @@ dayjs()
{{ item?.badgeContent }}
</div>
</div>
<div class="collapse-content">
<div class="collapse-content">
<div v-for="(el, key) of item?.children" class="menu bg-base-100 w-full !p-0">
<RouterLink
v-if="isNavLink(el)"
@ -181,6 +181,26 @@ dayjs()
</div>
</RouterLink>
</div>
<div v-if="dashboard.networkType === NetworkType.Testnet" class="menu bg-base-100 w-full !p-0">
<RouterLink
class="hover:bg-gray-100 dark:hover:bg-[#373f59] rounded cursor-pointer px-3 py-2 flex items-center"
:to="`/${blockchain.chainName}/faucet`">
<Icon
icon="mdi:chevron-right"
class="mr-2 ml-3"
></Icon>
<div
class="text-base capitalize text-gray-500 dark:text-gray-300"
>
Faucet
</div>
<div
class="badge badge-sm text-white border-none badge-error ml-auto"
>
New
</div>
</RouterLink>
</div>
</div>
</div>

View File

@ -0,0 +1,144 @@
<script lang="ts" setup>
import AdBanner from '@/components/ad/AdBanner.vue';
import { get } from '@/libs';
import { useBlockchain, useFormatter, useGovStore } from '@/stores';
import { ref, onMounted, computed } from 'vue';
const chainStore = useBlockchain();
const format = useFormatter();
const notReady = computed(() => {
return chainStore.current === undefined || chainStore.current.endpoints.grpc === undefined || chainStore.current.faucet === undefined;
});
const validAddress = computed(() => {
if (!address.value) return true;
return address.value.startsWith(chainStore.current?.bech32Prefix || '1');
});
const faucetUrl = computed(() => {
return `https://faucet.ping.pub/${chainStore.current?.chainName}`;
// return `http://localhost:3000/${chainStore.current?.chainName}`;
});
interface FaucetResponse {
status: string;
result: any;
message: string;
}
const address = ref('');
const faucet = ref('');
const balances = ref([]);
const faucetModal = ref(false);
const ret = ref({} as FaucetResponse);
function claim() {
ret.value = {} as FaucetResponse;
const prefix = chainStore.current?.bech32Prefix || 'cosmos';
if (!address.value ) return;
faucetModal.value = true;
// @ts-ignore
get(`${faucetUrl.value}/send/${address.value}`).then( (res: FaucetResponse) => {
console.log(res);
ret.value = res;
});
}
function balance() {
get(`${faucetUrl.value}/balance`).then(res => {
balances.value = res.result?.balance;
faucet.value = res.result?.address;
});
}
onMounted(() => {
if (notReady.value) return;
balance();
});
</script>
<template>
<div>
<div class="flex md:!flex-row flex-col items-center justify-center mb-6 mt-14 gap-2">
<div class="w-16 rounded-full">
<svg version="1.0" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 150.000000 132.000000"
preserveAspectRatio="xMidYMid meet">
<g transform="translate(0.000000,132.000000) scale(0.100000,-0.100000)" fill="#666CFF" class=""
stroke="none">
<path d="M500 1310 l-125 -5 -182 -315 c-100 -173 -182 -321 -182 -329 -1 -7
81 -159 181 -337 l183 -324 372 0 371 0 186 325 c102 179 186 330 186 337 0 7
-82 157 -182 335 l-183 323 -250 -2 c-137 -1 -306 -5 -375 -8z m588 -454 c61
-106 112 -197 112 -201 0 -4 -50 -95 -111 -201 l-112 -194 -231 0 -231 0 -105
181 c-58 100 -109 190 -114 200 -6 14 17 63 104 213 l112 196 232 0 231 0 113
-194z" />
<path d="M591 1001 l-54 -6 -87 -150 -88 -150 176 -3 c97 -1 181 -1 187 2 9 3
165 267 183 308 4 9 -233 7 -317 -1z" />
<path d="M872 824 l-90 -159 36 -66 c113 -201 147 -258 153 -251 8 8 179 302
179 307 0 2 -37 68 -83 147 -46 78 -88 151 -94 162 -9 16 -24 -5 -101 -140z" />
<path d="M360 625 c0 -7 148 -263 172 -297 l19 -28 186 0 c101 0 183 3 181 8
-1 4 -43 78 -93 165 l-90 157 -187 0 c-104 0 -188 -2 -188 -5z" />
</g>
</svg>
</div>
<h1 class="text-primary text-3xl md:!text-6xl font-bold capitalize">
{{ chainStore.chainName }} Faucet
</h1>
</div>
<div class="bg-base-100 my-5 px-4 pt-3 pb-4 rounded shadow">
<h2 class="card-title">Get Tokens</h2>
<input type="text" v-model="address" class="mt-4 mb-4 w-full border border-gray-300 rounded-md p-2"
:class="{'input-error' : !validAddress}"
:disabled="notReady" placeholder="Enter your address" />
<button class="btn btn-primary w-full bg-primary text-white" :disabled="notReady" @click="claim()">Get
Tokens</button>
</div>
<AdBanner id="home-banner-ad" unit="banner" />
<div class="bg-base-100 my-5 px-4 pt-3 pb-4 rounded shadow">
<h2 class="card-title">Enable Faucet</h2>
<div class="mt-4">
<span class="text-base"> 1. Submit chain configuation</span>
<div class="mockup-code bg-base-200 my-2 gap-4">
<pre>https://github.com/ping-pub/faucet </pre>
<a class=" btn-ghost text-white rounded-md p-2 ml-4"
href="https://github.com/ping-pub/faucet">Go</a>
</div>
<span class="text-base"> 2. Fund the faucet account</span>
<div class="mockup-code bg-base-200 my-2">
<pre data-prefix=">"><code class=" text-gray-800 dark:invert"> Address: {{ faucet }} </code></pre>
<pre
data-prefix=">"><code class="text-gray-800 dark:invert"> Balances: {{ format.formatTokens(balances) }} </code></pre>
</div>
</div>
</div>
<input type="checkbox" v-model="faucetModal" id="my_modal_6" class="modal-toggle" />
<div class="modal" role="dialog">
<div class="modal-box">
<div v-if="ret.status === 'error'">
<h3 class="font-bold text-red-500"> Error </h3>
<div>{{ ret.message }}</div>
</div>
<div v-else-if="ret.status === 'ok'">
<h3 class="font-bold text-green-500"> Token Sent! </h3>
<div><RouterLink :to="`/${chainStore.chainName}/tx/${ret.result.txhash}`">View Transaction</RouterLink></div>
</div>
<h3 v-else class="font-bold text-lg"> Processing <span class="loading loading-bars loading-sm"></span> </h3>
<div class="modal-action">
<label for="my_modal_6" class="btn btn-sm btn-circle btn-ghost absolute right-2 top-2"></label>
</div>
<p class="py-4">
<div>
<AdBanner id="home-banner-ad" unit="popup" />
</div>
</p>
</div>
</div>
</div>
</template>

View File

@ -85,7 +85,13 @@ export interface ChainConfig {
low: number,
average: number,
high: number,
},
},
faucet?: {
amount: string,
ip_limit: number,
address_limit: number,
fees: string
};
}
export interface LocalConfig {
@ -93,6 +99,7 @@ export interface LocalConfig {
consensus_prefix?: string;
alias: string;
api: string[] | Endpoint[];
grpc: Endpoint[];
provider_chain: {
api: string[] | Endpoint[]
}
@ -118,6 +125,12 @@ export interface LocalConfig {
high: number,
},
keplr_features: string[],
faucet?: {
amount: string,
ip_limit: number,
address_limit: number,
fees: string
};
}
function apiConverter(api: any[]) {
@ -164,6 +177,7 @@ export function fromLocal(lc: LocalConfig): ChainConfig {
conf.endpoints = {
rest: apiConverter(lc.api),
rpc: apiConverter(lc.rpc),
grpc: apiConverter(lc.grpc),
};
if(lc.provider_chain) {
conf.providerChain = {
@ -175,6 +189,7 @@ export function fromLocal(lc: LocalConfig): ChainConfig {
conf.keplrFeatures = lc.keplr_features;
conf.keplrPriceStep = lc.keplr_price_step;
conf.themeColor = lc.theme_color;
conf.faucet = lc.faucet;
return conf;
}