Skip to content

Commit

Permalink
Add GET /v2/contract/{chainId}/{address} endpoint (#1874)
Browse files Browse the repository at this point in the history
* Update API v2 spec

* Add VerifiedContract type

* Add tests for GET /v2/contracts/:chainId/:address endpoint

* Add GET `/v2/contract/{chainId}/{address}` endpoint

* Update API v2 spec

* Add proxy detection to GET /v2/contract/{chainId}/{address} endpoint

* Don't deploy a contract in every test

* Fix naming of enpoint to `/v2/contract/{chainId}/{address}`

* Fix proxy-contract-util tests

* Address PR feedback
  • Loading branch information
manuelwedler committed Jan 30, 2025
1 parent d9a2b11 commit b6d8686
Show file tree
Hide file tree
Showing 19 changed files with 1,763 additions and 115 deletions.
98 changes: 71 additions & 27 deletions services/server/src/apiv2.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ paths:
schema:
type: string
examples:
- 'userDoc,devDoc,storageLayout,compilation.sources'
- 'userdoc,devdoc,storageLayout,compilation.sources'
- $ref: '#/components/parameters/chainId'
- $ref: '#/components/parameters/address'
responses:
Expand Down Expand Up @@ -392,6 +392,7 @@ components:
chainId: '11155111'
address: '0xDFEBAd708F803af22e81044aD228Ff77C83C935c'
verifiedAt: '2024-07-24T12:00:00Z'
matchId: '3266227'
Pending:
value:
isJobCompleted: false
Expand Down Expand Up @@ -437,9 +438,13 @@ components:
transactionHash:
$ref: '#/components/schemas/Keccak256'
blockNumber:
type: integer
type: string
examples:
- '21721660'
transactionIndex:
type: integer
type: string
examples:
- '3'
deployer:
$ref: '#/components/schemas/Address'
sources:
Expand Down Expand Up @@ -470,10 +475,6 @@ components:
type: string
examples:
- 'contracts/MyContract.sol:MyContract'
implementations:
type: array
items:
type: object
abi:
type: array
items:
Expand All @@ -482,9 +483,9 @@ components:
type: object
storageLayout:
type: object
userDoc:
userdoc:
type: object
devDoc:
devdoc:
type: object
stdJsonInput:
type: object
Expand Down Expand Up @@ -530,9 +531,9 @@ components:
type: array
items:
type: object
userDoc:
userdoc:
type: object
devDoc:
devdoc:
type: object
storageLayout:
type: object
Expand Down Expand Up @@ -579,6 +580,7 @@ components:
chainId: '11155111'
address: '0xDFEBAd708F803af22e81044aD228Ff77C83C935c'
verifiedAt: '2024-07-24T12:00:00Z'
matchId: '3266227'
creationBytecode:
onchainBytecode: '0x608060405234801561001057600080fd5b5060043610610036570565b6000819050919050565b600080fd5b61010c816100f4565b811461011757600080fd5b5056fea264697066735821220404e37f487a89a932dca5e77faaf6ca2de3b991f93d230604b1b8daaef64766264736f6c63430008070033'
recompiledBytecode: '0x608060405234801561001057600080fd5b5060043610610036570565b6000819050919050565b600080fd5b61010c816100f4565b811461011757600080fd5b5056fea264697066735821220404e37f487a89a932dca5e77faaf6ca2de3b991f93d230604b1b8daaef64766264736f6c63430008070033'
Expand Down Expand Up @@ -673,8 +675,8 @@ components:
callProtection: '0x9deba23b95205127e906108f191a26f5d520896a'
deployment:
transactionHash: '0xb6ee9d528b336942dd70d3b41e2811be10a473776352009fd73f85604f5ed206'
blockNumber: 0
transactionIndex: 0
blockNumber: '21721660'
transactionIndex: '0'
deployer: '0xDFEBAd708F803af22e81044aD228Ff77C83C935c'
sources:
contracts/Storage.sol:
Expand Down Expand Up @@ -707,19 +709,56 @@ components:
}
compilation:
language: Solidity
compiler: solc
compilerVersion: v0.8.12+commit.f00d7308
compilerSettings: {}
name: MyContract
fullyQualifiedName: 'contracts/MyContract.sol:MyContract'
isProxy: true
implementations:
- {}
abi:
- {}
userDoc: {}
devDoc: {}
userdoc: {}
devdoc: {}
storageLayout: {}
metadata: {}
stdJsonInput:
language: Solidity
sources:
contracts/Storage.sol:
content: |
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract Storage {
uint256 number;
function setNumber(uint256 newNumber) public {
number = newNumber;
}
function getNumber() public view returns (uint256) {
return number;
}
}
contracts/Owner.sol:
content: |
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract Owner {
address public owner;
constructor() {
owner = msg.sender;
}
}
settings: {}
stdJsonOutput:
sources: {}
contracts: {}
proxyResolution:
isProxy: false
proxyType: null
implementations: []
Minimal Response:
value:
match: exact_match
Expand All @@ -728,6 +767,7 @@ components:
chainId: '11155111'
address: '0xDFEBAd708F803af22e81044aD228Ff77C83C935c'
verifiedAt: '2024-07-24T12:00:00Z'
matchId: '3266227'
'`fields=creationBytecode.onchainBytecode,abi,deployment`':
value:
match: match
Expand All @@ -740,8 +780,8 @@ components:
onchainBytecode: '0x608060405234801561001057600080fd5b5060043610610036570565b6000819050919050565b600080fd5b61010c816100f4565b811461011757600080fd5b5056fea264697066735821220404e37f487a89a932dca5e77faaf6ca2de3b991f93d230604b1b8daaef64766264736f6c63430008070033'
deployment:
transactionHash: '0xb6ee9d528b336942dd70d3b41e2811be10a473776352009fd73f85604f5ed206'
blockNumber: 0
transactionIndex: 0
blockNumber: '21721660'
transactionIndex: '0'
deployer: '0xDFEBAd708F803af22e81044aD228Ff77C83C935c'
abi:
- {}
Expand All @@ -754,12 +794,12 @@ components:
address: '0xDFEBAd708F803af22e81044aD228Ff77C83C935c'
verifiedAt: '2024-07-24T12:00:00Z'
deployment:
blockNumber: 0
transactionIndex: 0
blockNumber: '21721660'
transactionIndex: '0'
abi:
- {}
userDoc: {}
devDoc: {}
userdoc: {}
devdoc: {}
storageLayout: {}
metadata: {}
Proxy resolution (`fields=proxyResolution`):
Expand Down Expand Up @@ -797,7 +837,10 @@ components:
address: '0xDFEBAd708F803af22e81044aD228Ff77C83C935c'
verifiedAt: '2024-07-24T12:00:00Z'
proxyResolution:
proxyResolutionError: RPC failed
proxyResolutionError:
customCode: proxy_resolution_error
message: RPC failed
errorId: 1ac6b91a-0605-4459-93dc-18f210a70192
ReturnVerificationJob:
description: |-
Successfully submitted the verification. The server started to process the verification.
Expand Down Expand Up @@ -979,7 +1022,8 @@ components:
- match
- creationMatch
- runtimeMatch
- matchId
- chainId
- address
VerificationStatusNullable:
type: string
enum:
Expand Down Expand Up @@ -1301,7 +1345,7 @@ components:
address:
$ref: '#/components/schemas/Address'
proxyResolutionError:
type: string
$ref: '#/components/schemas/GenericErrorResponse'
ProxyType:
type: string
enum:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ import logger from "../../../common/logger";
import { Services } from "../../services/services";
import {
detectAndResolveProxy,
ProxyType,
Implementation,
ProxyDetectionResult,
} from "../../services/utils/proxy-contract-util";
import { ChainRepository } from "../../../sourcify-chain-repository";
import { getAddress } from "ethers";
Expand Down Expand Up @@ -137,11 +138,7 @@ export async function checkAllByChainAndAddressEndpoint(
}

