Skip to content

Commit

Permalink
feat: swagger working examples for all environments (#71)
Browse files Browse the repository at this point in the history
# What ❔

Dynamic swagger constants for different environments.

## Why ❔

Right now swagger examples are hardcoded and don't work on all envs
which might be confusing for users. In order to provide better developer
experience we want the default examples we provide to work on all envs
out of the box.

## 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.
  • Loading branch information
vasyl-ivanchuk authored Oct 30, 2023
1 parent fd5249c commit e777cf5
Show file tree
Hide file tree
Showing 12 changed files with 218 additions and 36 deletions.
1 change: 1 addition & 0 deletions packages/api/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,4 @@ DISABLE_BFF_API_SCHEMA_DOCS=false
DISABLE_EXTERNAL_API=false
DATABASE_STATEMENT_TIMEOUT_MS=90000
CONTRACT_VERIFICATION_API_URL=http://127.0.0.1:3070
NETWORK_NAME=testnet-goerli
9 changes: 7 additions & 2 deletions packages/api/nest-cli.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
{
"$schema": "https://json.schemastore.org/nest-cli",
"collection": "@nestjs/schematics",
"sourceRoot": "src"
}
"sourceRoot": "src",
"compilerOptions": {
"assets": [
"config/docs/constants.*.json"
]
}
}
7 changes: 4 additions & 3 deletions packages/api/src/address/address.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import { ParseAddressPipe, ADDRESS_REGEX_PATTERN } from "../common/pipes/parseAd
import { TransferService } from "../transfer/transfer.service";
import { TransferDto } from "../transfer/transfer.dto";
import { swagger } from "../config/featureFlags";
import { constants } from "../config/docs";

const entityName = "address";

