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

feat(api) add support for gearEthBridge #1658

Open
wants to merge 8 commits into
base: main
Choose a base branch
from
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
92 changes: 92 additions & 0 deletions api/src/EthBridge.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import { SubmittableExtrinsic } from '@polkadot/api/types';
import { GearApi } from './GearApi';
import { ISubmittableResult } from '@polkadot/types/types';
import { HexString, Proof } from './types';
import { AuthoritySetHashError, ClearTimerError, GetQueueMerkleRootError } from './errors';

export class GearEthBridge {
constructor(private api: GearApi) {}

async authoritySetHash(): Promise<HexString> {
const result = await this.api.query.gearEthBridge.authoritySetHash();

if (result.isNone) {
throw new AuthoritySetHashError();
}

return result.unwrap().toHex();
}

async clearTimer(): Promise<number> {
const result = await this.api.query.gearEthBridge.clearTimer();

if (result.isNone) {
throw new ClearTimerError();
}

return result.unwrap().toNumber();
}

async isInitialized(): Promise<boolean> {
const result = await this.api.query.gearEthBridge.initialized();
return result.toHuman();
}

async getMessageNonce(): Promise<bigint> {
const result = await this.api.query.gearEthBridge.messageNonce();
return result.toBigInt();
}

async isPaused(): Promise<boolean> {
const result = await this.api.query.gearEthBridge.paused();
return result.toHuman();
}

async getQueue(): Promise<Array<HexString>> {
const result = await this.api.query.gearEthBridge.queue();
return result.toArray().map((hash) => hash.toHex());
}

async isQueueChanged(): Promise<boolean> {
const result = await this.api.query.gearEthBridge.queueChanged();
return result.toHuman();
}

async getQueueMerkleRoot(): Promise<HexString> {
const result = await this.api.query.gearEthBridge.queueMerkleRoot();

if (result.isNone) {
throw new GetQueueMerkleRootError();
}

return result.unwrap().toHex();
}

async getSessionsTimer(): Promise<number> {
const result = await this.api.query.gearEthBridge.sessionsTimer();
return result.toNumber();
}

sendEthMessage(
destination: HexString | Uint8Array,
payload: HexString | Uint8Array,
): SubmittableExtrinsic<'promise', ISubmittableResult> {
return this.api.tx.gearEthBridge.sendEthMessage(destination, payload);
}

async merkleProof(hash: HexString | Uint8Array, at?: HexString | Uint8Array): Promise<Proof> {
return this.api.rpc.gearEthBridge.merkleProof(hash, at);
}

get maxPayloadSize(): number {
return this.api.consts.gearEthBridge.maxPayloadSize.toNumber();
}

get queueCapacity(): number {
return this.api.consts.gearEthBridge.queueCapacity.toNumber();
}

get sessionsPerEra(): number {
return this.api.consts.gearEthBridge.sessionsPerEra.toNumber();
}
}
3 changes: 3 additions & 0 deletions api/src/GearApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { GearProgramState } from './State';
import { GearProgramStorage } from './Storage';
import { GearVoucher } from './Voucher';
import { GearWaitlist } from './Waitlist';
import { GearEthBridge } from './EthBridge';
import { GearBuiltin } from './Builtin';

export class GearApi extends ApiPromise {
Expand All @@ -32,6 +33,7 @@ export class GearApi extends ApiPromise {
public code: GearCode;
public waitlist: GearWaitlist;
public voucher: GearVoucher;
public ethBridge: GearEthBridge;
public builtin: GearBuiltin;
public provider: WsProvider;

Expand Down Expand Up @@ -89,6 +91,7 @@ export class GearApi extends ApiPromise {
this.mailbox = new GearMailbox(this);
this.code = new GearCode(this);
this.waitlist = new GearWaitlist(this);
this.ethBridge = new GearEthBridge(this);
this.builtin = new GearBuiltin(this);
}

Expand Down
15 changes: 15 additions & 0 deletions api/src/default/rpc.json
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,21 @@
],
"type": "H256"
}
},
"gearEthBridge": {
"merkleProof": {
"params": [
{
"name": "hash",
"type": "H256"
},
{
"name": "at",
"type": "Option<BlockHash>"
}
],
"type": "Proof"
}
}
}
}
7 changes: 7 additions & 0 deletions api/src/default/types-common.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,13 @@
"InflationInfo": {
"inflation": "u64",
"roi": "u64"
},
"Proof": {
"root": "H256",
"proof": "Vec<H256>",
"number_of_leaves": "u64",
"leaf_index": "u64",
"leaf": "H256"
}
}
}
29 changes: 29 additions & 0 deletions api/src/errors/ethBridge.errors.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
export class AuthoritySetHashError extends Error {
name = 'AuthoritySetHashError';
message = 'Unable to get authority set hash';

constructor(message?: string) {
super();
this.message = `${this.message}. ${message}`;
}
}

