Skip to content

Commit

Permalink
feat: display badges for verified contracts (#319)
Browse files Browse the repository at this point in the history
# What ❔

* Add a green shield icon next to the `Contracts` tab title of field if
it's verified
* Update tab titles to have optional icons
* Add `Verified` badge next to contract name if it's verified

## Why ❔

To be able to quickly/easily know if a contract is verified (Closes
#142)

See an example here:
https://staging-scan-v2--pr-319-61jpzx7g.web.app/address/0x64AEB39926631F9601D78E3024D32632564C057B


![image](https://github.com/user-attachments/assets/3d1cb6eb-aef1-4d68-a362-e0b5577cceda)

Mobile screens:

![image](https://github.com/user-attachments/assets/3e74a55d-c68f-4ea4-95f8-64dd6abe07a7)


Contracts that are **not** verified:

![image](https://github.com/user-attachments/assets/802bcf97-b950-400d-81ad-28e8d3f50bac)



## Checklist

<!-- Check your PR fulfills the following items. -->
<!-- For draft PRs check the boxes as you complete them. -->

- [x] PR title corresponds to the body of PR (we generate changelog
entries from PRs).
- [x] Tests for the changes have been added / updated.
- [x] Documentation comments have been added / updated.

---------

Co-authored-by: Vasyl Ivanchuk <[email protected]>
  • Loading branch information
MexicanAce and vasyl-ivanchuk authored Nov 21, 2024
1 parent 75fcd21 commit 517ffd8
Show file tree
Hide file tree
Showing 8 changed files with 47 additions and 10 deletions.
9 changes: 8 additions & 1 deletion packages/app/src/components/Contract.vue
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
v-if="contract?.address && !pending"
:title="contractName ?? t('contract.title')"
:value="contractName ? undefined : contract?.address"
:is-verified="contract?.verificationInfo != null"
/>
<Spinner v-else size="md" />
<div class="tables-container">
Expand Down Expand Up @@ -78,6 +79,8 @@
import { computed, type PropType } from "vue";
import { useI18n } from "vue-i18n";
import { CheckCircleIcon } from "@heroicons/vue/solid";
import SearchForm from "@/components/SearchForm.vue";
import BalanceTable from "@/components/balances/Table.vue";
import Breadcrumbs from "@/components/common/Breadcrumbs.vue";
Expand Down Expand Up @@ -118,7 +121,11 @@ const props = defineProps({
const tabs = computed(() => [
{ title: t("tabs.transactions"), hash: "#transactions" },
{ title: t("tabs.transfers"), hash: "#transfers" },
{ title: t("tabs.contract"), hash: "#contract" },
{
title: t("tabs.contract"),
hash: "#contract",
icon: props.contract?.verificationInfo ? CheckCircleIcon : null,
},
{ title: t("tabs.events"), hash: "#events" },
]);
const breadcrumbItems = computed((): BreadcrumbItem[] | [] => {
Expand Down
16 changes: 13 additions & 3 deletions packages/app/src/components/common/Tabs.vue
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,13 @@
v-else
class="tab-btn"
:class="{ active: currentTabHash === tab.hash && tabs.length > 1 }"
v-html="tab.title"
@click="setTab(tab)"
></button>
>
<span v-html="tab.title"></span>
<span v-if="tab.icon" class="tab-icon">
<component :is="tab.icon" />
</span>
</button>
</li>
</template>
</ul>
Expand All @@ -35,9 +39,12 @@
import { type PropType, ref, watchEffect } from "vue";
import { useRoute, useRouter } from "vue-router";
import type { FunctionalComponent } from "vue";
export type Tab = {
title: string;
hash: string | null;
icon?: FunctionalComponent | null;
};
const props = defineProps({
Expand Down Expand Up @@ -76,13 +83,16 @@ watchEffect(() => {
@apply flex border-b md:flex-row;
}
.tab-btn {
@apply px-4 py-3.5 text-sm text-gray-400 outline-0 sm:text-base;
@apply px-4 py-3.5 text-sm text-gray-400 outline-0 sm:text-base flex;
}
.tab-content {
@apply rounded-b-lg;
}
.active {
@apply border-b-2 border-primary-600 font-bold text-primary-600;
}
.tab-icon {
@apply ml-0.5 w-5 text-green-500;
}
}
</style>
17 changes: 16 additions & 1 deletion packages/app/src/components/common/Title.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,16 @@
<slot>{{ shortValue(value) }}</slot>
<CopyButton :value="value" class="title-copy-button" />
</div>
<Badge v-if="isVerified" color="dark-success" class="verified-badge" :tooltip="t('contract.verifiedTooltip')">
{{ t("contract.verified") }}
</Badge>
</h1>
</template>
<script lang="ts" setup>
import { useI18n } from "vue-i18n";
import Badge from "./Badge.vue";
import CopyButton from "@/components/common/CopyButton.vue";
import { shortValue } from "@/utils/formatters";
Expand All @@ -20,11 +27,16 @@ defineProps({
value: {
type: String,
},
isVerified: {
type: Boolean,
},
});
const { t } = useI18n();
</script>
<style lang="scss">
.title-container {
@apply flex flex-wrap break-all text-3xl sm:text-4xl;
@apply flex flex-wrap break-all text-3xl sm:text-4xl items-end;
.title-block {
@apply flex gap-4 self-center font-bold;
.title-copy-button {
Expand All @@ -36,5 +48,8 @@ defineProps({
}
}
}
.verified-badge {
@apply mb-1 ml-1;
}
}
</style>
2 changes: 2 additions & 0 deletions packages/app/src/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -326,6 +326,8 @@
"infoTableError": "An Error Occurred",
"balanceTableTitle": "Balances",
"notFound": "Not Found",
"verified": "Source Code",
"verifiedTooltip": "The contract's source code has been verified to match its on-chain Bytecode. Source code verification does not imply the contract is safe to interact with.",
"transactionTable": {
"error": "Something went wrong",
"notFound": {
Expand Down
2 changes: 2 additions & 0 deletions packages/app/src/locales/uk.json
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,8 @@
"infoTableError": "Виникла помилка",
"balanceTableTitle": "Мої кошти",
"notFound": "Не знайдено",
"verified": "вихідний код",
"verifiedTooltip": "Вихідний код контракту було перевірено на відповідність його байт-коду в мережі. Перевірений вихідний код не означає, що контракт безпечний для взаємодії.",
"transactionTable": {
"error": "Щось пішло не так",
"notFound": {
Expand Down
3 changes: 2 additions & 1 deletion packages/app/tests/components/Contract.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ describe("Contract:", () => {
stubs: ["router-link"],
},
});
expect(container.querySelector(".title-container")?.textContent?.trim()).toBe("DARA2");
expect(container.querySelector(".title-container")?.textContent?.trim()).toContain("DARA2");
expect(container.querySelector(".title-container")?.textContent?.trim()).toContain("Source Code");
});
});
4 changes: 2 additions & 2 deletions packages/app/tests/e2e/src/pages/contract.page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,11 @@ export class ContractPage extends BasePage {
super(world);
}
get transactionsTab() {
return "//button[text()='Transactions']/..";
return "//button[contains(.,'Transactions')]/..";
}

get contractTab() {
return "//button[text()='Contract']/..";
return "//button[contains(.,'Contract')]/..";
}

get contractVerificationBtn() {
Expand Down
4 changes: 2 additions & 2 deletions packages/app/tests/e2e/src/pages/transaction.page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,11 @@ export class TransactionPage extends BasePage {
}

get generalInfoTab() {
return "//button[contains(text(),'General Info')]/..";
return "//button[contains(.,'General Info')]/..";
}

get logsTab() {
return "//button[contains(text(),'Logs')]/..";
return "//button[contains(.,'Logs')]/..";
}

get badgeContent() {
Expand Down

0 comments on commit 517ffd8

Please sign in to comment.