Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add GET /v2/contract/{chainId}/{address} endpoint #1874

Merged
merged 10 commits into from
Jan 29, 2025
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