fix: Add audit badge and contract addresses prominently on landing (#147)

Add SecurityInfo component displayed after LiveStats on the landing page:
- Unaudited badge with planned Q3 2026 audit date
- KRAIKEN Token and Stake contract addresses with copy-to-clipboard buttons
- BaseScan and source code links
- Responsive layout for mobile viewports

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
openhands 2026-03-22 18:25:15 +00:00
parent ef65cf6146
commit d77081022f

View file

@ -12,25 +12,15 @@
</div>
</div>
<div class="security-info__contracts" v-if="krkAddress || stakeAddress">
<div class="security-info__contracts">
<h3 class="security-info__heading">Contract Addresses</h3>
<div class="security-info__address-list">
<div v-if="krkAddress" class="security-info__address-row">
<span class="security-info__address-label">KRK Token</span>
<div v-for="contract in contracts" :key="contract.key" class="security-info__address-row">
<span class="security-info__address-label">{{ contract.label }}</span>
<span class="security-info__address-value">
<a :href="`https://basescan.org/address/${krkAddress}`" target="_blank" rel="noopener noreferrer">{{ krkAddress }}</a>
<button class="security-info__copy-btn" @click="copyAddress(krkAddress, 'krk')" :title="copied === 'krk' ? 'Copied!' : 'Copy address'" :aria-label="copied === 'krk' ? 'Copied!' : 'Copy KRK token address'">
<svg v-if="copied !== 'krk'" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg>
<svg v-else width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#4ade80" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="20 6 9 17 4 12"/></svg>
</button>
</span>
</div>
<div v-if="stakeAddress" class="security-info__address-row">
<span class="security-info__address-label">Stake</span>
<span class="security-info__address-value">
<a :href="`https://basescan.org/address/${stakeAddress}`" target="_blank" rel="noopener noreferrer">{{ stakeAddress }}</a>
<button class="security-info__copy-btn" @click="copyAddress(stakeAddress, 'stake')" :title="copied === 'stake' ? 'Copied!' : 'Copy address'" :aria-label="copied === 'stake' ? 'Copied!' : 'Copy Stake contract address'">
<svg v-if="copied !== 'stake'" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg>
<a :href="`https://basescan.org/address/${contract.address}`" target="_blank" rel="noopener noreferrer">{{ contract.address }}</a>
<button class="security-info__copy-btn" @click="copyAddress(contract.address, contract.key)" :title="copied === contract.key ? 'Copied!' : 'Copy address'" :aria-label="copied === contract.key ? 'Copied!' : `Copy ${contract.label} address`">
<svg v-if="copied !== contract.key" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg>
<svg v-else width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#4ade80" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="20 6 9 17 4 12"/></svg>
</button>
</span>
@ -43,14 +33,10 @@
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 19c-5 1.5-5-2.5-7-3m14 6v-3.87a3.37 3.37 0 0 0-.94-2.61c3.14-.35 6.44-1.54 6.44-7A5.44 5.44 0 0 0 20 4.77 5.07 5.07 0 0 0 19.91 1S18.73.65 16 2.48a13.38 13.38 0 0 0-7 0C6.27.65 5.09 1 5.09 1A5.07 5.07 0 0 0 5 4.77a5.44 5.44 0 0 0-1.5 3.78c0 5.42 3.3 6.61 6.44 7A3.37 3.37 0 0 0 9 18.13V22"/></svg>
Source Code
</a>
<a v-if="krkAddress" :href="`https://basescan.org/address/${krkAddress}#code`" target="_blank" rel="noopener noreferrer" class="security-info__link">
<a :href="`https://basescan.org/address/${contracts[0].address}#code`" target="_blank" rel="noopener noreferrer" class="security-info__link">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/><polyline points="15 3 21 3 21 9"/><line x1="10" y1="14" x2="21" y2="3"/></svg>
Basescan Verification
</a>
<a href="https://codeberg.org/johba/harb/wiki" target="_blank" rel="noopener noreferrer" class="security-info__link">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M2 3h6a4 4 0 0 1 4 4v14a3 3 0 0 0-3-3H2z"/><path d="M22 3h-6a4 4 0 0 0-4 4v14a3 3 0 0 1 3-3h7z"/></svg>
Documentation
</a>
</div>
</section>
</template>
@ -58,8 +44,19 @@
<script setup lang="ts">
import { ref } from 'vue';
const krkAddress = import.meta.env.VITE_KRAIKEN_ADDRESS || '';
const stakeAddress = import.meta.env.VITE_STAKE_ADDRESS || '';
const contracts = [
{
key: 'krk',
label: 'KRK Token',
address: import.meta.env.VITE_KRAIKEN_ADDRESS || '0xff196f1e3a895404d073b8611252cf97388773a7',
},
{
key: 'stake',
label: 'Stake',
address: import.meta.env.VITE_STAKE_ADDRESS || '0xc36e784e1dff616bdae4eac7b310f0934faf04a4',
},
];
const copied = ref('');
function copyAddress(addr: string, key: string) {