Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions plugins/evm/dao/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ type ISrv interface {
BlockByHash(ctx context.Context, hash string) *EvmBlock
TransactionsCursor(ctx context.Context, limit int, before, after *uint, opts ...model.Option) ([]TransactionSampleJson, map[string]interface{})
AccountsCursor(ctx context.Context, address string, limit int, before, after *string) ([]AccountsJson, map[string]interface{})
ContractsCursor(ctx context.Context, limit int, before, after *string) ([]ContractsJson, map[string]interface{})
ContractsCursor(ctx context.Context, limit int, before, after *string, verifiedSourceOnly bool) ([]ContractsJson, map[string]interface{})

AccountTokens(ctx context.Context, address, category string) []AccountTokenJson
CollectiblesCursor(ctx context.Context, address string, contract string, limit int, before, after *string) ([]Erc721Holders, map[string]interface{})
Expand Down Expand Up @@ -541,10 +541,13 @@ func (c ContractsJson) Cursor() string {
return util.Base64Encode(fmt.Sprintf("%d_%s", c.TransactionCount, c.Address))
}

func (a *ApiSrv) ContractsCursor(ctx context.Context, limit int, before, after *string) ([]ContractsJson, map[string]interface{}) {
func (a *ApiSrv) ContractsCursor(ctx context.Context, limit int, before, after *string, verifiedSourceOnly bool) ([]ContractsJson, map[string]interface{}) {
var list []ContractsJson
fetch := limit + 1
q := sg.db.WithContext(ctx).Model(&Contract{}).Select("contract_name,address,transaction_count,verify_status")
if verifiedSourceOnly {
q = q.Where("verify_status = ? AND source_code IS NOT NULL AND source_code <> ?", "verified", "")
}
if cursor := cursorDecode(after); len(cursor) == 2 {
q = q.Where("(transaction_count,address) < (?,?)", cursor[0], cursor[1]).Order("transaction_count desc").Order("address desc")
} else if cursor = cursorDecode(before); len(cursor) == 2 {
Expand Down
39 changes: 39 additions & 0 deletions plugins/evm/dao/api_cursor_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,3 +69,42 @@ func TestAccountsCursorBeforeUsesBeforeCursor(t *testing.T) {
assert.Equal(t, false, page["has_previous_page"])
assert.Equal(t, true, page["has_next_page"])
}

func TestContractsCursorVerifiedSourceOnly(t *testing.T) {
db, err := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{})
require.NoError(t, err)
require.NoError(t, db.AutoMigrate(&Contract{}))

sg = &Storage{db: db}

ctx := context.Background()
contracts := []Contract{
{
Address: "0x0000000000000000000000000000000000000001",
ContractName: "VerifiedWithSource",
VerifyStatus: "verified",
SourceCode: "pragma solidity ^0.8.0; contract VerifiedWithSource {}",
TransactionCount: 30,
},
{
Address: "0x0000000000000000000000000000000000000002",
ContractName: "VerifiedWithoutSource",
VerifyStatus: "verified",
TransactionCount: 20,
},
{
Address: "0x0000000000000000000000000000000000000003",
ContractName: "UnverifiedWithSource",
SourceCode: "pragma solidity ^0.8.0; contract UnverifiedWithSource {}",
TransactionCount: 10,
},
}
require.NoError(t, db.Create(&contracts).Error)

list, page := (&ApiSrv{}).ContractsCursor(ctx, 10, nil, nil, true)

require.Len(t, list, 1)
assert.Equal(t, "VerifiedWithSource", list[0].ContractName)
assert.Equal(t, "verified", list[0].VerifyStatus)
assert.Equal(t, false, page["has_next_page"])
}
2 changes: 1 addition & 1 deletion plugins/evm/http/api_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ func (m MockServer) AccountsCursor(ctx context.Context, address string, limit in
return nil, nil
}

func (m MockServer) ContractsCursor(ctx context.Context, limit int, before, after *string) ([]dao.ContractsJson, map[string]interface{}) {
func (m MockServer) ContractsCursor(ctx context.Context, limit int, before, after *string, verifiedSourceOnly bool) ([]dao.ContractsJson, map[string]interface{}) {
return nil, nil
}

Expand Down
9 changes: 5 additions & 4 deletions plugins/evm/http/http.go
Original file line number Diff line number Diff line change
Expand Up @@ -342,9 +342,10 @@ func contractHandle(w http.ResponseWriter, r *http.Request) error {
}

type contractsParams struct {
Limit int `json:"row" validate:"min=1,max=100"`
Before *string `json:"before" validate:"omitempty,min=0"`
After *string `json:"after" validate:"omitempty,min=0"`
Limit int `json:"row" validate:"min=1,max=100"`
Before *string `json:"before" validate:"omitempty,min=0"`
After *string `json:"after" validate:"omitempty,min=0"`
VerifiedSourceOnly bool `json:"verified_source"`
}

// @Summary Evm contract list
Expand All @@ -360,7 +361,7 @@ func contractsHandle(w http.ResponseWriter, r *http.Request) error {
toJson(w, 10001, nil, err)
return nil
}
list, page := srv.ContractsCursor(r.Context(), p.Limit, p.Before, p.After)
list, page := srv.ContractsCursor(r.Context(), p.Limit, p.Before, p.After, p.VerifiedSourceOnly)
toJson(w, 0, map[string]interface{}{"list": list, "pagination": page}, nil)
return nil
}
Expand Down
89 changes: 48 additions & 41 deletions ui-react/src/components/contract/contractTable.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React, { useMemo } from 'react'
import React from 'react'

import { BareProps } from '@/types/page'
import { Table, TableHeader, TableColumn, TableBody, TableRow, TableCell, getKeyValue, Spinner } from '@heroui/react'
import { Table, TableHeader, TableColumn, TableBody, TableRow, TableCell, getKeyValue, Spinner, Switch } from '@heroui/react'
import { getPVMContractListParams, unwrap, usePVMContracts } from '@/utils/api'
import { PAGE_SIZE } from '@/utils/const'
import { useData } from '@/context'
Expand All @@ -18,11 +18,13 @@ const Component: React.FC<Props> = ({ children, className, args }) => {
const { metadata, token } = useData()
const [page, setPage] = React.useState(1)
const [cursor, setCursor] = React.useState<{ after?: number; before?: number }>({})
const [verifiedSourceOnly, setVerifiedSourceOnly] = React.useState(false)
const rowsPerPage = PAGE_SIZE
const NEXT_PUBLIC_API_HOST = env('NEXT_PUBLIC_API_HOST') || ''
const { data, isLoading } = usePVMContracts(NEXT_PUBLIC_API_HOST, {
...args,
row: rowsPerPage,
verified_source: verifiedSourceOnly,
...cursor,
})
const contractsData = unwrap(data)
Expand All @@ -41,46 +43,51 @@ const Component: React.FC<Props> = ({ children, className, args }) => {
setPage(page + 1)
}
}
const handleVerifiedSourceChange = (selected: boolean) => {
setVerifiedSourceOnly(selected)
setCursor({})
setPage(1)
}
return (
<Table
aria-label="Table"
bottomContent={
<CursorPagination
pagination={pagination}
onPrevious={handlePrevious}
onNext={handleNext}
color={getThemeColor()}
/>
}
classNames={{
wrapper: 'min-h-[222px]',
td: 'h-[50px]',
}}>
<TableHeader>
<TableColumn key="address">Contract</TableColumn>
<TableColumn key="contract_name">Name</TableColumn>
<TableColumn key="transaction_count">Transaction</TableColumn>
<TableColumn key="verify_status">Status</TableColumn>
</TableHeader>
<TableBody isLoading={isLoading} loadingContent={<Spinner color={getThemeColor()} />} items={items || []} emptyContent={'No data'}>
{(item) => (
<TableRow key={item.address}>
{(columnKey) => {
if (columnKey === 'address') {
return (
<TableCell>
<Link href={`/contract/${item.address}`}>{item.address}</Link>
</TableCell>
)
} else if (columnKey === 'verify_status') {
return <TableCell>{item.verify_status === 'verified' ? 'Verified' : 'Unverified'}</TableCell>
}
return <TableCell>{getKeyValue(item, columnKey)}</TableCell>
}}
</TableRow>
)}
</TableBody>
</Table>
<div className="space-y-3">
<div className="flex justify-end">
<Switch size="sm" isSelected={verifiedSourceOnly} onValueChange={handleVerifiedSourceChange}>
Verified source only
</Switch>
</div>
<Table
aria-label="Table"
bottomContent={<CursorPagination pagination={pagination} onPrevious={handlePrevious} onNext={handleNext} color={getThemeColor()} />}
classNames={{
wrapper: 'min-h-[222px]',
td: 'h-[50px]',
}}>
<TableHeader>
<TableColumn key="address">Contract</TableColumn>
<TableColumn key="contract_name">Name</TableColumn>
<TableColumn key="transaction_count">Transaction</TableColumn>
<TableColumn key="verify_status">Status</TableColumn>
</TableHeader>
<TableBody isLoading={isLoading} loadingContent={<Spinner color={getThemeColor()} />} items={items || []} emptyContent={'No data'}>
{(item) => (
<TableRow key={item.address}>
{(columnKey) => {
if (columnKey === 'address') {
return (
<TableCell>
<Link href={`/contract/${item.address}`}>{item.address}</Link>
</TableCell>
)
} else if (columnKey === 'verify_status') {
return <TableCell>{item.verify_status === 'verified' ? 'Verified' : 'Unverified'}</TableCell>
}
return <TableCell>{getKeyValue(item, columnKey)}</TableCell>
}}
</TableRow>
)}
</TableBody>
</Table>
</div>
)
}

Expand Down
2 changes: 1 addition & 1 deletion ui-react/src/components/contract/info.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ const Component: React.FC<Props> = ({ children, className, contract }) => {
<div>
<div className="mb-2">Contract Source Code</div>
<div>
<OverflowText text={contract.source_code} />
{contract.source_code ? <OverflowText text={contract.source_code} /> : <div>No uploaded source code is stored for this contract.</div>}
</div>
</div>
<div>
Expand Down
7 changes: 6 additions & 1 deletion ui-react/src/pages/contract/[id].tsx
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,12 @@ export default function Page() {
{contractData.verify_status === 'verified' ? (
<ContractInfo contract={contractData}></ContractInfo>
) : (
<ContractVerify address={id} />
<div className="space-y-4">
<div className="rounded-lg border border-default-200 bg-default-100 p-4 text-sm">
Source code has not been uploaded for this contract.
</div>
<ContractVerify address={id} />
</div>
)}
</Tab>
<Tab key="transactions" title="Transactions">
Expand Down
1 change: 1 addition & 0 deletions ui-react/src/utils/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -649,6 +649,7 @@ export type getPVMContractListParams = {
row?: number
after?: number
before?: number
verified_source?: boolean
}

type getPVMContractParams = {
Expand Down
Loading