Skip to content
Merged
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
16 changes: 7 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ a 32-byte hex string (`0x` followed by 64 hexadecimal digits) that denotes the b

- [`/node/version` fetch information about the Substrates node's implementation and versioning.](src/controllers/node/NodeVersionController.ts)

- [`/runtime/metadata` fetch the runtime metadata in decoded, JSON form.](src/controllers/runtime/RuntimeMetadataController.ts) (replaces `/metadata`)
- [`/runtime/metadata` fetch the runtime metadata in decoded, JSON form.](src/controllers/runtime/RuntimeMetadataController.ts) (Replaces `/metadata`.)

- [`/runtime/code` fetch the Wasm code blob of the Substrate runtime.](src/controllers/runtime/RuntimeCodeController.ts)

Expand All @@ -116,15 +116,13 @@ a 32-byte hex string (`0x` followed by 64 hexadecimal digits) that denotes the b

- [`/claims/ADDRESS/NUMBER` fetch claims data for an Ethereum `ADDRESS` at the block identified by 'NUMBER`.](src/controllers/claims/ClaimsController.ts)

- [`/tx/artifacts/` fetch artifacts used for creating transactions at latest finalized block.](src/controllers/transaction/TransactionMaterialController.ts)
- [`/transaction/material` fetch all the network information needed to construct a transaction offline.](src/controllers/transaction/TransactionMaterialController.ts) (Replaces `/tx/artifacts`.)

- [`/tx/artifacts/NUMBER` fetch artifacts used for creating transactions at the block identified by 'NUMBER`.](src/controllers/transaction/TransactionMaterialController.ts)

- [`/tx/fee-estimate` submit a transaction in order to get back a fee estimation.](src/controllers/transaction/TransactionFeeEstimateController.ts) Expects a string
- [`/transaction/fee-estimate` submit a transaction in order to get back a fee estimation.](src/controllers/transaction/TransactionFeeEstimateController.ts) (Replaces `/tx/fee-estimate`.) Expects a string
with a hex-encoded transaction in a JSON POST body:

```
curl localhost:8080/tx/fee-estimate -X POST --data '{"tx": "0x..."}' -H 'Content-Type: application/json'
curl localhost:8080/transaction/fee-estimate -X POST --data '{"tx": "0x..."}' -H 'Content-Type: application/json'
```

Expected result is a JSON with fee information:
Expand All @@ -137,10 +135,10 @@ a 32-byte hex string (`0x` followed by 64 hexadecimal digits) that denotes the b
}
```

- [`/tx/` submit a signed transaction.](src/controllers/transaction/TransactionSubmitController.ts) Expects a string with hex-encoded transaction in a JSON POST
- [`/transaction` submit a signed transaction.](src/controllers/transaction/TransactionSubmitController.ts) (Replaces `/tx`.) Expects a string with hex-encoded transaction in a JSON POST
body:
```
curl localhost:8080/tx/ -X POST --data '{"tx": "0x..."}' -H 'Content-Type: application/json'
curl localhost:8080/transaction -X POST --data '{"tx": "0x..."}' -H 'Content-Type: application/json'
```
Expected result is a JSON with transaction hash:
```
Expand All @@ -149,7 +147,7 @@ a 32-byte hex string (`0x` followed by 64 hexadecimal digits) that denotes the b
}
```

- [`transaction/dry-run` dry run a transaction to check if it is valid.](src/controllers/transaction/TransactionDryRunController.ts)
- [`/transaction/dry-run` dry run a transaction to check if it is valid.](src/controllers/transaction/TransactionDryRunController.ts)
Expects a string with hex-encoded transaction in a JSON POST
body:
```
Expand Down
44 changes: 34 additions & 10 deletions openapi/openapi-proposal.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -366,8 +366,15 @@ paths:
tags:
- transaction
summary: Receive a fee estimate for a transaction.
description: Send a serialized transaction and receive back a naive fee
estimate. Replaces `/tx/fee-estimate` from versions < v1.0.0.
description: >-
Send a serialized transaction and receive back a naive fee estimate.
Note: `partialFee` does not include any tips that you may add to increase
a transaction's priority. See the reference on `compute_fee`.
Replaces `/tx/fee-estimate` from versions < v1.0.0.
Substrate Reference:
- `RuntimeDispatchInfo`: https://crates.parity.io/pallet_transaction_payment_rpc_runtime_api/struct.RuntimeDispatchInfo.html
- `query_info`: https://crates.parity.io/pallet_transaction_payment/struct.Module.html#method.query_info
- `compute_fee`: https://crates.parity.io/pallet_transaction_payment/struct.Module.html#method.compute_fee
operationId: feeEstimateTransaction
requestBody:
$ref: '#/components/requestBodies/Transaction'
Expand All @@ -388,7 +395,7 @@ paths:
get:
tags:
- transaction
summary: Get the baseline material to construct a transaction.
summary: Get all the network information needed to construct a transaction offline.
description: Returns the material that is universal to constructing any
signed transaction offline. Replaces `/tx/artifacts` from versions < v1.0.0.
operationId: getTransactionMaterial
Expand All @@ -402,6 +409,13 @@ paths:
type: string
description: Block identifier, as the block height or block hash.
format: unsignedInteger or $hex
- name: noMeta
in: query
schema:
type: boolean
description: If true, does not return metadata hex. This is useful when
metadata is not needed and response time is a concern. Defaults to false.
default: false
responses:
"200":
description: successful operation
Expand Down Expand Up @@ -1784,7 +1798,7 @@ components:
Transaction:
type: object
properties:
transaction:
tx:
type: string
format: hex
TransactionMaterial:
Expand Down Expand Up @@ -1814,12 +1828,16 @@ components:
metadata:
type: string
description: The chain's metadata in hex format.
format: hexScaleEncoded
format: hex
description: >-
Note: `chainName`, `specName`, and `specVersion` are used to define a type registry with a set
of signed extensions and types. For Polkadot and Kusama, `chainName` is not used in defining
this registry, but in other Substrate-based chains that re-launch their network without
changing the `specName`, the `chainName` would be needed to create the correct registry.
Substrate Reference:
- `RuntimeVersion`: https://crates.parity.io/sp_version/struct.RuntimeVersion.html
- `SignedExtension`: https://crates.parity.io/sp_runtime/traits/trait.SignedExtension.html
- FRAME Support: https://crates.parity.io/frame_support/metadata/index.html
TransactionSuccess:
type: object
properties:
Expand All @@ -1831,7 +1849,7 @@ components:
properties:
code:
type: number
message:
error:
type: string
description: >-
`Failed to parse a tx.`
Expand All @@ -1848,9 +1866,9 @@ components:
properties:
code:
type: number
message:
error:
type: string
description: Failed to submit a tx
description: Failed to submit transaction.
transaction:
type: string
format: hex
Expand All @@ -1869,9 +1887,14 @@ components:
properties:
code:
type: number
message:
at:
type: object
properties:
hash:
type: string
error:
type: string
description: Unable to fetch fee info
description: Error description.
transaction:
type: string
format: hex
Expand All @@ -1880,6 +1903,7 @@ components:
description: Block hash of the block fee estimation was attempted at.
cause:
type: string
description: Error message from the client.
stack:
type: string
TransactionFeeEstimate:
Expand Down
76 changes: 76 additions & 0 deletions src/controllers/transaction/TransactionFeeEstimateController.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import { ApiPromise } from '@polkadot/api';

import { TransactionFeeEstimateService } from '../../services';
import { IPostRequestHandler, ITx } from '../../types/requests';
import AbstractController from '../AbstractController';

/**
* POST a serialized transaction and receive a fee estimate.
*
* Post info:
* - `data`: Expects a hex-encoded transaction, e.g. '{"tx": "0x..."}'.
* - `headers`: Expects 'Content-Type: application/json'.
*
* Returns:
* - Success:
* - `weight`: Extrinsic weight.
* - `class`: Extrinsic class, one of 'Normal', 'Operational', or 'Mandatory'.
* - `partialFee`: _Expected_ inclusion fee for the transaction. Note that the fee rate changes
* up to 30% in a 24 hour period and this will not be the exact fee.
* - Failure:
* - `error`: Error description.
* - `extrinsic`: The extrinsic and reference block hash.
* - `cause`: Error message from the client.
*
* Note: `partialFee` does not include any tips that you may add to increase a transaction's
* priority. See the reference on `compute_fee`.
*
* Substrate Reference:
* - `RuntimeDispatchInfo`: https://crates.parity.io/pallet_transaction_payment_rpc_runtime_api/struct.RuntimeDispatchInfo.html
* - `query_info`: https://crates.parity.io/pallet_transaction_payment/struct.Module.html#method.query_info
* - `compute_fee`: https://crates.parity.io/pallet_transaction_payment/struct.Module.html#method.compute_fee
*/
export default class TransactionFeeEstimateController extends AbstractController<
TransactionFeeEstimateService
> {
constructor(api: ApiPromise) {
super(
api,
'/transaction/fee-estimate',
new TransactionFeeEstimateService(api)
);
this.initRoutes();
}

protected initRoutes(): void {
this.router.post(
this.path,
TransactionFeeEstimateController.catchWrap(this.txFeeEstimate)
);
}

/**
* Submit a serialized transaction in order to receive an estimate for its
* partial fees.
*
* @param req Sidecar TxRequest
* @param res Express Response
*/
private txFeeEstimate: IPostRequestHandler<ITx> = async (
{ body: { tx } },
res
): Promise<void> => {
if (!tx) {
throw {
error: 'Missing field `tx` on request body.',
};
}

const hash = await this.api.rpc.chain.getFinalizedHead();

TransactionFeeEstimateController.sanitizedSend(
res,
await this.service.fetchTransactionFeeEstimate(hash, tx)
);
};
}
72 changes: 72 additions & 0 deletions src/controllers/transaction/TransactionMaterialController.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import { ApiPromise } from '@polkadot/api';
import { RequestHandler } from 'express';

import { TransactionMaterialService } from '../../services';
import AbstractController from '../AbstractController';

/**
* GET all the network information needed to construct a transaction offline.
*
* Query
* - (Optional) `noMeta`: If true, does not return metadata hex. This is useful when metadata is not
* needed and response time is a concern. Defaults to false.
* - (Optional) `at`: Block hash or number at which to query. If not provided, queries
* finalized head.
*
* Returns:
* - `at`: Block number and hash at which the call was made.
* - `genesisHash`: The hash of the chain's genesis block.
* - `chainName`: The chain's name.
* - `specName`: The chain's spec.
* - `specVersion`: The spec version. Always increased in a runtime upgrade.
* - `txversion`: The transaction version. Common `txVersion` numbers indicate that the
* transaction encoding format and method indices are the same. Needed for decoding in an
* offline environment. Adding new transactions does not change `txVersion`.
* - `metadata`: The chain's metadata in hex format.
*
* Note: `chainName`, `specName`, and `specVersion` are used to define a type registry with a set
* of signed extensions and types. For Polkadot and Kusama, `chainName` is not used in defining
* this registry, but in other Substrate-based chains that re-launch their network without
* changing the `specName`, the `chainName` would be needed to create the correct registry.
*
* Substrate Reference:
* - `RuntimeVersion`: https://crates.parity.io/sp_version/struct.RuntimeVersion.html
* - `SignedExtension`: https://crates.parity.io/sp_runtime/traits/trait.SignedExtension.html
* - FRAME Support: https://crates.parity.io/frame_support/metadata/index.html
*/
export default class TransactionMaterialController extends AbstractController<
TransactionMaterialService
> {
constructor(api: ApiPromise) {
super(
api,
'/transaction/material',
new TransactionMaterialService(api)
);
this.initRoutes();
}

protected initRoutes(): void {
this.safeMountAsyncGetHandlers([['', this.getTransactionMaterial]]);
}

/**
* GET all the network information needed to construct a transaction offline.
*
* @param _req Express Request
* @param res Express Response
*/
private getTransactionMaterial: RequestHandler = async (
{ query: { noMeta, at } },
res
): Promise<void> => {
const hash = await this.getHashFromAt(at);

const noMetaArg = noMeta === 'true' ? true : false;

TransactionMaterialController.sanitizedSend(
res,
await this.service.fetchTransactionMaterial(hash, noMetaArg)
);
};
}
59 changes: 59 additions & 0 deletions src/controllers/transaction/TransactionSubmitController.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import { ApiPromise } from '@polkadot/api';

import { TransactionSubmitService } from '../../services';
import { IPostRequestHandler, ITx } from '../../types/requests';
import AbstractController from '../AbstractController';

/**
* POST a serialized transaction to submit to the transaction queue.
*
* Post info:
* - `data`: Expects a hex-encoded transaction, e.g. '{"tx": "0x..."}'.
* - `headers`: Expects 'Content-Type: application/json'.
*
* Returns:
* - Success:
* - `hash`: The hash of the encoded transaction.
* - Failure:
* - `error`: 'Failed to parse transaction' or 'Failed to submit transaction'. In the case of the former,
* Sidecar was unable to parse the transaction and never submitted it to the client. In
* the case of the latter, the transaction queue rejected the transaction.
* - `extrinsic`: The hex-encoded extrinsic. Only present if Sidecar fails to parse a transaction.
* - `cause`: The error message from parsing or from the client.
*/
export default class TransactionSubmitController extends AbstractController<
TransactionSubmitService
> {
constructor(api: ApiPromise) {
super(api, '/transaction', new TransactionSubmitService(api));
this.initRoutes();
}

protected initRoutes(): void {
this.router.post(
this.path,
TransactionSubmitController.catchWrap(this.txSubmit)
);
}

/**
* Submit a serialized transaction to the transaction queue.
*
* @param req Sidecar TxRequest
* @param res Express Response
*/
private txSubmit: IPostRequestHandler<ITx> = async (
{ body: { tx } },
res
): Promise<void> => {
if (!tx) {
throw {
error: 'Missing field `tx` on request body.',
};
}

const hash = await this.api.rpc.chain.getFinalizedHead();

res.send(await this.service.submitTransaction(hash, tx));
};
}
3 changes: 3 additions & 0 deletions src/controllers/transaction/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,4 @@
export { default as TransactionDryRun } from './TransactionDryRunController';
export { default as TransactionMaterial } from './TransactionMaterialController';
export { default as TransactionFeeEstimate } from './TransactionFeeEstimateController';
export { default as TransactionSubmit } from './TransactionSubmitController';
Loading