Expand All @@ -46,7 +47,7 @@ export class AddressController {
@ApiParam({
name: "address",
schema: { pattern: ADDRESS_REGEX_PATTERN },
example: "0xd754ff5e8a6f257e162f72578a4bb0493c0681d8",
example: constants.address,
description: "Valid hex address",
})
@ApiExtraModels(AccountDto, ContractDto)
Expand Down Expand Up @@ -112,7 +113,7 @@ export class AddressController {
@ApiParam({
name: "address",
schema: { pattern: ADDRESS_REGEX_PATTERN },
example: "0xd754ff5e8a6f257e162f72578a4bb0493c0681d8",
example: constants.contractAddressWithLogs,
description: "Valid hex address",
})
@ApiListPageOkResponse(LogDto, { description: "Successfully returned address logs" })
Expand All @@ -136,7 +137,7 @@ export class AddressController {
@ApiParam({
name: "address",
schema: { pattern: ADDRESS_REGEX_PATTERN },
example: "0xd754ff5e8a6f257e162f72578a4bb0493c0681d8",
example: constants.address,
description: "Valid hex address",
})
@ApiListPageOkResponse(TransferDto, { description: "Successfully returned address transfers" })
Expand Down
14 changes: 14 additions & 0 deletions packages/api/src/api/api.controller.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,20 @@ describe("ApiController", () => {
});
});

describe("getInternalTransactionsByTxHash", () => {
it("returns null as it is defined only to appear in docs and cannot be called", async () => {
const result = await controller.getInternalTransactionsByTxHash(
{
page: 1,
offset: 10,
maxLimit: 10000,
},
{ sort: SortingOrder.Desc }
);
expect(result).toBe(null);
});
});

describe("getAccountTokenTransfers", () => {
it("returns null as it is defined only to appear in docs and cannot be called", async () => {
const result = await controller.getAccountTokenTransfers(
Expand Down
80 changes: 56 additions & 24 deletions packages/api/src/api/api.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ import { ParseModulePipe } from "./pipes/parseModule.pipe";
import { ParseActionPipe } from "./pipes/parseAction.pipe";
import { ApiExceptionFilter } from "./exceptionFilter";
import { LogsResponseDto, LogApiDto } from "./dtos/log/logs.dto";
import { constants } from "../config/docs";

@Controller("")
export class ApiController {
Expand Down Expand Up @@ -82,7 +83,7 @@ export class ApiController {
@ApiQuery({
name: "address",
description: "The contract address that has a verified source code",
example: "0x8A63F953e19aA4Ce3ED90621EeF61E17A95c6594",
example: constants.verifiedContractAddress,
required: true,
})
@ApiOkResponse({
Expand All @@ -99,7 +100,7 @@ export class ApiController {
@ApiQuery({
name: "address",
description: "The contract address that has a verified source code",
example: "0x8A63F953e19aA4Ce3ED90621EeF61E17A95c6594",
example: constants.verifiedContractAddress,
required: true,
})
@ApiOkResponse({
Expand All @@ -118,7 +119,7 @@ export class ApiController {
explode: false,
name: "contractaddresses",
description: "List of contract addresses, up to 5 at a time",
example: ["0x8A63F953e19aA4Ce3ED90621EeF61E17A95c6594", "0x0E03197d697B592E5AE49EC14E952cddc9b28e14"],
example: [constants.verifiedContractAddress, constants.verifiedContractAddress2],
required: true,
})
@ApiExtraModels(ContractCreationInfoDto)
Expand Down Expand Up @@ -165,7 +166,7 @@ export class ApiController {
@ApiQuery({
name: "txhash",
description: "The transaction hash to check the execution status",
example: "0x04a4757cd59681b037c1e7bd2402cc45a23c66ed7497614879376719d34e020a",
example: constants.txHash,
required: true,
})
@ApiExtraModels(TransactionStatusDto)
Expand All @@ -183,7 +184,7 @@ export class ApiController {
@ApiQuery({
name: "txhash",
description: "The transaction hash to check the execution status",
example: "0x04a4757cd59681b037c1e7bd2402cc45a23c66ed7497614879376719d34e020a",
example: constants.txHash,
required: true,
})
@ApiOkResponse({
Expand All @@ -200,7 +201,7 @@ export class ApiController {
@ApiQuery({
name: "address",
description: "The address to filter transactions by",
example: "0xFb7E0856e44Eff812A44A9f47733d7d55c39Aa28",
example: constants.address,
required: true,
})
@ApiQuery({
Expand Down Expand Up @@ -232,18 +233,49 @@ export class ApiController {
}

@ApiTags("Account API")
@Get("api?module=account&action=txlistinternal")
@ApiOperation({ summary: "Retrieve internal transactions for a given address or transaction hash" })
@Get("api?module=account&action=txlistinternal&address=")
@ApiOperation({ summary: "Retrieve internal transactions for a given address" })
@ApiQuery({
name: "address",
description: "The address to filter internal transactions by",
example: "0xFb7E0856e44Eff812A44A9f47733d7d55c39Aa28",
example: constants.addressWithInternalTx,
required: false,
})
@ApiQuery({
name: "startblock",
type: "integer",
description: "The block number to start searching for internal transactions",
example: 0,
required: false,
})
@ApiQuery({
name: "endblock",
type: "integer",
description: "The block number to stop searching for internal transactions",
example: 99999999,
required: false,
})
@ApiExtraModels(AccountInternalTransactionDto)
@ApiOkResponse({
description: "Internal transactions list",
type: AccountInternalTransactionsResponseDto,
})
public async getAccountInternalTransactions(
// eslint-disable-next-line @typescript-eslint/no-unused-vars
@Query() pagingOptions: PagingOptionsWithMaxItemsLimitDto,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
@Query() sortingOptions: SortingOptionsDto
): Promise<AccountInternalTransactionsResponseDto> {
return null;
}

@ApiTags("Account API")
@Get("api?module=account&action=txlistinternal&txhash=")
@ApiOperation({ summary: "Retrieve internal transactions for a given transaction hash" })
@ApiQuery({
name: "txhash",
description: "The transaction hash to filter internal transaction by",
example: "0x04a4757cd59681b037c1e7bd2402cc45a23c66ed7497614879376719d34e020a",
example: constants.addressTxWithInternalTransfers,
required: false,
})
@ApiQuery({
Expand All @@ -265,7 +297,7 @@ export class ApiController {
description: "Internal transactions list",
type: AccountInternalTransactionsResponseDto,
})
public async getAccountInternalTransactions(
public async getInternalTransactionsByTxHash(
// eslint-disable-next-line @typescript-eslint/no-unused-vars
@Query() pagingOptions: PagingOptionsWithMaxItemsLimitDto,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
Expand All @@ -280,7 +312,7 @@ export class ApiController {
@ApiQuery({
name: "address",
description: "The address to get Ether balance for",
example: "0xFb7E0856e44Eff812A44A9f47733d7d55c39Aa28",
example: constants.address,
required: true,
})
@ApiOkResponse({
Expand All @@ -299,7 +331,7 @@ export class ApiController {
explode: false,
name: "address",
description: "List of addresses to get Ether balance for",
example: ["0xFb7E0856e44Eff812A44A9f47733d7d55c39Aa28", "0x0E03197d697B592E5AE49EC14E952cddc9b28e14"],
example: [constants.address, constants.addressWithInternalTx],
required: true,
})
@ApiOkResponse({
Expand All @@ -316,13 +348,13 @@ export class ApiController {
@ApiQuery({
name: "address",
description: "The address to get Token balance for",
example: "0xFb7E0856e44Eff812A44A9f47733d7d55c39Aa28",
example: constants.address,
required: true,
})
@ApiQuery({
name: "contractaddress",
description: "The Token contract address to get balance for",
example: "0x0faF6df7054946141266420b43783387A78d82A9",
example: constants.tokenAddress,
required: true,
})
@ApiOkResponse({
Expand All @@ -339,13 +371,13 @@ export class ApiController {
@ApiQuery({
name: "address",
description: "The address to get transfers for",
example: "0xFb7E0856e44Eff812A44A9f47733d7d55c39Aa28",
example: constants.address,
required: false,
})
@ApiQuery({
name: "contractaddress",
description: "The Token contract address to get transfers for",
example: "0x0faF6df7054946141266420b43783387A78d82A9",
example: constants.tokenAddress,
required: false,
})
@ApiQuery({
Expand Down Expand Up @@ -382,13 +414,13 @@ export class ApiController {
@ApiQuery({
name: "address",
description: "The address to get transfers for",
example: "0xFb7E0856e44Eff812A44A9f47733d7d55c39Aa28",
example: constants.address,
required: false,
})
@ApiQuery({
name: "contractaddress",
description: "The Token contract address to get transfers for",
example: "0x0faF6df7054946141266420b43783387A78d82A9",
example: constants.tokenAddress,
required: false,
})
@ApiQuery({
Expand Down Expand Up @@ -472,7 +504,7 @@ export class ApiController {
name: "blockno",
type: "integer",
description: "The integer block number to estimate time remaining to be mined",
example: 12697906,
example: 20697906,
required: true,
})
@ApiOkResponse({
Expand All @@ -490,7 +522,7 @@ export class ApiController {
name: "blockno",
type: "integer",
description: "The integer block number to check block rewards",
example: 12697906,
example: 1500,
required: true,
})
@ApiOkResponse({
Expand All @@ -507,21 +539,21 @@ export class ApiController {
@ApiQuery({
name: "address",
description: "The address to filter logs by",
example: "0xFb7E0856e44Eff812A44A9f47733d7d55c39Aa28",
example: constants.contractAddressWithLogs,
required: true,
})
@ApiQuery({
name: "fromBlock",
type: "integer",
description: "The integer block number to start searching for logs",
example: 12878196,
example: 0,
required: false,
})
@ApiQuery({
name: "toBlock",
type: "integer",
description: "The integer block number to stop searching for logs ",
example: 12879196,
example: 99999999,
required: false,
})
@ApiExtraModels(LogApiDto)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@ export class VerifyContractRequestDto {
},
sources: {
"contracts/HelloWorld.sol": {
content: "// SPDX-License-Identifier: UNLICENSED ..",
content:
"// SPDX-License-Identifier: UNLICENSED\n// Specifies the version of Solidity, using semantic versioning.\n// Learn more: https://solidity.readthedocs.io/en/v0.5.10/layout-of-source-files.html#pragma\npragma solidity >=0.7.3;\n\n// Defines a contract named `HelloWorld`.\n// A contract is a collection of functions and data (its state). Once deployed, a contract resides at a specific address on the Ethereum blockchain. Learn more: https://solidity.readthedocs.io/en/v0.5.10/structure-of-a-contract.html\ncontract HelloWorld {\n\n //Emitted when update function is called\n //Smart contract events are a way for your contract to communicate that something happened on the blockchain to your app front-end, which can be 'listening' for certain events and take action when they happen.\n event UpdatedMessages(string oldStr, string newStr);\n\n // Declares a state variable `message` of type `string`.\n // State variables are variables whose values are permanently stored in contract storage. The keyword `public` makes variables accessible from outside a contract and creates a function that other contracts or clients can call to access the value.\n string public message;\n\n // Similar to many class-based object-oriented languages, a constructor is a special function that is only executed upon contract creation.\n // Constructors are used to initialize the contract's data. Learn more:https://solidity.readthedocs.io/en/v0.5.10/contracts.html#constructors\n constructor(string memory initMessage) {\n\n // Accepts a string argument `initMessage` and sets the value into the contract's `message` storage variable).\n message = initMessage;\n }\n\n // A public function that accepts a string argument and updates the `message` storage variable.\n function update(string memory newMessage) public {\n string memory oldMsg = message;\n message = newMessage;\n emit UpdatedMessages(oldMsg, newMessage);\n }\n}",
},
},
},
Expand Down Expand Up @@ -125,7 +126,8 @@ export class VerifyContractRequestDto {
@ApiProperty({
name: "constructorArguements",
description: "Contract constructor arguments",
example: "0x94869207468657265210000000000000000000000000000000000000000000000",
example:
"0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000094869207468657265210000000000000000000000000000000000000000000000",
required: false,
})
@IsOptional()
Expand Down
10 changes: 10 additions & 0 deletions packages/api/src/config/docs/constants.mainnet.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"verifiedContractAddress": "0x2da10A1e27bF85cEdD8FFb1AbBe97e53391C0295",
"verifiedContractAddress2": "0x1fa66e2B38d0cC496ec51F81c3e05E6A6708986F",
"contractAddressWithLogs": "0x1fa66e2B38d0cC496ec51F81c3e05E6A6708986F",
"txHash": "0xbca76582802d8172fe5bf6ba9c42d675a2ceab858dff555929f2c4021bf77386",
"address": "0xd3D526A8CCA22Fe072cD1852faA4F0a6F2C21765",
"addressWithInternalTx": "0x8B021d2BeD73675F7715422C4BFcBfE759890308",
"addressTxWithInternalTransfers": "0x4683986b4d6b07aa5a8ba6c4a6aa7b1a420a0dfd944ac7128f3e4ab7bd74567c",
"tokenAddress": "0x000000000000000000000000000000000000800A"
}
10 changes: 10 additions & 0 deletions packages/api/src/config/docs/constants.testnet-goerli.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"verifiedContractAddress": "0x53E185A2FA7c9caF14A887E8E9a4862D4bd094ea",
"verifiedContractAddress2": "0xbf2A1ACE3B12b81bab4985f05E850AcFCCb416E0",
"contractAddressWithLogs": "0xbf2A1ACE3B12b81bab4985f05E850AcFCCb416E0",
"txHash": "0x3d36c6e6a3625d698ef41d20c9457a6628254c8307df54b7c887e30f7dda00c8",
"address": "0xE4ce1da467a7Ca37727eb7e19857e5167DE25966",
"addressWithInternalTx": "0xbf2A1ACE3B12b81bab4985f05E850AcFCCb416E0",
"addressTxWithInternalTransfers": "0x8a453b8dd3e095b3034dc3692663d5bf0c9883cbe6e9f9a0425a3ebf9b9360ab",
"tokenAddress": "0x000000000000000000000000000000000000800A"
}
Loading

0 comments on commit e777cf5

Please sign in to comment.