Skip to content

Commit

Permalink
feat: add abi json for verified contracts (#320)
Browse files Browse the repository at this point in the history
# What ❔

Display the contract's ABI JSON if it's verified

## Why ❔

This addresses #242 and allows users to easily copy/paste the ABI for
easier development

## 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.

## Evidence

Verified contract with a small ABI:

![image](https://github.com/user-attachments/assets/cb69aeaf-b905-4ec1-bd73-4c9642288ef4)


Verified contract with a large ABI (Closed & Expanded):

![image](https://github.com/user-attachments/assets/694824b3-3c59-4df7-9e38-9d0af0067676)

![image](https://github.com/user-attachments/assets/7b161062-1c45-45f4-8ab9-def76b312b46)

Unverified contract:

![image](https://github.com/user-attachments/assets/dba0dfa2-46fa-47cb-84ba-8e6cc0f0418b)

---------

Co-authored-by: Roman Petriv <[email protected]>
  • Loading branch information
MexicanAce and Romsters authored Nov 21, 2024
1 parent 517ffd8 commit 9dca4b2
Show file tree
Hide file tree
Showing 6 changed files with 97 additions and 0 deletions.
63 changes: 63 additions & 0 deletions packages/app/src/components/common/table/fields/AbiData.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
<template>
<div class="info-field-abi-data">
<Disclosure v-slot="{ open }">
<DisclosureButton
class="abi-data-disclosure-btn"
:class="open ? 'rounded-tl-lg rounded-tr-lg' : 'rounded-lg'"
:data-testid="$testId.abiDataDropDown"
>
{{ truncatedAbi }}

<div class="abi-data-disclosure-icons">
<CopyButton class="mr-1" tooltipPosition="left" :value="value" />
<ChevronDownIcon
:class="open ? 'rotate-180 transform' : ''"
class="h-5 w-5 text-gray-500 transition-transform"
/>
</div>
</DisclosureButton>
<DisclosurePanel class="abi-data-disclosure-panel">
<div class="abi-data-full-value">{{ value }}</div>
</DisclosurePanel>
</Disclosure>
</div>
</template>

<script lang="ts" setup>
import { computed } from "vue";
import { Disclosure, DisclosureButton, DisclosurePanel } from "@headlessui/vue";
import { ChevronDownIcon } from "@heroicons/vue/solid";
import CopyButton from "@/components/common/CopyButton.vue";
const props = defineProps({
value: {
type: String,
default: "",
required: true,
},
});
const truncatedAbi = computed<string>(() => {
return props.value.replace(/(.{600})..+/, "$1...");
});
</script>

<style lang="scss">
.info-field-abi-data {
.abi-data-disclosure-btn {
@apply flex w-full items-center justify-between bg-gray-200 px-4 py-2 text-left text-sm font-medium text-gray-900 hover:bg-gray-200 focus:outline-none;
}
.abi-data-disclosure-icons {
@apply flex items-center;
}
.abi-data-disclosure-panel {
@apply rounded-bl-lg rounded-br-lg border border-t-0 border-dashed border-gray-300 px-4 py-4;
.abi-data-full-value {
@apply overflow-hidden whitespace-pre-line break-words break-all text-sm text-gray-700;
}
}
}
</style>
16 changes: 16 additions & 0 deletions packages/app/src/components/contract/ContractBytecode.vue
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,12 @@
<div class="info-field-label">{{ t("contract.sourceCode.label") }}</div>
<CodeBlock v-for="(item, index) in sourceCode" :key="index" :code="item.code" :label="item.label" />
</div>
<div v-if="sourceCode" class="abi-json-field-container">
<div class="info-field-label">{{ t("contract.abiInteraction.contractAbi") }}</div>
<div class="abi-json">
<AbiData :value="abiJson" />
</div>
</div>
<div class="bytecode-field-container">
<div class="info-field-label">{{ t("contract.bytecode.deployedBytecode") }}</div>
<div class="bytecode">
Expand All @@ -42,6 +48,7 @@ import { computed } from "vue";
import { useI18n } from "vue-i18n";
import Button from "@/components/common/Button.vue";
import AbiData from "@/components/common/table/fields/AbiData.vue";
import ByteData from "@/components/common/table/fields/ByteData.vue";
import CodeBlock from "@/components/contract/CodeBlock.vue";
import CompilationInfo from "@/components/contract/CompilationInfo.vue";
Expand Down Expand Up @@ -96,6 +103,14 @@ const sourceCode = computed<undefined | { code: string; label: string }[]>(() =>
});
}
});
const abiJson = computed<undefined | string>(() => {
if (!props.contract?.verificationInfo?.artifacts?.abi) {
return undefined;
}
return JSON.stringify(props.contract.verificationInfo.artifacts.abi);
});
</script>

<style scoped lang="scss">
Expand Down Expand Up @@ -132,6 +147,7 @@ const sourceCode = computed<undefined | { code: string; label: string }[]>(() =>
@apply text-sm font-bold text-neutral-700;
}
.source-code-container,
.abi-json-field-container,
.bytecode-field-container {
@apply grid grid-cols-1 gap-2;
}
Expand Down
1 change: 1 addition & 0 deletions packages/app/src/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -375,6 +375,7 @@
"hide": "Hide"
},
"abiInteraction": {
"contractAbi": "Contract ABI",
"transactionHash": "Transaction Hash: {transactionHash}",
"connectWalletToInteract": "Connect Wallet to write",
"metaMaskNotFound": "MetaMask not found. Please install MetaMask to continue.",
Expand Down
3 changes: 3 additions & 0 deletions packages/app/src/locales/uk.json
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,9 @@
"verifyButton": "Завірити Смарт Контракт",
"deployedBytecode": "Розгорнутий байт-код",
"sourceCode": "Вихідний код"
},
"abiInteraction": {
"contractAbi": "ABI контракту"
}
},
"contractVerification": {
Expand Down
13 changes: 13 additions & 0 deletions packages/app/tests/components/contract/ContractBytecode.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,19 @@ describe("ContractBytecode", () => {
expect(codeBlocks[0].props().code).toBe(contract.verificationInfo?.request.sourceCode);
});

it("renders contract abi json when solidity single-file contract is verified", () => {
const wrapper = mount(ContractBytecode, {
global: {
plugins: [i18n, $testId],
stubs: ["router-link"],
},
props: {
contract,
},
});
expect(wrapper.find(".abi-json").text()).toBe(JSON.stringify(contract.verificationInfo?.artifacts.abi));
});

it("renders contract code when vyper single-file contract is verified", () => {
const verifiedContractSources = {
ERC20: contract.verificationInfo?.request.sourceCode,
Expand Down
1 change: 1 addition & 0 deletions packages/app/tests/e2e/testId.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{
"abiDataDropDown": "abi-data-dropdown",
"badge": "badge",
"statusBadge": "status-badge",
"blocksNumber": "blocks-number",
Expand Down

0 comments on commit 9dca4b2

Please sign in to comment.