// Proxy detection and resolution
type Implementation = { address: string; name?: string };
let proxyStatus: {
isProxy?: boolean;
proxyType?: ProxyType | null;
implementations?: Implementation[];
let proxyStatus: Partial<ProxyDetectionResult> & {
proxyResolutionError?: string;
} = {};
if (
Expand All @@ -159,7 +156,7 @@ export async function checkAllByChainAndAddressEndpoint(
// Find contract names if the implementations are verified on Sourcify
const implementations = await Promise.all(
proxyDetectionResult.implementations.map(
async (implementationAddress) => {
async ({ address: implementationAddress }) => {
implementationAddress = getAddress(implementationAddress);
const implementation: Implementation = {
address: implementationAddress,
Expand Down
20 changes: 18 additions & 2 deletions services/server/src/server/apiv2/errors.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import { NotFoundError } from "../../common/errors";
import { BadRequestError, NotFoundError } from "../../common/errors";
import { v4 as uuidv4 } from "uuid";

export type ErrorCode = "unsupported_chain";
export type ErrorCode =
| "unsupported_chain"
| "invalid_parameter"
| "proxy_resolution_error";

export interface GenericErrorResponse {
customCode: ErrorCode;
Expand All @@ -21,3 +24,16 @@ export class ChainNotFoundError extends NotFoundError {
};
}
}

export class InvalidParametersError extends BadRequestError {
payload: GenericErrorResponse;

constructor(message: string) {
super(message);
this.payload = {
customCode: "invalid_parameter",
message,
errorId: uuidv4(),
};
}
}
Loading

0 comments on commit b6d8686

Please sign in to comment.