export class ClearTimerError extends Error {
name = 'ClearTimerError';
message = "Can't clear timer";

constructor(message?: string) {
super();
this.message = `${this.message}. ${message}`;
}
}

export class GetQueueMerkleRootError extends Error {
name = 'GetQueueMerkleRootError';
message = 'Unable to get queue merkle root';

constructor(message?: string) {
super();
this.message = `${this.message}. ${message}`;
}
}
1 change: 1 addition & 0 deletions api/src/errors/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@ export * from './state.errors';
export * from './claim.errors';
export * from './blocks.errors';
export * from './validation.errors';
export * from './ethBridge.errors';
export * from './builtin.errors';
20 changes: 20 additions & 0 deletions api/src/types/augment/augment-api-consts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,26 @@ declare module '@polkadot/api-base/types/consts' {
**/
[key: string]: Codec;
};
gearEthBridge: {
/**
* Constant defining maximal payload size in bytes of message for bridging.
**/
maxPayloadSize: u32 & AugmentedConst<ApiType>;
/**
* Constant defining maximal amount of messages that are able to be
* bridged within the single staking era.
**/
queueCapacity: u32 & AugmentedConst<ApiType>;
/**
* Constant defining amount of sessions in manager for keys rotation.
* Similar to `pallet_staking::SessionsPerEra`.
**/
sessionsPerEra: u32 & AugmentedConst<ApiType>;
/**
* Generic const
**/
[key: string]: Codec;
};
gearGas: {
/**
* The maximum amount of gas that can be used within a single block.
Expand Down
29 changes: 29 additions & 0 deletions api/src/types/augment/augment-api-errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,35 @@ declare module '@polkadot/api-base/types/errors' {
**/
[key: string]: AugmentedError<ApiType>;
};
gearEthBridge: {
/**
* The error happens when bridge got called before
* proper initialization after deployment.
**/
BridgeIsNotYetInitialized: AugmentedError<ApiType>;
/**
* The error happens when bridge got called when paused.
**/
BridgeIsPaused: AugmentedError<ApiType>;
/**
* The error happens when bridging thorough builtin and message value
* is inapplicable to operation or insufficient.
**/
IncorrectValueApplied: AugmentedError<ApiType>;
/**
* The error happens when bridging message sent with too big payload.
**/
MaxPayloadSizeExceeded: AugmentedError<ApiType>;
/**
* The error happens when bridging queue capacity exceeded,
* so message couldn't be sent.
**/
QueueCapacityExceeded: AugmentedError<ApiType>;
/**
* Generic error
**/
[key: string]: AugmentedError<ApiType>;
};
gearGas: {
/**
* `GasTree::consume` called on node, which has some balance locked.
Expand Down
44 changes: 43 additions & 1 deletion api/src/types/augment/augment-api-events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,10 @@ import {
GprimitivesCodeId,
GprimitivesMessageId,
PalletGearDebugDebugData,
PalletGearEthBridgeInternalEthMessage,
PalletGearVoucherInternalVoucherId,
} from '../lookup';
import type { AccountId32 } from '@polkadot/types/interfaces/runtime';
import type { AccountId32, H256 } from '@polkadot/types/interfaces/runtime';
import type { ApiTypes } from '@polkadot/api-base/types';

declare module '@polkadot/api-base/types/events' {
Expand Down Expand Up @@ -140,6 +141,47 @@ declare module '@polkadot/api-base/types/events' {
**/
[key: string]: AugmentedEvent<ApiType>;
};
gearEthBridge: {
/**
* Grandpa validator's keys set was hashed and set in storage at
* first block of the last session in the era.
**/
AuthoritySetHashChanged: AugmentedEvent<ApiType, [H256]>;
/**
* Bridge got cleared on initialization of the second block in a new era.
**/
BridgeCleared: AugmentedEvent<ApiType, []>;
/**
* Optimistically, single-time called event defining that pallet
* got initialized and started processing session changes,
* as well as putting initial zeroed queue merkle root.
**/
BridgeInitialized: AugmentedEvent<ApiType, []>;
/**
* Bridge was paused and temporary doesn't process any incoming requests.
**/
BridgePaused: AugmentedEvent<ApiType, []>;
/**
* Bridge was unpaused and from now on processes any incoming requests.
**/
BridgeUnpaused: AugmentedEvent<ApiType, []>;
/**
* A new message was queued for bridging.
**/
MessageQueued: AugmentedEvent<
ApiType,
[message: PalletGearEthBridgeInternalEthMessage, hash_: H256],
{ message: PalletGearEthBridgeInternalEthMessage; hash_: H256 }
>;
/**
* Merkle root of the queue changed: new messages queued within the block.
**/
QueueMerkleRootChanged: AugmentedEvent<ApiType, [H256]>;
/**
* Generic event
**/
[key: string]: AugmentedEvent<ApiType>;
};
gearVoucher: {
/**
* Voucher has been declined (set to expired state).
Expand Down
Loading
Loading