diff --git a/android/app/build.gradle b/android/app/build.gradle
index 55679eb9bead8a9808f3b2109ad4144b2a484a26..9278f8b078a89eab8598205d43c4ba801f358d9f 100644
--- a/android/app/build.gradle
+++ b/android/app/build.gradle
@@ -13,8 +13,8 @@ android {
         minSdkVersion rootProject.ext.minSdkVersion
         compileSdkVersion rootProject.ext.compileSdkVersion
         targetSdkVersion rootProject.ext.targetSdkVersion
-        versionCode 2000041
-        versionName "2.0.0-alpha41"
+        versionCode 2000042
+        versionName "2.0.0-alpha42"
         testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
         aaptOptions {
              // Files and dirs to omit from the packaged assets dir, modified to accommodate modern web apps.
diff --git a/electron/package.json b/electron/package.json
index 0c00bc51b4842aa869bc215e80645799c7c1237d..e4adb40323dd1e8ad2ecc4de308a08c708fb4040 100644
--- a/electron/package.json
+++ b/electron/package.json
@@ -1,6 +1,6 @@
 {
   "name": "cesium2s",
-  "version": "2.0.0-alpha41",
+  "version": "2.0.0-alpha42",
   "description": "Cesium², running on Duniter v2s (Substrate).",
   "author": {
     "name": "Benoit Lavenier",
diff --git a/graphql.config.yml b/graphql.config.yml
index 5d96ef556aabd8e78d69fb49fda33cf6e7d74799..68a6ad952c55eb6779092514ca7dd90f2bc607db 100644
--- a/graphql.config.yml
+++ b/graphql.config.yml
@@ -1,7 +1,7 @@
 projects:
   indexer:
     schema: src/app/network/indexer/indexer-schema.graphql
-    documents: "src/app/network/indexer/indexer-*!(.generated).{ts,gql}"
+    documents: "src/app/network/indexer/*!(.generated).{ts,gql}"
     extensions:
       endpoints:
         Gdev Indexer GraphQL Endpoint:
@@ -26,14 +26,13 @@ projects:
               namedClient: 'indexer'
           src/app/network/indexer/indexer-helpers.generated.ts:
             plugins:
-              - "add"
               - "typescript-apollo-client-helpers"
             config:
               content: "// Auto-generated via `npx graphql-codegen`, do not edit\n/* eslint-disable */"
 
   pod:
     schema: src/app/network/pod/pod-schema.graphql
-    documents: "src/app/network/pod/pod-*!(.generated).{ts,gql}"
+    documents: "src/app/network/pod/*!(.generated).{ts,gql}"
     extensions:
       endpoints:
         Gdev Pod GraphQL Endpoint:
diff --git a/install.sh b/install.sh
index 065a2833d6c3c1284de1674825275580a560e4ee..1abcb385d25f0581dff45ee11f4c2fb9be9593cf 100755
--- a/install.sh
+++ b/install.sh
@@ -14,7 +14,7 @@ INSTALL_DIR=${1:-$(pwd)/${PROJECT_NAME}}
 INSTALL_ENV=testing
 
 latest_version() {
-  echo "2.0.0-alpha41" #lastest
+  echo "2.0.0-alpha42" #lastest
 }
 
 api_release_url() {
diff --git a/package-lock.json b/package-lock.json
index 55b3a68194c4ec9f4c9c61c950aed63be814ac9a..40371375023a94f16b24b8f28821b182b5b4faf8 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -45,9 +45,9 @@
         "@polkadot/ui-settings": "^2.12.1",
         "@polkadot/util": "^10.4.2",
         "@polkadot/util-crypto": "^10.4.2",
-        "@rx-angular/cdk": "^17.0.1",
-        "@rx-angular/state": "^17.0.1",
-        "@rx-angular/template": "^17.1.0",
+        "@rx-angular/cdk": "^17.1.0",
+        "@rx-angular/state": "^17.2.0",
+        "@rx-angular/template": "^17.3.1",
         "apollo-angular": "~6.0.0",
         "apollo-link-logger": "~2.0.1",
         "apollo-link-queue": "~3.1.0",
@@ -125,7 +125,7 @@
         "shelljs": "~0.8.5",
         "stdio": "^2.1.3",
         "ts-node": "^8.10.2",
-        "typescript": "~5.2.2"
+        "typescript": "~5.4.5"
       },
       "engines": {
         "node": ">= 18.18.2",
@@ -9389,9 +9389,9 @@
       ]
     },
     "node_modules/@rx-angular/cdk": {
-      "version": "17.0.1",
-      "resolved": "https://registry.npmjs.org/@rx-angular/cdk/-/cdk-17.0.1.tgz",
-      "integrity": "sha512-l4iJA8hqlUWXsH+QFj6El66eIOmOH3zf6itnGMcxO3B44jjOlwyT/tj2jsL4uDJDUQyM22iY5kLSjinkW5OU+g==",
+      "version": "17.1.0",
+      "resolved": "https://registry.npmjs.org/@rx-angular/cdk/-/cdk-17.1.0.tgz",
+      "integrity": "sha512-N24LvggsDPjk7VJb5h9ICHxFW7EQbF2Qw6nnLCvfGR/yrP7VPGxbzl51pEOXZmN1lotBfzS28tLfCXqA3gMgyA==",
       "dependencies": {
         "ng-morph": "^4.0.3",
         "tslib": "^2.4.1"
@@ -9416,9 +9416,9 @@
       }
     },
     "node_modules/@rx-angular/state": {
-      "version": "17.0.1",
-      "resolved": "https://registry.npmjs.org/@rx-angular/state/-/state-17.0.1.tgz",
-      "integrity": "sha512-S8ASWMNFh7hIyDV/EwRHpK5PCiOx26Ey0hiaQvQNuiQlGcOLjHVe5jCuTftc5AdPLpM+gc8v4ZIz0yOCdu8Ebg==",
+      "version": "17.2.0",
+      "resolved": "https://registry.npmjs.org/@rx-angular/state/-/state-17.2.0.tgz",
+      "integrity": "sha512-1wN7TOO2W/R5i6I/mLjOPzO+Bizeu2mrfGPA/dcKxUHNnMTvqjPah/cfK0QtxFxOTGMf5TtmPhlKC1bsoJroIg==",
       "dependencies": {
         "ng-morph": "^4.0.3",
         "tslib": "^2.4.1"
@@ -9429,9 +9429,9 @@
       }
     },
     "node_modules/@rx-angular/template": {
-      "version": "17.1.0",
-      "resolved": "https://registry.npmjs.org/@rx-angular/template/-/template-17.1.0.tgz",
-      "integrity": "sha512-+dO4FJZk1GMJxKfIDMfngM0+XaEbIan2yAlngb46v2PXhFd3q21hihLhqL48hVjfu0UEApwKii5GyjlSjEs7nA==",
+      "version": "17.3.1",
+      "resolved": "https://registry.npmjs.org/@rx-angular/template/-/template-17.3.1.tgz",
+      "integrity": "sha512-C9xdKNQ9qqkuHXosmqCrLRNkpqhZhqLJyhI29HCsk09BfDyaNrLVahppP0bBivGPWPsDeQ6ZU98K/BpT0N7JlQ==",
       "dependencies": {
         "ng-morph": "^4.0.3",
         "tslib": "^2.4.1"
@@ -26944,9 +26944,9 @@
       }
     },
     "node_modules/typescript": {
-      "version": "5.2.2",
-      "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz",
-      "integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==",
+      "version": "5.4.5",
+      "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz",
+      "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==",
       "bin": {
         "tsc": "bin/tsc",
         "tsserver": "bin/tsserver"
diff --git a/package.json b/package.json
index c85c93a858ca74d72e5d875372c26a9666670979..1b96bec659174e8d7e343180b1d39af7e175958e 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "cesium",
-  "version": "2.0.0-alpha41",
+  "version": "2.0.0-alpha42",
   "description": "Manage G1 wallet",
   "author": "Benoit Lavenier <benoit.lavenier@e-is.pro>",
   "homepage": "https://cesium.app",
@@ -116,9 +116,9 @@
     "@polkadot/ui-settings": "^2.12.1",
     "@polkadot/util": "^10.4.2",
     "@polkadot/util-crypto": "^10.4.2",
-    "@rx-angular/cdk": "^17.0.1",
-    "@rx-angular/state": "^17.0.1",
-    "@rx-angular/template": "^17.1.0",
+    "@rx-angular/cdk": "^17.1.0",
+    "@rx-angular/state": "^17.2.0",
+    "@rx-angular/template": "^17.3.1",
     "apollo-angular": "~6.0.0",
     "apollo-link-logger": "~2.0.1",
     "apollo-link-queue": "~3.1.0",
diff --git a/resources/webext/manifest.json b/resources/webext/manifest.json
index ffa142a0474b58b73eb243c127f0f8541b4f59aa..b7711a488881ac19d7ea79db937cebea31dbeda7 100644
--- a/resources/webext/manifest.json
+++ b/resources/webext/manifest.json
@@ -1,8 +1,8 @@
 {
   "manifest_version": 2,
   "name": "cesium2s",
-  "version": "2.0.0.41",
-  "version_name": "2.0.0-alpha41",
+  "version": "2.0.0.42",
+  "version_name": "2.0.0-alpha42",
   "short_name": "Cesium²",
   "description": "Manage G1 wallet",
   "author": "Benoit Lavenier <benoit.lavenier@e-is.pro>",
diff --git a/src/app/account/accounts.service.ts b/src/app/account/accounts.service.ts
index 441412fee193bf43b9ad8e68750c0996e10e55a2..d7b740368629a0cf33dcf673aa586e668598cd06 100644
--- a/src/app/account/accounts.service.ts
+++ b/src/app/account/accounts.service.ts
@@ -580,7 +580,6 @@ export class AccountsService extends RxStartableService<AccountsState> {
    */
   async cert(from: Partial<Account>, to: Partial<Account>, opts = { allowCreation: true, confirmBeforeCreation: true }): Promise<string> {
     if (!from || !to) throw new Error("Missing argument 'from' or 'to' !");
-    if (isNil(to.meta)) throw new Error("Missing 'to.meta' argument");
 
     // Check currency
     const currency = this.network.currency;
@@ -672,6 +671,37 @@ export class AccountsService extends RxStartableService<AccountsState> {
     }
   }
 
+  /// WIP should wot action be part of account.service or wot.service?
+  async confirm(account: Partial<Account>, uid: string): Promise<void> {
+    // TODO some checks:
+    // - status Unconfirmed
+    // - uid availability
+
+    // THIS IS DUPLICATED CODE
+    const issuerPair = keyring.getPair(account.address);
+    if (issuerPair.isLocked) {
+      console.debug(`[account-service] Unlocking address ${account.address} ...`);
+      const isAuth = await this.auth();
+      if (!isAuth) throw new Error('ERROR.AUTH_REQUIRED');
+      issuerPair.unlock(this._password);
+    }
+
+    // build tx
+    const tx = this.api.tx.identity.confirmIdentity(uid);
+
+    // try run tx (also code duplication)
+    try {
+      const { status } = await ExtrinsicUtils.submit(tx, issuerPair);
+      console.info(`${this._logPrefix}Extrinsic status`, status.toHuman());
+    } catch (err) {
+      const error = new ExtrinsicError(this.api, err, 'ERROR.SEND_CERT_FAILED');
+      console.error(`${this._logPrefix}Cannot confirm: ${error?.message || error}`);
+      throw error;
+    }
+
+    // TODO process status
+  }
+
   /**
    * Load account data (balance, tx history, etc.).
    * This load can be skipped, when data already loaded (See options)
diff --git a/src/app/account/auth/auth.form.ts b/src/app/account/auth/auth.form.ts
index 57b408f7acf53560f4ce5678e327a347d6e861ce..e7b2a14f0c30afddc1e373a4a123dcb83d4c5661 100644
--- a/src/app/account/auth/auth.form.ts
+++ b/src/app/account/auth/auth.form.ts
@@ -1,4 +1,4 @@
-import { ChangeDetectionStrategy, Component, EventEmitter, inject, Injector, Input, OnInit, Output } from '@angular/core';
+import { ChangeDetectionStrategy, Component, EventEmitter, inject, Input, OnInit, Output } from '@angular/core';
 import { FormBuilder, Validators } from '@angular/forms';
 import { ModalController } from '@ionic/angular';
 import { RegisterModal } from '../register/register.modal';
@@ -49,7 +49,6 @@ export class AuthForm extends AppForm<AuthData> implements OnInit {
   }
 
   constructor(
-    injector: Injector,
     settings: SettingsService,
     formBuilder: FormBuilder,
     private modalCtrl: ModalController,
@@ -57,7 +56,6 @@ export class AuthForm extends AppForm<AuthData> implements OnInit {
     public network: NetworkService
   ) {
     super(
-      injector,
       formBuilder.group({
         salt: [null, Validators.required],
         password: [null, Validators.required],
diff --git a/src/app/account/auth/authv2.form.ts b/src/app/account/auth/authv2.form.ts
index 9b28cbdb381ecfd8d7875c8a76ed1d6927f79579..e326a1cf1c138829ece6e73bec9ca5601620ef62 100644
--- a/src/app/account/auth/authv2.form.ts
+++ b/src/app/account/auth/authv2.form.ts
@@ -1,4 +1,4 @@
-import { ChangeDetectionStrategy, Component, Injector, Input, OnInit } from '@angular/core';
+import { ChangeDetectionStrategy, Component, Input, OnInit } from '@angular/core';
 import { FormBuilder, Validators } from '@angular/forms';
 import { ModalController } from '@ionic/angular';
 import { RegisterModal } from '../register/register.modal';
@@ -25,14 +25,12 @@ export class AuthV2Form extends AppForm<AuthData> implements OnInit {
   @Input() canRegister: boolean;
 
   constructor(
-    injector: Injector,
     settings: SettingsService,
     formBuilder: FormBuilder,
     private modalCtrl: ModalController,
     public network: NetworkService
   ) {
     super(
-      injector,
       formBuilder.group({
         mnemonic: [null, Validators.required],
       })
diff --git a/src/app/account/confirm/identity-confirm.form.html b/src/app/account/confirm/identity-confirm.form.html
new file mode 100644
index 0000000000000000000000000000000000000000..a67f14d0e95eb9f5db78a13b21cb5a654ebcebb5
--- /dev/null
+++ b/src/app/account/confirm/identity-confirm.form.html
@@ -0,0 +1,35 @@
+<form [formGroup]="form" novalidate (ngSubmit)="doSubmit($event)" (keyup.enter)="doSubmit($event)">
+  <ion-text color="dark" class="ion-text-wrap ion-text-center">
+    <p [innerHTML]="'ACCOUNT.CONFIRM_IDENTITY.PSEUDO_HELP' | translate"></p>
+  </ion-text>
+
+  <ion-list>
+    <!-- error -->
+    <ion-item lines="none" *ngIf="error && !loading" @slideUpDownAnimation>
+      <ion-icon color="danger" slot="start" name="alert-circle"></ion-icon>
+      <ion-label color="danger" class="error" [innerHTML]="error | translate"></ion-label>
+    </ion-item>
+
+    <!-- Pseudo -->
+    @if (_form | formGetControl: 'pseudo'; as control) {
+      <ion-item lines="none">
+        <ion-input
+          [formControl]="control"
+          [label]="'ACCOUNT.NEW.PSEUDO' | translate"
+          labelPlacement="floating"
+          autocomplete="off"
+          [counter]="true"
+          [helperText]="control.valid ? ('ACCOUNT.NEW.PSEUDO_AVAILABLE' | translate) : ''"
+          [errorText]="control | formError: errorTranslatorOptions"
+          maxlength="42"
+          required="true"
+          inputmode="text"
+          type="text"
+          enterkeyhint="send"
+          [debounce]="450"
+          (ionInput)="markForCheck()"
+        ></ion-input>
+      </ion-item>
+    }
+  </ion-list>
+</form>
diff --git a/src/app/account/confirm/identity-confirm.form.ts b/src/app/account/confirm/identity-confirm.form.ts
new file mode 100644
index 0000000000000000000000000000000000000000..3aae8f5b74ea7dbc45266ed7302a704784c91707
--- /dev/null
+++ b/src/app/account/confirm/identity-confirm.form.ts
@@ -0,0 +1,56 @@
+import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core';
+import { AppForm } from '@app/shared/form.class';
+import { FormBuilder, FormControl, Validators } from '@angular/forms';
+import { IdentityConfirmValidators } from '@app/account/confirm/identity-confirm.validator';
+import { IndexerService } from '@app/network/indexer/indexer.service';
+import { SharedValidators } from '@app/shared/form/form-validators';
+import { filter, first } from 'rxjs/operators';
+import { debounceTime } from 'rxjs';
+
+export interface IdentityConfirmData {
+  pseudo: string;
+}
+@Component({
+  selector: 'app-identity-confirm-form',
+  templateUrl: 'identity-confirm.form.html',
+  changeDetection: ChangeDetectionStrategy.OnPush,
+})
+export class IdentityConfirmForm extends AppForm<IdentityConfirmData> implements OnInit {
+  constructor(formBuilder: FormBuilder, indexerService: IndexerService) {
+    super();
+
+    this.setForm(
+      formBuilder.group({
+        pseudo: new FormControl<string>(
+          null,
+          // Validators
+          [Validators.required, Validators.minLength(3), SharedValidators.uid],
+          // Async validators
+          IdentityConfirmValidators.availableUid(indexerService)
+        ),
+      })
+    );
+
+    this._i18nPrefix = 'ACCOUNT.NEW.';
+  }
+
+  ngOnInit() {
+    console.debug(`${this._logPrefix} Init`);
+    super.ngOnInit();
+
+    // Force control to be touched, if invalid and more than 3 characters
+    const pseudoControl = this.form.get('pseudo');
+    this.registerSubscription(
+      pseudoControl.statusChanges
+        .pipe(
+          debounceTime(450),
+          filter(() => !pseudoControl.touched && pseudoControl.invalid),
+          first()
+        )
+        .subscribe(() => {
+          pseudoControl.markAsTouched({ onlySelf: true });
+          this.markForCheck();
+        })
+    );
+  }
+}
diff --git a/src/app/account/confirm/identity-confirm.modal.html b/src/app/account/confirm/identity-confirm.modal.html
new file mode 100644
index 0000000000000000000000000000000000000000..c720f078fc7733dc426061a70bc072e9581a5b66
--- /dev/null
+++ b/src/app/account/confirm/identity-confirm.modal.html
@@ -0,0 +1,48 @@
+<ion-header>
+  <ion-toolbar color="secondary">
+    <ion-buttons slot="start">
+      @if (mobile) {
+        <ion-button (click)="cancel()">
+          <ion-icon slot="icon-only" name="arrow-back"></ion-icon>
+        </ion-button>
+      }
+    </ion-buttons>
+
+    <ion-title translate>ACCOUNT.CONFIRM_IDENTITY.TITLE</ion-title>
+
+    <ion-buttons slot="end">
+      <ion-spinner *ngIf="pending"></ion-spinner>
+
+      @if (mobile) {
+        <ion-button [disabled]="!valid" (click)="doSubmit()">
+          <ion-icon slot="icon-only" name="send"></ion-icon>
+        </ion-button>
+      }
+    </ion-buttons>
+  </ion-toolbar>
+</ion-header>
+
+<ion-content class="ion-padding-top">
+  <app-identity-confirm-form #form (validate)="doSubmit()" (cancel)="cancel()"></app-identity-confirm-form>
+</ion-content>
+
+@if (!mobile) {
+  <ion-footer>
+    <ion-toolbar>
+      <ion-row class="ion-no-padding" nowrap>
+        <ion-col></ion-col>
+
+        <!-- buttons -->
+        <ion-col size="auto">
+          <ion-button fill="clear" color="dark" (click)="cancel()">
+            <ion-label translate>COMMON.BTN_CANCEL</ion-label>
+          </ion-button>
+
+          <ion-button [fill]="invalid ? 'clear' : 'solid'" [disabled]="invalid" (click)="doSubmit()" (keyup.enter)="doSubmit()">
+            <ion-label translate>ACCOUNT.BTN_CONFIRM_MEMBERSHIP</ion-label>
+          </ion-button>
+        </ion-col>
+      </ion-row>
+    </ion-toolbar>
+  </ion-footer>
+}
diff --git a/src/app/account/confirm/identity-confirm.modal.ts b/src/app/account/confirm/identity-confirm.modal.ts
new file mode 100644
index 0000000000000000000000000000000000000000..f02737b8ced318e9e3cf327f623bcf73df4f103a
--- /dev/null
+++ b/src/app/account/confirm/identity-confirm.modal.ts
@@ -0,0 +1,54 @@
+import { ChangeDetectionStrategy, ChangeDetectorRef, Component, inject, Input, OnInit, ViewChild } from '@angular/core';
+import { ModalController } from '@ionic/angular';
+import { Account } from '@app/account/account.model';
+import { IdentityConfirmForm } from '@app/account/confirm/identity-confirm.form';
+import { SettingsService } from '@app/settings/settings.service';
+
+export interface IdentityConfirmModalOptions {
+  account: Account;
+}
+
+export declare type IdentityConfirmModalRole = 'CANCEL' | 'VALIDATE';
+@Component({
+  selector: 'app-identity-confirm-modal',
+  templateUrl: 'identity-confirm.modal.html',
+  changeDetection: ChangeDetectionStrategy.OnPush,
+})
+export class IdentityConfirmModal implements IdentityConfirmModalOptions, OnInit {
+  protected readonly mobile = inject(SettingsService).mobile;
+
+  @Input() account: Account;
+
+  get pending() {
+    return this.form.pending;
+  }
+
+  get invalid() {
+    return this.form.invalid;
+  }
+
+  get valid() {
+    return this.form.valid;
+  }
+
+  @ViewChild('form', { static: true }) form: IdentityConfirmForm;
+
+  constructor(
+    private viewCtrl: ModalController,
+    private _cd: ChangeDetectorRef
+  ) {}
+
+  ngOnInit() {
+    this.form.markAsReady({ emitEvent: false });
+    this.form.markAsLoaded();
+    this.form.enable();
+  }
+
+  cancel() {
+    this.viewCtrl.dismiss(null, <IdentityConfirmModalRole>'CANCEL');
+  }
+
+  doSubmit() {
+    this.viewCtrl.dismiss(this.form.value, <IdentityConfirmModalRole>'VALIDATE');
+  }
+}
diff --git a/src/app/account/confirm/identity-confirm.module.ts b/src/app/account/confirm/identity-confirm.module.ts
new file mode 100644
index 0000000000000000000000000000000000000000..d7c69daf57a2ee993b17cdcdabdb4fe6b736c02a
--- /dev/null
+++ b/src/app/account/confirm/identity-confirm.module.ts
@@ -0,0 +1,13 @@
+import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
+import { TranslateModule } from '@ngx-translate/core';
+import { IdentityConfirmForm } from '@app/account/confirm/identity-confirm.form';
+import { IdentityConfirmModal } from '@app/account/confirm/identity-confirm.modal';
+import { AppSharedModule } from '@app/shared/shared.module';
+
+@NgModule({
+  imports: [AppSharedModule],
+  declarations: [IdentityConfirmForm, IdentityConfirmModal],
+  exports: [AppSharedModule, IdentityConfirmForm, IdentityConfirmModal, TranslateModule],
+  schemas: [CUSTOM_ELEMENTS_SCHEMA],
+})
+export class AppIdentityConfirmModule {}
diff --git a/src/app/account/confirm/identity-confirm.validator.ts b/src/app/account/confirm/identity-confirm.validator.ts
new file mode 100644
index 0000000000000000000000000000000000000000..7b3404a11e1329b1951fce63bc4f5b1081c25ab5
--- /dev/null
+++ b/src/app/account/confirm/identity-confirm.validator.ts
@@ -0,0 +1,23 @@
+import { AsyncValidatorFn } from '@angular/forms';
+import { isNotEmptyArray, isNotNilOrBlank } from '@app/shared/functions';
+import { IndexerService } from '@app/network/indexer/indexer.service';
+import { firstValueFrom } from 'rxjs';
+
+export abstract class IdentityConfirmValidators {
+  static availableUid(indexer: IndexerService): AsyncValidatorFn {
+    return async (control) => {
+      const name = control.value;
+      if (isNotNilOrBlank(name) && indexer.started) {
+        const { data } = await firstValueFrom(indexer.wotSearch({ uid: name }, { first: 1, fetchPolicy: 'no-cache' }));
+        if (isNotEmptyArray(data)) {
+          return { availableUid: true };
+        }
+      }
+      return undefined; // No error
+    };
+  }
+
+  static readonly I18N_ERROR_KEYS = {
+    availableUid: 'ACCOUNT.NEW.PSEUDO_NOT_AVAILABLE',
+  };
+}
diff --git a/src/app/account/register/register.form.ts b/src/app/account/register/register.form.ts
index 2b3d511edc443449ec0894e153c2936c3ebacd16..9a974976b9b326f63471a279082b79e060729262 100644
--- a/src/app/account/register/register.form.ts
+++ b/src/app/account/register/register.form.ts
@@ -1,4 +1,4 @@
-import { Component, Injector, Input, OnInit, ViewChild } from '@angular/core';
+import { Component, Input, OnInit, ViewChild } from '@angular/core';
 import { AbstractControl, FormBuilder, FormControl, ValidationErrors, ValidatorFn, Validators } from '@angular/forms';
 import { AccountsService } from '@app/account/accounts.service';
 import { SettingsService } from '@app/settings/settings.service';
@@ -56,22 +56,21 @@ export class RegisterForm extends AppForm<AuthData> implements OnInit {
   @ViewChild(SwiperDirective) swiperDir: SwiperDirective;
 
   constructor(
-    injector: Injector,
     private accountService: AccountsService,
     private networkService: NetworkService,
     public formBuilder: FormBuilder,
     protected settings?: SettingsService
   ) {
-    super(injector);
+    super();
 
     this.setForm(
       formBuilder.group({
-        words: new FormControl(null, Validators.required),
-        wordNumber: new FormControl(null, Validators.required),
-        code: new FormControl(null, Validators.required),
-        codeConfirmation: new FormControl(null, Validators.compose([Validators.required, this.equalsValidator('code')])),
-        name: new FormControl(null),
-        address: new FormControl(null),
+        words: new FormControl<string>(null, Validators.required),
+        wordNumber: new FormControl<number>(null, Validators.required),
+        code: new FormControl<string>(null, Validators.required),
+        codeConfirmation: new FormControl<string>(null, Validators.compose([Validators.required, this.equalsValidator('code')])),
+        name: new FormControl<string>(null),
+        address: new FormControl<string>(null),
       })
     );
 
diff --git a/src/app/account/unlock/unlock.form.ts b/src/app/account/unlock/unlock.form.ts
index e251281b90706a3cd439139ccc9e56e5a6d19672..b9fa44717a9536c0607a919d57b0f3cb07d7ad69 100644
--- a/src/app/account/unlock/unlock.form.ts
+++ b/src/app/account/unlock/unlock.form.ts
@@ -1,4 +1,4 @@
-import { ChangeDetectionStrategy, Component, EventEmitter, Injector, Input, OnInit, Optional, Output } from '@angular/core';
+import { ChangeDetectionStrategy, Component, EventEmitter, Input, OnInit, Optional, Output } from '@angular/core';
 import { AbstractControl, FormBuilder, FormControl, FormGroup, FormGroupDirective, ValidationErrors, ValidatorFn, Validators } from '@angular/forms';
 import { SettingsService } from '@app/settings/settings.service';
 import { environment } from '@environments/environment';
@@ -35,12 +35,11 @@ export class UnlockForm extends AppForm<string> implements OnInit {
   readonly maskPredicate: MaskitoElementPredicateAsync = async (el) => (el as HTMLIonInputElement).getInputElement();
 
   constructor(
-    injector: Injector,
     public formBuilder: FormBuilder,
     protected settings?: SettingsService,
     @Optional() protected formGroupDir?: FormGroupDirective
   ) {
-    super(injector);
+    super();
 
     this.debug = !environment.production;
   }
diff --git a/src/app/account/wallet/wallet.page.html b/src/app/account/wallet/wallet.page.html
index 53128d3b1eaf536ff365a1a32e7eee15fe9114fa..0238549e084dc6564913930c3994e55ae45305d5 100644
--- a/src/app/account/wallet/wallet.page.html
+++ b/src/app/account/wallet/wallet.page.html
@@ -67,14 +67,25 @@
 
   <div id="container">
     <div class="ion-text-center ion-padding-top" *ngIf="!mobile">
-      <ion-button *rxIf="account$; let account" (click)="transfer()" [disabled]="loading">
-        <ion-icon slot="start" name="paper-plane"></ion-icon>
-        <ion-label translate>COMMON.BTN_SEND_MONEY</ion-label>
-      </ion-button>
+      @if (account$ | push; as account) {
+        <!-- Send TX -->
+        <ion-button (click)="transfer()" [disabled]="loading">
+          <ion-icon slot="start" name="paper-plane"></ion-icon>
+          <ion-label translate>COMMON.BTN_SEND_MONEY</ion-label>
+        </ion-button>
+
+        <!-- Confirm identity -->
+        @if (account.meta?.status === IdentityStatusEnum.Unconfirmed) {
+          <ion-button (click)="confirmIdentity()" [disabled]="loading" color="tertiary">
+            <!--            <ion-icon slot="start" name="checkmark-circle-outline"></ion-icon>-->
+            <ion-label translate>ACCOUNT.BTN_CONFIRM_MEMBERSHIP</ion-label>
+          </ion-button>
+        }
+      }
     </div>
 
     <ion-list>
-      <ion-item *rxIf="error$; let error" lines="none" color="light">
+      <ion-item *rxIf="error$; let error" lines="none" color="light" @fadeInOutAnimation>
         <ion-icon slot="start" name="alert-circle" color="danger"></ion-icon>
         <ion-label color="danger">{{ error | translate }}</ion-label>
       </ion-item>
@@ -121,16 +132,37 @@
         @if (account.meta?.index) {
           <ion-item>
             <ion-icon aria-hidden="true" slot="start" name="calendar-clear-outline"></ion-icon>
-            <ion-label>
-              <h3 translate>COMMON.UID</h3>
-              <p>
-                {{ 'WOT.REGISTERED_SINCE' | translate }} {{ account.meta.createdOn | blockTime | dateFormat }} -
-                {{ 'WOT.REGISTERED_SINCE_BLOCK' | translate }} {{ account.meta.createdOn | blockNumber }}
-              </p>
-            </ion-label>
-            <ion-badge [color]="account.meta.isMember ? 'warning' : 'medium'" slot="end">
-              {{ account.meta.uid }} ({{ account.meta.status }})
-            </ion-badge>
+
+            <!-- special case for unconfirmed (UID is not known yet)-->
+            @if (account.meta.status === IdentityStatusEnum.Unconfirmed) {
+              <ion-label color="danger" [innerHTML]="'WOT.IDENTITY_UNCONFIRMED' | translate"></ion-label>
+
+              @if (mobile) {
+                <ion-button slot="end" (click)="confirmIdentity()" [disabled]="loading" color="tertiary">
+                  <ion-label translate>COMMON.BTN_CONFIRM</ion-label>
+                </ion-button>
+              } @else {
+                <ion-button slot="end" (click)="confirmIdentity()" [disabled]="loading" fill="clear" color="tertiary">
+                  <ion-label translate>COMMON.BTN_CONFIRM</ion-label>
+                </ion-button>
+              }
+            } @else {
+              <ion-label>
+                <h3 translate>COMMON.UID</h3>
+                <p>
+                  {{ 'WOT.REGISTERED_SINCE' | translate }} {{ account.meta.createdOn | blockTime | dateFormat }} -
+                  {{ 'WOT.REGISTERED_SINCE_BLOCK' | translate }}{{ account.meta.createdOn | blockNumber }}
+                </p>
+              </ion-label>
+              <ion-buttons slot="end" class="vertical-alignment">
+                <ion-badge [color]="account.meta.isMember ? 'warning' : 'medium'">
+                  {{ account.meta?.uid }}
+                </ion-badge>
+                @if (!account.meta.isMember) {
+                  <ion-note color="danger">({{ 'WOT.STATUS_ENUM.' + account.meta.status | translate }})</ion-note>
+                }
+              </ion-buttons>
+            }
           </ion-item>
 
           <!-- Received cert count -->
diff --git a/src/app/account/wallet/wallet.page.ts b/src/app/account/wallet/wallet.page.ts
index 2e0f39f9709a9bc7048a4025098605976fe49838..ca08ac231e1b41141827c8e43c0c41645087a54b 100644
--- a/src/app/account/wallet/wallet.page.ts
+++ b/src/app/account/wallet/wallet.page.ts
@@ -3,9 +3,9 @@ import { ChangeDetectionStrategy, Component, Inject, OnInit, ViewChild } from '@
 import { Clipboard } from '@capacitor/clipboard';
 import { AppPage, AppPageState } from '@app/shared/pages/base-page.class';
 import { Account } from '@app/account/account.model';
-import { isNil, isNotEmptyArray, isNotNilOrBlank } from '@app/shared/functions';
+import { isNil, isNotEmptyArray, isNotNil, isNotNilOrBlank } from '@app/shared/functions';
 import { NetworkService } from '@app/network/network.service';
-import { ActionSheetOptions, IonModal, IonPopover, PopoverOptions } from '@ionic/angular';
+import { ActionSheetOptions, IonModal, IonPopover, ModalController, PopoverOptions } from '@ionic/angular';
 import { ActivatedRoute, Router } from '@angular/router';
 import { RxStateProperty, RxStateSelect } from '@app/shared/decorator/state.decorator';
 import { distinctUntilChanged, filter, mergeMap, switchMap } from 'rxjs/operators';
@@ -17,6 +17,10 @@ import { TranslateModule } from '@ngx-translate/core';
 import { AppSharedModule } from '@app/shared/shared.module';
 import { AppAccountModule } from '@app/account/account.module';
 import { AppAuthModule } from '@app/account/auth/auth.module';
+import { IdentityStatusEnum } from '@app/network/indexer/indexer-types.generated';
+import { AppIdentityConfirmModule } from '@app/account/confirm/identity-confirm.module';
+import { IdentityConfirmModal } from '@app/account/confirm/identity-confirm.modal';
+import { fadeInOutAnimation, slideUpDownAnimation } from '@app/shared/animations';
 
 export interface WalletState extends AppPageState {
   accounts: Account[];
@@ -26,6 +30,7 @@ export interface WalletState extends AppPageState {
   balance: number;
   receivedCertCount: number;
   givenCertCount: number;
+  status: IdentityStatusEnum;
 }
 
 @Component({
@@ -35,13 +40,16 @@ export interface WalletState extends AppPageState {
   changeDetection: ChangeDetectionStrategy.OnPush,
   providers: [RxState],
   standalone: true,
-  imports: [TranslateModule, AppSharedModule, AppAccountModule, AppAuthModule],
+  animations: [fadeInOutAnimation, slideUpDownAnimation],
+  imports: [TranslateModule, AppSharedModule, AppAccountModule, AppAuthModule, AppIdentityConfirmModule],
 })
 export class WalletPage extends AppPage<WalletState> implements OnInit {
   static NEW = Object.freeze(<Account>{
     address: '',
   });
 
+  IdentityStatusEnum = IdentityStatusEnum;
+
   protected qrCodeValue: string;
   protected qrCodeTitle: string;
 
@@ -54,6 +62,7 @@ export class WalletPage extends AppPage<WalletState> implements OnInit {
   @RxStateSelect() accounts$: Observable<Account[]>;
   @RxStateSelect() receivedCertCount$: Observable<number>;
   @RxStateSelect() givenCertCount$: Observable<number>;
+  @RxStateSelect() status$: Observable<IdentityStatusEnum>;
 
   get balance(): number {
     if (!this.account?.data) return undefined;
@@ -80,6 +89,7 @@ export class WalletPage extends AppPage<WalletState> implements OnInit {
     protected route: ActivatedRoute,
     protected networkService: NetworkService,
     protected accountService: AccountsService,
+    protected modalCtrl: ModalController,
     @Inject(APP_TRANSFER_CONTROLLER) protected transferController: ITransferController
   ) {
     super({
@@ -153,6 +163,14 @@ export class WalletPage extends AppPage<WalletState> implements OnInit {
         map(({ total }) => total)
       )
     );
+
+    this._state.connect(
+      'status',
+      this.account$.pipe(
+        map((account) => account?.meta?.status),
+        filter(isNotNil)
+      )
+    );
   }
 
   async ngOnInit() {
@@ -205,4 +223,42 @@ export class WalletPage extends AppPage<WalletState> implements OnInit {
   transfer(opts?: TransferFormOptions) {
     return this.transferController.transfer({ account: this.account, ...opts });
   }
+
+  get isUnconfirmed() {
+    return this.account.meta?.status == IdentityStatusEnum.Unconfirmed;
+  }
+
+  async confirmIdentity(): Promise<void> {
+    console.info(`${this._logPrefix}Opening identity confirm modal...`);
+
+    const modal = await this.modalCtrl.create({
+      component: IdentityConfirmModal,
+      presentingElement: this._presentingElement,
+      canDismiss: true,
+    });
+    await modal.present();
+    const { data, role } = await modal.onWillDismiss();
+
+    if (!data || role === 'CANCEL') {
+      console.info(`${this._logPrefix}User cancelled identity confirmation`);
+      this.markAsLoaded();
+      return;
+    }
+
+    console.info(`${this._logPrefix}User confirmed. Pseudo: ${data.pseudo}`);
+    this.markAsLoading();
+
+    try {
+      await this.showToast({ id: 'confirm-identity', message: 'INFO.CONFIRM_IDENTITY_PENDING', duration: -1 });
+
+      // Send confirmation
+      await this.accountService.confirm(this.account, data.pseudo);
+
+      // Show toast
+      await this.showToast({ id: 'confirm-identity', message: 'INFO.CONFIRM_IDENTITY_DONE', swipeGesture: 'vertical', color: 'secondary' });
+    } catch (err) {
+      this.showErrorToast(err, { id: 'confirm-identity' });
+      this.markAsLoaded();
+    }
+  }
 }
diff --git a/src/app/app.component.ts b/src/app/app.component.ts
index 373ce9f1c33fce7e2679896c0bc15d1c71792d2b..6bcbbf20703610a86a177fb00d926c697cb182aa 100644
--- a/src/app/app.component.ts
+++ b/src/app/app.component.ts
@@ -10,6 +10,7 @@ import { fadeInAnimation } from '@app/shared/animations';
 import { SettingsService } from '@app/settings/settings.service';
 import { TranslateService } from '@ngx-translate/core';
 import { AlertController } from '@ionic/angular';
+import { WotController } from './wot/wot.controller';
 
 export interface IMenuItem {
   title: string;
@@ -70,6 +71,7 @@ export class AppComponent {
     protected settings: SettingsService,
     private accountService: AccountsService,
     private transferController: TransferController,
+    private wotController: WotController,
     private translate: TranslateService,
     private alertController: AlertController,
     private router: Router
diff --git a/src/app/app.module.ts b/src/app/app.module.ts
index 35c322af862815db97501561e7a99528b58f1a8b..b0229f05ac0d6834bea8fb066b685e81be7012dc 100644
--- a/src/app/app.module.ts
+++ b/src/app/app.module.ts
@@ -25,6 +25,9 @@ import { AppTransferModule } from '@app/transfer/send/transfer.module';
 import { APP_GRAPHQL_TYPE_POLICIES } from '@app/shared/services/network/graphql/graphql.service';
 import { INDEXER_GRAPHQL_TYPE_POLICIES } from '@app/network/indexer/indexer.config';
 import { POD_GRAPHQL_TYPE_POLICIES } from '@app/network/pod/pod.config';
+import { AppWotModule } from './wot/wot.module';
+import { APP_FORM_ERROR_I18N_KEYS } from '@app/shared/form/form-error-translator.service';
+import { IdentityConfirmValidators } from '@app/account/confirm/identity-confirm.validator';
 
 export function createTranslateLoader(http: HttpClient) {
   if (environment.production) {
@@ -59,6 +62,7 @@ export function createTranslateLoader(http: HttpClient) {
     AppSharedModule,
     AppAccountModule.forRoot(),
     AppTransferModule.forRoot(),
+    AppWotModule.forRoot(),
   ],
   providers: [
     PlatformService,
@@ -106,6 +110,14 @@ export function createTranslateLoader(http: HttpClient) {
         backColor: '#0000',
       },
     },
+
+    // Custom error i18nk keys
+    {
+      provide: APP_FORM_ERROR_I18N_KEYS,
+      useValue: {
+        ...IdentityConfirmValidators.I18N_ERROR_KEYS,
+      },
+    },
   ],
   bootstrap: [AppComponent],
 })
diff --git a/src/app/network/indexer/indexer-helpers.generated.ts b/src/app/network/indexer/indexer-helpers.generated.ts
index 39ddea059e5d3fabb074796af5e463f827395f0c..d32e89bbf0e70d8779ac6d4fb9c70cc84074e802 100644
--- a/src/app/network/indexer/indexer-helpers.generated.ts
+++ b/src/app/network/indexer/indexer-helpers.generated.ts
@@ -1,8 +1,6 @@
-// Auto-generated via `npx graphql-codegen`, do not edit
-/* eslint-disable */
 import { FieldPolicy, FieldReadFunction, TypePolicies, TypePolicy } from '@apollo/client/cache';
 export type AccountKeySpecifier = ('id' | 'identity' | 'linkedIdentity' | 'linkedIdentityId' | 'transfersIssued' | 'transfersIssuedAggregate' | 'transfersIssued_connection' | 'transfersReceived' | 'transfersReceivedAggregate' | 'transfersReceived_connection' | 'wasIdentity' | 'wasIdentityAggregate' | 'wasIdentity_connection' | AccountKeySpecifier)[];
-export type AccountFieldPolicy = {
+export interface AccountFieldPolicy {
 	id?: FieldPolicy<any> | FieldReadFunction<any>,
 	identity?: FieldPolicy<any> | FieldReadFunction<any>,
 	linkedIdentity?: FieldPolicy<any> | FieldReadFunction<any>,
@@ -16,40 +14,40 @@ export type AccountFieldPolicy = {
 	wasIdentity?: FieldPolicy<any> | FieldReadFunction<any>,
 	wasIdentityAggregate?: FieldPolicy<any> | FieldReadFunction<any>,
 	wasIdentity_connection?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type AccountAggregateKeySpecifier = ('aggregate' | 'nodes' | AccountAggregateKeySpecifier)[];
-export type AccountAggregateFieldPolicy = {
+export interface AccountAggregateFieldPolicy {
 	aggregate?: FieldPolicy<any> | FieldReadFunction<any>,
 	nodes?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type AccountAggregateFieldsKeySpecifier = ('count' | 'max' | 'min' | AccountAggregateFieldsKeySpecifier)[];
-export type AccountAggregateFieldsFieldPolicy = {
+export interface AccountAggregateFieldsFieldPolicy {
 	count?: FieldPolicy<any> | FieldReadFunction<any>,
 	max?: FieldPolicy<any> | FieldReadFunction<any>,
 	min?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type AccountConnectionKeySpecifier = ('edges' | 'pageInfo' | AccountConnectionKeySpecifier)[];
-export type AccountConnectionFieldPolicy = {
+export interface AccountConnectionFieldPolicy {
 	edges?: FieldPolicy<any> | FieldReadFunction<any>,
 	pageInfo?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type AccountEdgeKeySpecifier = ('cursor' | 'node' | AccountEdgeKeySpecifier)[];
-export type AccountEdgeFieldPolicy = {
+export interface AccountEdgeFieldPolicy {
 	cursor?: FieldPolicy<any> | FieldReadFunction<any>,
 	node?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type AccountMaxFieldsKeySpecifier = ('id' | 'linkedIdentityId' | AccountMaxFieldsKeySpecifier)[];
-export type AccountMaxFieldsFieldPolicy = {
+export interface AccountMaxFieldsFieldPolicy {
 	id?: FieldPolicy<any> | FieldReadFunction<any>,
 	linkedIdentityId?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type AccountMinFieldsKeySpecifier = ('id' | 'linkedIdentityId' | AccountMinFieldsKeySpecifier)[];
-export type AccountMinFieldsFieldPolicy = {
+export interface AccountMinFieldsFieldPolicy {
 	id?: FieldPolicy<any> | FieldReadFunction<any>,
 	linkedIdentityId?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type BlockKeySpecifier = ('calls' | 'callsAggregate' | 'callsCount' | 'calls_connection' | 'events' | 'eventsAggregate' | 'eventsCount' | 'events_connection' | 'extrinsics' | 'extrinsicsAggregate' | 'extrinsicsCount' | 'extrinsics_connection' | 'extrinsicsicRoot' | 'hash' | 'height' | 'id' | 'implName' | 'implVersion' | 'parentHash' | 'specName' | 'specVersion' | 'stateRoot' | 'timestamp' | 'validator' | BlockKeySpecifier)[];
-export type BlockFieldPolicy = {
+export interface BlockFieldPolicy {
 	calls?: FieldPolicy<any> | FieldReadFunction<any>,
 	callsAggregate?: FieldPolicy<any> | FieldReadFunction<any>,
 	callsCount?: FieldPolicy<any> | FieldReadFunction<any>,
@@ -74,19 +72,19 @@ export type BlockFieldPolicy = {
 	stateRoot?: FieldPolicy<any> | FieldReadFunction<any>,
 	timestamp?: FieldPolicy<any> | FieldReadFunction<any>,
 	validator?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type BlockConnectionKeySpecifier = ('edges' | 'pageInfo' | BlockConnectionKeySpecifier)[];
-export type BlockConnectionFieldPolicy = {
+export interface BlockConnectionFieldPolicy {
 	edges?: FieldPolicy<any> | FieldReadFunction<any>,
 	pageInfo?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type BlockEdgeKeySpecifier = ('cursor' | 'node' | BlockEdgeKeySpecifier)[];
-export type BlockEdgeFieldPolicy = {
+export interface BlockEdgeFieldPolicy {
 	cursor?: FieldPolicy<any> | FieldReadFunction<any>,
 	node?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type CallKeySpecifier = ('address' | 'args' | 'argsStr' | 'block' | 'blockId' | 'error' | 'events' | 'eventsAggregate' | 'events_connection' | 'extrinsic' | 'extrinsicId' | 'id' | 'name' | 'pallet' | 'parent' | 'parentId' | 'subcalls' | 'subcallsAggregate' | 'subcalls_connection' | 'success' | CallKeySpecifier)[];
-export type CallFieldPolicy = {
+export interface CallFieldPolicy {
 	address?: FieldPolicy<any> | FieldReadFunction<any>,
 	args?: FieldPolicy<any> | FieldReadFunction<any>,
 	argsStr?: FieldPolicy<any> | FieldReadFunction<any>,
@@ -107,30 +105,30 @@ export type CallFieldPolicy = {
 	subcallsAggregate?: FieldPolicy<any> | FieldReadFunction<any>,
 	subcalls_connection?: FieldPolicy<any> | FieldReadFunction<any>,
 	success?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type CallAggregateKeySpecifier = ('aggregate' | 'nodes' | CallAggregateKeySpecifier)[];
-export type CallAggregateFieldPolicy = {
+export interface CallAggregateFieldPolicy {
 	aggregate?: FieldPolicy<any> | FieldReadFunction<any>,
 	nodes?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type CallAggregateFieldsKeySpecifier = ('count' | 'max' | 'min' | CallAggregateFieldsKeySpecifier)[];
-export type CallAggregateFieldsFieldPolicy = {
+export interface CallAggregateFieldsFieldPolicy {
 	count?: FieldPolicy<any> | FieldReadFunction<any>,
 	max?: FieldPolicy<any> | FieldReadFunction<any>,
 	min?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type CallConnectionKeySpecifier = ('edges' | 'pageInfo' | CallConnectionKeySpecifier)[];
-export type CallConnectionFieldPolicy = {
+export interface CallConnectionFieldPolicy {
 	edges?: FieldPolicy<any> | FieldReadFunction<any>,
 	pageInfo?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type CallEdgeKeySpecifier = ('cursor' | 'node' | CallEdgeKeySpecifier)[];
-export type CallEdgeFieldPolicy = {
+export interface CallEdgeFieldPolicy {
 	cursor?: FieldPolicy<any> | FieldReadFunction<any>,
 	node?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type CallMaxFieldsKeySpecifier = ('address' | 'argsStr' | 'blockId' | 'extrinsicId' | 'id' | 'name' | 'pallet' | 'parentId' | CallMaxFieldsKeySpecifier)[];
-export type CallMaxFieldsFieldPolicy = {
+export interface CallMaxFieldsFieldPolicy {
 	address?: FieldPolicy<any> | FieldReadFunction<any>,
 	argsStr?: FieldPolicy<any> | FieldReadFunction<any>,
 	blockId?: FieldPolicy<any> | FieldReadFunction<any>,
@@ -139,9 +137,9 @@ export type CallMaxFieldsFieldPolicy = {
 	name?: FieldPolicy<any> | FieldReadFunction<any>,
 	pallet?: FieldPolicy<any> | FieldReadFunction<any>,
 	parentId?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type CallMinFieldsKeySpecifier = ('address' | 'argsStr' | 'blockId' | 'extrinsicId' | 'id' | 'name' | 'pallet' | 'parentId' | CallMinFieldsKeySpecifier)[];
-export type CallMinFieldsFieldPolicy = {
+export interface CallMinFieldsFieldPolicy {
 	address?: FieldPolicy<any> | FieldReadFunction<any>,
 	argsStr?: FieldPolicy<any> | FieldReadFunction<any>,
 	blockId?: FieldPolicy<any> | FieldReadFunction<any>,
@@ -150,9 +148,9 @@ export type CallMinFieldsFieldPolicy = {
 	name?: FieldPolicy<any> | FieldReadFunction<any>,
 	pallet?: FieldPolicy<any> | FieldReadFunction<any>,
 	parentId?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type CertKeySpecifier = ('certHistory' | 'certHistoryAggregate' | 'certHistory_connection' | 'createdIn' | 'createdInId' | 'createdOn' | 'expireOn' | 'id' | 'isActive' | 'issuer' | 'issuerId' | 'receiver' | 'receiverId' | 'updatedIn' | 'updatedInId' | 'updatedOn' | CertKeySpecifier)[];
-export type CertFieldPolicy = {
+export interface CertFieldPolicy {
 	certHistory?: FieldPolicy<any> | FieldReadFunction<any>,
 	certHistoryAggregate?: FieldPolicy<any> | FieldReadFunction<any>,
 	certHistory_connection?: FieldPolicy<any> | FieldReadFunction<any>,
@@ -169,14 +167,14 @@ export type CertFieldPolicy = {
 	updatedIn?: FieldPolicy<any> | FieldReadFunction<any>,
 	updatedInId?: FieldPolicy<any> | FieldReadFunction<any>,
 	updatedOn?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type CertAggregateKeySpecifier = ('aggregate' | 'nodes' | CertAggregateKeySpecifier)[];
-export type CertAggregateFieldPolicy = {
+export interface CertAggregateFieldPolicy {
 	aggregate?: FieldPolicy<any> | FieldReadFunction<any>,
 	nodes?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type CertAggregateFieldsKeySpecifier = ('avg' | 'count' | 'max' | 'min' | 'stddev' | 'stddevPop' | 'stddevSamp' | 'sum' | 'varPop' | 'varSamp' | 'variance' | CertAggregateFieldsKeySpecifier)[];
-export type CertAggregateFieldsFieldPolicy = {
+export interface CertAggregateFieldsFieldPolicy {
 	avg?: FieldPolicy<any> | FieldReadFunction<any>,
 	count?: FieldPolicy<any> | FieldReadFunction<any>,
 	max?: FieldPolicy<any> | FieldReadFunction<any>,
@@ -188,25 +186,25 @@ export type CertAggregateFieldsFieldPolicy = {
 	varPop?: FieldPolicy<any> | FieldReadFunction<any>,
 	varSamp?: FieldPolicy<any> | FieldReadFunction<any>,
 	variance?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type CertAvgFieldsKeySpecifier = ('createdOn' | 'expireOn' | 'updatedOn' | CertAvgFieldsKeySpecifier)[];
-export type CertAvgFieldsFieldPolicy = {
+export interface CertAvgFieldsFieldPolicy {
 	createdOn?: FieldPolicy<any> | FieldReadFunction<any>,
 	expireOn?: FieldPolicy<any> | FieldReadFunction<any>,
 	updatedOn?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type CertConnectionKeySpecifier = ('edges' | 'pageInfo' | CertConnectionKeySpecifier)[];
-export type CertConnectionFieldPolicy = {
+export interface CertConnectionFieldPolicy {
 	edges?: FieldPolicy<any> | FieldReadFunction<any>,
 	pageInfo?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type CertEdgeKeySpecifier = ('cursor' | 'node' | CertEdgeKeySpecifier)[];
-export type CertEdgeFieldPolicy = {
+export interface CertEdgeFieldPolicy {
 	cursor?: FieldPolicy<any> | FieldReadFunction<any>,
 	node?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type CertEventKeySpecifier = ('blockNumber' | 'cert' | 'certId' | 'event' | 'eventId' | 'eventType' | 'id' | CertEventKeySpecifier)[];
-export type CertEventFieldPolicy = {
+export interface CertEventFieldPolicy {
 	blockNumber?: FieldPolicy<any> | FieldReadFunction<any>,
 	cert?: FieldPolicy<any> | FieldReadFunction<any>,
 	certId?: FieldPolicy<any> | FieldReadFunction<any>,
@@ -214,14 +212,14 @@ export type CertEventFieldPolicy = {
 	eventId?: FieldPolicy<any> | FieldReadFunction<any>,
 	eventType?: FieldPolicy<any> | FieldReadFunction<any>,
 	id?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type CertEventAggregateKeySpecifier = ('aggregate' | 'nodes' | CertEventAggregateKeySpecifier)[];
-export type CertEventAggregateFieldPolicy = {
+export interface CertEventAggregateFieldPolicy {
 	aggregate?: FieldPolicy<any> | FieldReadFunction<any>,
 	nodes?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type CertEventAggregateFieldsKeySpecifier = ('avg' | 'count' | 'max' | 'min' | 'stddev' | 'stddevPop' | 'stddevSamp' | 'sum' | 'varPop' | 'varSamp' | 'variance' | CertEventAggregateFieldsKeySpecifier)[];
-export type CertEventAggregateFieldsFieldPolicy = {
+export interface CertEventAggregateFieldsFieldPolicy {
 	avg?: FieldPolicy<any> | FieldReadFunction<any>,
 	count?: FieldPolicy<any> | FieldReadFunction<any>,
 	max?: FieldPolicy<any> | FieldReadFunction<any>,
@@ -233,65 +231,65 @@ export type CertEventAggregateFieldsFieldPolicy = {
 	varPop?: FieldPolicy<any> | FieldReadFunction<any>,
 	varSamp?: FieldPolicy<any> | FieldReadFunction<any>,
 	variance?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type CertEventAvgFieldsKeySpecifier = ('blockNumber' | CertEventAvgFieldsKeySpecifier)[];
-export type CertEventAvgFieldsFieldPolicy = {
+export interface CertEventAvgFieldsFieldPolicy {
 	blockNumber?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type CertEventConnectionKeySpecifier = ('edges' | 'pageInfo' | CertEventConnectionKeySpecifier)[];
-export type CertEventConnectionFieldPolicy = {
+export interface CertEventConnectionFieldPolicy {
 	edges?: FieldPolicy<any> | FieldReadFunction<any>,
 	pageInfo?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type CertEventEdgeKeySpecifier = ('cursor' | 'node' | CertEventEdgeKeySpecifier)[];
-export type CertEventEdgeFieldPolicy = {
+export interface CertEventEdgeFieldPolicy {
 	cursor?: FieldPolicy<any> | FieldReadFunction<any>,
 	node?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type CertEventMaxFieldsKeySpecifier = ('blockNumber' | 'certId' | 'eventId' | 'id' | CertEventMaxFieldsKeySpecifier)[];
-export type CertEventMaxFieldsFieldPolicy = {
+export interface CertEventMaxFieldsFieldPolicy {
 	blockNumber?: FieldPolicy<any> | FieldReadFunction<any>,
 	certId?: FieldPolicy<any> | FieldReadFunction<any>,
 	eventId?: FieldPolicy<any> | FieldReadFunction<any>,
 	id?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type CertEventMinFieldsKeySpecifier = ('blockNumber' | 'certId' | 'eventId' | 'id' | CertEventMinFieldsKeySpecifier)[];
-export type CertEventMinFieldsFieldPolicy = {
+export interface CertEventMinFieldsFieldPolicy {
 	blockNumber?: FieldPolicy<any> | FieldReadFunction<any>,
 	certId?: FieldPolicy<any> | FieldReadFunction<any>,
 	eventId?: FieldPolicy<any> | FieldReadFunction<any>,
 	id?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type CertEventStddevFieldsKeySpecifier = ('blockNumber' | CertEventStddevFieldsKeySpecifier)[];
-export type CertEventStddevFieldsFieldPolicy = {
+export interface CertEventStddevFieldsFieldPolicy {
 	blockNumber?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type CertEventStddevPopFieldsKeySpecifier = ('blockNumber' | CertEventStddevPopFieldsKeySpecifier)[];
-export type CertEventStddevPopFieldsFieldPolicy = {
+export interface CertEventStddevPopFieldsFieldPolicy {
 	blockNumber?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type CertEventStddevSampFieldsKeySpecifier = ('blockNumber' | CertEventStddevSampFieldsKeySpecifier)[];
-export type CertEventStddevSampFieldsFieldPolicy = {
+export interface CertEventStddevSampFieldsFieldPolicy {
 	blockNumber?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type CertEventSumFieldsKeySpecifier = ('blockNumber' | CertEventSumFieldsKeySpecifier)[];
-export type CertEventSumFieldsFieldPolicy = {
+export interface CertEventSumFieldsFieldPolicy {
 	blockNumber?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type CertEventVarPopFieldsKeySpecifier = ('blockNumber' | CertEventVarPopFieldsKeySpecifier)[];
-export type CertEventVarPopFieldsFieldPolicy = {
+export interface CertEventVarPopFieldsFieldPolicy {
 	blockNumber?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type CertEventVarSampFieldsKeySpecifier = ('blockNumber' | CertEventVarSampFieldsKeySpecifier)[];
-export type CertEventVarSampFieldsFieldPolicy = {
+export interface CertEventVarSampFieldsFieldPolicy {
 	blockNumber?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type CertEventVarianceFieldsKeySpecifier = ('blockNumber' | CertEventVarianceFieldsKeySpecifier)[];
-export type CertEventVarianceFieldsFieldPolicy = {
+export interface CertEventVarianceFieldsFieldPolicy {
 	blockNumber?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type CertMaxFieldsKeySpecifier = ('createdInId' | 'createdOn' | 'expireOn' | 'id' | 'issuerId' | 'receiverId' | 'updatedInId' | 'updatedOn' | CertMaxFieldsKeySpecifier)[];
-export type CertMaxFieldsFieldPolicy = {
+export interface CertMaxFieldsFieldPolicy {
 	createdInId?: FieldPolicy<any> | FieldReadFunction<any>,
 	createdOn?: FieldPolicy<any> | FieldReadFunction<any>,
 	expireOn?: FieldPolicy<any> | FieldReadFunction<any>,
@@ -300,9 +298,9 @@ export type CertMaxFieldsFieldPolicy = {
 	receiverId?: FieldPolicy<any> | FieldReadFunction<any>,
 	updatedInId?: FieldPolicy<any> | FieldReadFunction<any>,
 	updatedOn?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type CertMinFieldsKeySpecifier = ('createdInId' | 'createdOn' | 'expireOn' | 'id' | 'issuerId' | 'receiverId' | 'updatedInId' | 'updatedOn' | CertMinFieldsKeySpecifier)[];
-export type CertMinFieldsFieldPolicy = {
+export interface CertMinFieldsFieldPolicy {
 	createdInId?: FieldPolicy<any> | FieldReadFunction<any>,
 	createdOn?: FieldPolicy<any> | FieldReadFunction<any>,
 	expireOn?: FieldPolicy<any> | FieldReadFunction<any>,
@@ -311,51 +309,51 @@ export type CertMinFieldsFieldPolicy = {
 	receiverId?: FieldPolicy<any> | FieldReadFunction<any>,
 	updatedInId?: FieldPolicy<any> | FieldReadFunction<any>,
 	updatedOn?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type CertStddevFieldsKeySpecifier = ('createdOn' | 'expireOn' | 'updatedOn' | CertStddevFieldsKeySpecifier)[];
-export type CertStddevFieldsFieldPolicy = {
+export interface CertStddevFieldsFieldPolicy {
 	createdOn?: FieldPolicy<any> | FieldReadFunction<any>,
 	expireOn?: FieldPolicy<any> | FieldReadFunction<any>,
 	updatedOn?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type CertStddevPopFieldsKeySpecifier = ('createdOn' | 'expireOn' | 'updatedOn' | CertStddevPopFieldsKeySpecifier)[];
-export type CertStddevPopFieldsFieldPolicy = {
+export interface CertStddevPopFieldsFieldPolicy {
 	createdOn?: FieldPolicy<any> | FieldReadFunction<any>,
 	expireOn?: FieldPolicy<any> | FieldReadFunction<any>,
 	updatedOn?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type CertStddevSampFieldsKeySpecifier = ('createdOn' | 'expireOn' | 'updatedOn' | CertStddevSampFieldsKeySpecifier)[];
-export type CertStddevSampFieldsFieldPolicy = {
+export interface CertStddevSampFieldsFieldPolicy {
 	createdOn?: FieldPolicy<any> | FieldReadFunction<any>,
 	expireOn?: FieldPolicy<any> | FieldReadFunction<any>,
 	updatedOn?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type CertSumFieldsKeySpecifier = ('createdOn' | 'expireOn' | 'updatedOn' | CertSumFieldsKeySpecifier)[];
-export type CertSumFieldsFieldPolicy = {
+export interface CertSumFieldsFieldPolicy {
 	createdOn?: FieldPolicy<any> | FieldReadFunction<any>,
 	expireOn?: FieldPolicy<any> | FieldReadFunction<any>,
 	updatedOn?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type CertVarPopFieldsKeySpecifier = ('createdOn' | 'expireOn' | 'updatedOn' | CertVarPopFieldsKeySpecifier)[];
-export type CertVarPopFieldsFieldPolicy = {
+export interface CertVarPopFieldsFieldPolicy {
 	createdOn?: FieldPolicy<any> | FieldReadFunction<any>,
 	expireOn?: FieldPolicy<any> | FieldReadFunction<any>,
 	updatedOn?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type CertVarSampFieldsKeySpecifier = ('createdOn' | 'expireOn' | 'updatedOn' | CertVarSampFieldsKeySpecifier)[];
-export type CertVarSampFieldsFieldPolicy = {
+export interface CertVarSampFieldsFieldPolicy {
 	createdOn?: FieldPolicy<any> | FieldReadFunction<any>,
 	expireOn?: FieldPolicy<any> | FieldReadFunction<any>,
 	updatedOn?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type CertVarianceFieldsKeySpecifier = ('createdOn' | 'expireOn' | 'updatedOn' | CertVarianceFieldsKeySpecifier)[];
-export type CertVarianceFieldsFieldPolicy = {
+export interface CertVarianceFieldsFieldPolicy {
 	createdOn?: FieldPolicy<any> | FieldReadFunction<any>,
 	expireOn?: FieldPolicy<any> | FieldReadFunction<any>,
 	updatedOn?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type ChangeOwnerKeyKeySpecifier = ('blockNumber' | 'id' | 'identity' | 'identityId' | 'next' | 'nextId' | 'previous' | 'previousId' | ChangeOwnerKeyKeySpecifier)[];
-export type ChangeOwnerKeyFieldPolicy = {
+export interface ChangeOwnerKeyFieldPolicy {
 	blockNumber?: FieldPolicy<any> | FieldReadFunction<any>,
 	id?: FieldPolicy<any> | FieldReadFunction<any>,
 	identity?: FieldPolicy<any> | FieldReadFunction<any>,
@@ -364,14 +362,14 @@ export type ChangeOwnerKeyFieldPolicy = {
 	nextId?: FieldPolicy<any> | FieldReadFunction<any>,
 	previous?: FieldPolicy<any> | FieldReadFunction<any>,
 	previousId?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type ChangeOwnerKeyAggregateKeySpecifier = ('aggregate' | 'nodes' | ChangeOwnerKeyAggregateKeySpecifier)[];
-export type ChangeOwnerKeyAggregateFieldPolicy = {
+export interface ChangeOwnerKeyAggregateFieldPolicy {
 	aggregate?: FieldPolicy<any> | FieldReadFunction<any>,
 	nodes?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type ChangeOwnerKeyAggregateFieldsKeySpecifier = ('avg' | 'count' | 'max' | 'min' | 'stddev' | 'stddevPop' | 'stddevSamp' | 'sum' | 'varPop' | 'varSamp' | 'variance' | ChangeOwnerKeyAggregateFieldsKeySpecifier)[];
-export type ChangeOwnerKeyAggregateFieldsFieldPolicy = {
+export interface ChangeOwnerKeyAggregateFieldsFieldPolicy {
 	avg?: FieldPolicy<any> | FieldReadFunction<any>,
 	count?: FieldPolicy<any> | FieldReadFunction<any>,
 	max?: FieldPolicy<any> | FieldReadFunction<any>,
@@ -383,67 +381,67 @@ export type ChangeOwnerKeyAggregateFieldsFieldPolicy = {
 	varPop?: FieldPolicy<any> | FieldReadFunction<any>,
 	varSamp?: FieldPolicy<any> | FieldReadFunction<any>,
 	variance?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type ChangeOwnerKeyAvgFieldsKeySpecifier = ('blockNumber' | ChangeOwnerKeyAvgFieldsKeySpecifier)[];
-export type ChangeOwnerKeyAvgFieldsFieldPolicy = {
+export interface ChangeOwnerKeyAvgFieldsFieldPolicy {
 	blockNumber?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type ChangeOwnerKeyConnectionKeySpecifier = ('edges' | 'pageInfo' | ChangeOwnerKeyConnectionKeySpecifier)[];
-export type ChangeOwnerKeyConnectionFieldPolicy = {
+export interface ChangeOwnerKeyConnectionFieldPolicy {
 	edges?: FieldPolicy<any> | FieldReadFunction<any>,
 	pageInfo?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type ChangeOwnerKeyEdgeKeySpecifier = ('cursor' | 'node' | ChangeOwnerKeyEdgeKeySpecifier)[];
-export type ChangeOwnerKeyEdgeFieldPolicy = {
+export interface ChangeOwnerKeyEdgeFieldPolicy {
 	cursor?: FieldPolicy<any> | FieldReadFunction<any>,
 	node?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type ChangeOwnerKeyMaxFieldsKeySpecifier = ('blockNumber' | 'id' | 'identityId' | 'nextId' | 'previousId' | ChangeOwnerKeyMaxFieldsKeySpecifier)[];
-export type ChangeOwnerKeyMaxFieldsFieldPolicy = {
+export interface ChangeOwnerKeyMaxFieldsFieldPolicy {
 	blockNumber?: FieldPolicy<any> | FieldReadFunction<any>,
 	id?: FieldPolicy<any> | FieldReadFunction<any>,
 	identityId?: FieldPolicy<any> | FieldReadFunction<any>,
 	nextId?: FieldPolicy<any> | FieldReadFunction<any>,
 	previousId?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type ChangeOwnerKeyMinFieldsKeySpecifier = ('blockNumber' | 'id' | 'identityId' | 'nextId' | 'previousId' | ChangeOwnerKeyMinFieldsKeySpecifier)[];
-export type ChangeOwnerKeyMinFieldsFieldPolicy = {
+export interface ChangeOwnerKeyMinFieldsFieldPolicy {
 	blockNumber?: FieldPolicy<any> | FieldReadFunction<any>,
 	id?: FieldPolicy<any> | FieldReadFunction<any>,
 	identityId?: FieldPolicy<any> | FieldReadFunction<any>,
 	nextId?: FieldPolicy<any> | FieldReadFunction<any>,
 	previousId?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type ChangeOwnerKeyStddevFieldsKeySpecifier = ('blockNumber' | ChangeOwnerKeyStddevFieldsKeySpecifier)[];
-export type ChangeOwnerKeyStddevFieldsFieldPolicy = {
+export interface ChangeOwnerKeyStddevFieldsFieldPolicy {
 	blockNumber?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type ChangeOwnerKeyStddevPopFieldsKeySpecifier = ('blockNumber' | ChangeOwnerKeyStddevPopFieldsKeySpecifier)[];
-export type ChangeOwnerKeyStddevPopFieldsFieldPolicy = {
+export interface ChangeOwnerKeyStddevPopFieldsFieldPolicy {
 	blockNumber?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type ChangeOwnerKeyStddevSampFieldsKeySpecifier = ('blockNumber' | ChangeOwnerKeyStddevSampFieldsKeySpecifier)[];
-export type ChangeOwnerKeyStddevSampFieldsFieldPolicy = {
+export interface ChangeOwnerKeyStddevSampFieldsFieldPolicy {
 	blockNumber?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type ChangeOwnerKeySumFieldsKeySpecifier = ('blockNumber' | ChangeOwnerKeySumFieldsKeySpecifier)[];
-export type ChangeOwnerKeySumFieldsFieldPolicy = {
+export interface ChangeOwnerKeySumFieldsFieldPolicy {
 	blockNumber?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type ChangeOwnerKeyVarPopFieldsKeySpecifier = ('blockNumber' | ChangeOwnerKeyVarPopFieldsKeySpecifier)[];
-export type ChangeOwnerKeyVarPopFieldsFieldPolicy = {
+export interface ChangeOwnerKeyVarPopFieldsFieldPolicy {
 	blockNumber?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type ChangeOwnerKeyVarSampFieldsKeySpecifier = ('blockNumber' | ChangeOwnerKeyVarSampFieldsKeySpecifier)[];
-export type ChangeOwnerKeyVarSampFieldsFieldPolicy = {
+export interface ChangeOwnerKeyVarSampFieldsFieldPolicy {
 	blockNumber?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type ChangeOwnerKeyVarianceFieldsKeySpecifier = ('blockNumber' | ChangeOwnerKeyVarianceFieldsKeySpecifier)[];
-export type ChangeOwnerKeyVarianceFieldsFieldPolicy = {
+export interface ChangeOwnerKeyVarianceFieldsFieldPolicy {
 	blockNumber?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type EventKeySpecifier = ('args' | 'argsStr' | 'block' | 'blockId' | 'call' | 'callId' | 'extrinsic' | 'extrinsicId' | 'id' | 'index' | 'name' | 'pallet' | 'phase' | EventKeySpecifier)[];
-export type EventFieldPolicy = {
+export interface EventFieldPolicy {
 	args?: FieldPolicy<any> | FieldReadFunction<any>,
 	argsStr?: FieldPolicy<any> | FieldReadFunction<any>,
 	block?: FieldPolicy<any> | FieldReadFunction<any>,
@@ -457,14 +455,14 @@ export type EventFieldPolicy = {
 	name?: FieldPolicy<any> | FieldReadFunction<any>,
 	pallet?: FieldPolicy<any> | FieldReadFunction<any>,
 	phase?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type EventAggregateKeySpecifier = ('aggregate' | 'nodes' | EventAggregateKeySpecifier)[];
-export type EventAggregateFieldPolicy = {
+export interface EventAggregateFieldPolicy {
 	aggregate?: FieldPolicy<any> | FieldReadFunction<any>,
 	nodes?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type EventAggregateFieldsKeySpecifier = ('avg' | 'count' | 'max' | 'min' | 'stddev' | 'stddevPop' | 'stddevSamp' | 'sum' | 'varPop' | 'varSamp' | 'variance' | EventAggregateFieldsKeySpecifier)[];
-export type EventAggregateFieldsFieldPolicy = {
+export interface EventAggregateFieldsFieldPolicy {
 	avg?: FieldPolicy<any> | FieldReadFunction<any>,
 	count?: FieldPolicy<any> | FieldReadFunction<any>,
 	max?: FieldPolicy<any> | FieldReadFunction<any>,
@@ -476,23 +474,23 @@ export type EventAggregateFieldsFieldPolicy = {
 	varPop?: FieldPolicy<any> | FieldReadFunction<any>,
 	varSamp?: FieldPolicy<any> | FieldReadFunction<any>,
 	variance?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type EventAvgFieldsKeySpecifier = ('index' | EventAvgFieldsKeySpecifier)[];
-export type EventAvgFieldsFieldPolicy = {
+export interface EventAvgFieldsFieldPolicy {
 	index?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type EventConnectionKeySpecifier = ('edges' | 'pageInfo' | EventConnectionKeySpecifier)[];
-export type EventConnectionFieldPolicy = {
+export interface EventConnectionFieldPolicy {
 	edges?: FieldPolicy<any> | FieldReadFunction<any>,
 	pageInfo?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type EventEdgeKeySpecifier = ('cursor' | 'node' | EventEdgeKeySpecifier)[];
-export type EventEdgeFieldPolicy = {
+export interface EventEdgeFieldPolicy {
 	cursor?: FieldPolicy<any> | FieldReadFunction<any>,
 	node?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type EventMaxFieldsKeySpecifier = ('argsStr' | 'blockId' | 'callId' | 'extrinsicId' | 'id' | 'index' | 'name' | 'pallet' | 'phase' | EventMaxFieldsKeySpecifier)[];
-export type EventMaxFieldsFieldPolicy = {
+export interface EventMaxFieldsFieldPolicy {
 	argsStr?: FieldPolicy<any> | FieldReadFunction<any>,
 	blockId?: FieldPolicy<any> | FieldReadFunction<any>,
 	callId?: FieldPolicy<any> | FieldReadFunction<any>,
@@ -502,9 +500,9 @@ export type EventMaxFieldsFieldPolicy = {
 	name?: FieldPolicy<any> | FieldReadFunction<any>,
 	pallet?: FieldPolicy<any> | FieldReadFunction<any>,
 	phase?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type EventMinFieldsKeySpecifier = ('argsStr' | 'blockId' | 'callId' | 'extrinsicId' | 'id' | 'index' | 'name' | 'pallet' | 'phase' | EventMinFieldsKeySpecifier)[];
-export type EventMinFieldsFieldPolicy = {
+export interface EventMinFieldsFieldPolicy {
 	argsStr?: FieldPolicy<any> | FieldReadFunction<any>,
 	blockId?: FieldPolicy<any> | FieldReadFunction<any>,
 	callId?: FieldPolicy<any> | FieldReadFunction<any>,
@@ -514,37 +512,37 @@ export type EventMinFieldsFieldPolicy = {
 	name?: FieldPolicy<any> | FieldReadFunction<any>,
 	pallet?: FieldPolicy<any> | FieldReadFunction<any>,
 	phase?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type EventStddevFieldsKeySpecifier = ('index' | EventStddevFieldsKeySpecifier)[];
-export type EventStddevFieldsFieldPolicy = {
+export interface EventStddevFieldsFieldPolicy {
 	index?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type EventStddevPopFieldsKeySpecifier = ('index' | EventStddevPopFieldsKeySpecifier)[];
-export type EventStddevPopFieldsFieldPolicy = {
+export interface EventStddevPopFieldsFieldPolicy {
 	index?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type EventStddevSampFieldsKeySpecifier = ('index' | EventStddevSampFieldsKeySpecifier)[];
-export type EventStddevSampFieldsFieldPolicy = {
+export interface EventStddevSampFieldsFieldPolicy {
 	index?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type EventSumFieldsKeySpecifier = ('index' | EventSumFieldsKeySpecifier)[];
-export type EventSumFieldsFieldPolicy = {
+export interface EventSumFieldsFieldPolicy {
 	index?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type EventVarPopFieldsKeySpecifier = ('index' | EventVarPopFieldsKeySpecifier)[];
-export type EventVarPopFieldsFieldPolicy = {
+export interface EventVarPopFieldsFieldPolicy {
 	index?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type EventVarSampFieldsKeySpecifier = ('index' | EventVarSampFieldsKeySpecifier)[];
-export type EventVarSampFieldsFieldPolicy = {
+export interface EventVarSampFieldsFieldPolicy {
 	index?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type EventVarianceFieldsKeySpecifier = ('index' | EventVarianceFieldsKeySpecifier)[];
-export type EventVarianceFieldsFieldPolicy = {
+export interface EventVarianceFieldsFieldPolicy {
 	index?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type ExtrinsicKeySpecifier = ('block' | 'blockId' | 'call' | 'callId' | 'calls' | 'callsAggregate' | 'calls_connection' | 'error' | 'events' | 'eventsAggregate' | 'events_connection' | 'fee' | 'hash' | 'id' | 'index' | 'signature' | 'success' | 'tip' | 'version' | ExtrinsicKeySpecifier)[];
-export type ExtrinsicFieldPolicy = {
+export interface ExtrinsicFieldPolicy {
 	block?: FieldPolicy<any> | FieldReadFunction<any>,
 	blockId?: FieldPolicy<any> | FieldReadFunction<any>,
 	call?: FieldPolicy<any> | FieldReadFunction<any>,
@@ -564,14 +562,14 @@ export type ExtrinsicFieldPolicy = {
 	success?: FieldPolicy<any> | FieldReadFunction<any>,
 	tip?: FieldPolicy<any> | FieldReadFunction<any>,
 	version?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type ExtrinsicAggregateKeySpecifier = ('aggregate' | 'nodes' | ExtrinsicAggregateKeySpecifier)[];
-export type ExtrinsicAggregateFieldPolicy = {
+export interface ExtrinsicAggregateFieldPolicy {
 	aggregate?: FieldPolicy<any> | FieldReadFunction<any>,
 	nodes?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type ExtrinsicAggregateFieldsKeySpecifier = ('avg' | 'count' | 'max' | 'min' | 'stddev' | 'stddevPop' | 'stddevSamp' | 'sum' | 'varPop' | 'varSamp' | 'variance' | ExtrinsicAggregateFieldsKeySpecifier)[];
-export type ExtrinsicAggregateFieldsFieldPolicy = {
+export interface ExtrinsicAggregateFieldsFieldPolicy {
 	avg?: FieldPolicy<any> | FieldReadFunction<any>,
 	count?: FieldPolicy<any> | FieldReadFunction<any>,
 	max?: FieldPolicy<any> | FieldReadFunction<any>,
@@ -583,26 +581,26 @@ export type ExtrinsicAggregateFieldsFieldPolicy = {
 	varPop?: FieldPolicy<any> | FieldReadFunction<any>,
 	varSamp?: FieldPolicy<any> | FieldReadFunction<any>,
 	variance?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type ExtrinsicAvgFieldsKeySpecifier = ('fee' | 'index' | 'tip' | 'version' | ExtrinsicAvgFieldsKeySpecifier)[];
-export type ExtrinsicAvgFieldsFieldPolicy = {
+export interface ExtrinsicAvgFieldsFieldPolicy {
 	fee?: FieldPolicy<any> | FieldReadFunction<any>,
 	index?: FieldPolicy<any> | FieldReadFunction<any>,
 	tip?: FieldPolicy<any> | FieldReadFunction<any>,
 	version?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type ExtrinsicConnectionKeySpecifier = ('edges' | 'pageInfo' | ExtrinsicConnectionKeySpecifier)[];
-export type ExtrinsicConnectionFieldPolicy = {
+export interface ExtrinsicConnectionFieldPolicy {
 	edges?: FieldPolicy<any> | FieldReadFunction<any>,
 	pageInfo?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type ExtrinsicEdgeKeySpecifier = ('cursor' | 'node' | ExtrinsicEdgeKeySpecifier)[];
-export type ExtrinsicEdgeFieldPolicy = {
+export interface ExtrinsicEdgeFieldPolicy {
 	cursor?: FieldPolicy<any> | FieldReadFunction<any>,
 	node?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type ExtrinsicMaxFieldsKeySpecifier = ('blockId' | 'callId' | 'fee' | 'id' | 'index' | 'tip' | 'version' | ExtrinsicMaxFieldsKeySpecifier)[];
-export type ExtrinsicMaxFieldsFieldPolicy = {
+export interface ExtrinsicMaxFieldsFieldPolicy {
 	blockId?: FieldPolicy<any> | FieldReadFunction<any>,
 	callId?: FieldPolicy<any> | FieldReadFunction<any>,
 	fee?: FieldPolicy<any> | FieldReadFunction<any>,
@@ -610,9 +608,9 @@ export type ExtrinsicMaxFieldsFieldPolicy = {
 	index?: FieldPolicy<any> | FieldReadFunction<any>,
 	tip?: FieldPolicy<any> | FieldReadFunction<any>,
 	version?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type ExtrinsicMinFieldsKeySpecifier = ('blockId' | 'callId' | 'fee' | 'id' | 'index' | 'tip' | 'version' | ExtrinsicMinFieldsKeySpecifier)[];
-export type ExtrinsicMinFieldsFieldPolicy = {
+export interface ExtrinsicMinFieldsFieldPolicy {
 	blockId?: FieldPolicy<any> | FieldReadFunction<any>,
 	callId?: FieldPolicy<any> | FieldReadFunction<any>,
 	fee?: FieldPolicy<any> | FieldReadFunction<any>,
@@ -620,58 +618,58 @@ export type ExtrinsicMinFieldsFieldPolicy = {
 	index?: FieldPolicy<any> | FieldReadFunction<any>,
 	tip?: FieldPolicy<any> | FieldReadFunction<any>,
 	version?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type ExtrinsicStddevFieldsKeySpecifier = ('fee' | 'index' | 'tip' | 'version' | ExtrinsicStddevFieldsKeySpecifier)[];
-export type ExtrinsicStddevFieldsFieldPolicy = {
+export interface ExtrinsicStddevFieldsFieldPolicy {
 	fee?: FieldPolicy<any> | FieldReadFunction<any>,
 	index?: FieldPolicy<any> | FieldReadFunction<any>,
 	tip?: FieldPolicy<any> | FieldReadFunction<any>,
 	version?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type ExtrinsicStddevPopFieldsKeySpecifier = ('fee' | 'index' | 'tip' | 'version' | ExtrinsicStddevPopFieldsKeySpecifier)[];
-export type ExtrinsicStddevPopFieldsFieldPolicy = {
+export interface ExtrinsicStddevPopFieldsFieldPolicy {
 	fee?: FieldPolicy<any> | FieldReadFunction<any>,
 	index?: FieldPolicy<any> | FieldReadFunction<any>,
 	tip?: FieldPolicy<any> | FieldReadFunction<any>,
 	version?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type ExtrinsicStddevSampFieldsKeySpecifier = ('fee' | 'index' | 'tip' | 'version' | ExtrinsicStddevSampFieldsKeySpecifier)[];
-export type ExtrinsicStddevSampFieldsFieldPolicy = {
+export interface ExtrinsicStddevSampFieldsFieldPolicy {
 	fee?: FieldPolicy<any> | FieldReadFunction<any>,
 	index?: FieldPolicy<any> | FieldReadFunction<any>,
 	tip?: FieldPolicy<any> | FieldReadFunction<any>,
 	version?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type ExtrinsicSumFieldsKeySpecifier = ('fee' | 'index' | 'tip' | 'version' | ExtrinsicSumFieldsKeySpecifier)[];
-export type ExtrinsicSumFieldsFieldPolicy = {
+export interface ExtrinsicSumFieldsFieldPolicy {
 	fee?: FieldPolicy<any> | FieldReadFunction<any>,
 	index?: FieldPolicy<any> | FieldReadFunction<any>,
 	tip?: FieldPolicy<any> | FieldReadFunction<any>,
 	version?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type ExtrinsicVarPopFieldsKeySpecifier = ('fee' | 'index' | 'tip' | 'version' | ExtrinsicVarPopFieldsKeySpecifier)[];
-export type ExtrinsicVarPopFieldsFieldPolicy = {
+export interface ExtrinsicVarPopFieldsFieldPolicy {
 	fee?: FieldPolicy<any> | FieldReadFunction<any>,
 	index?: FieldPolicy<any> | FieldReadFunction<any>,
 	tip?: FieldPolicy<any> | FieldReadFunction<any>,
 	version?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type ExtrinsicVarSampFieldsKeySpecifier = ('fee' | 'index' | 'tip' | 'version' | ExtrinsicVarSampFieldsKeySpecifier)[];
-export type ExtrinsicVarSampFieldsFieldPolicy = {
+export interface ExtrinsicVarSampFieldsFieldPolicy {
 	fee?: FieldPolicy<any> | FieldReadFunction<any>,
 	index?: FieldPolicy<any> | FieldReadFunction<any>,
 	tip?: FieldPolicy<any> | FieldReadFunction<any>,
 	version?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type ExtrinsicVarianceFieldsKeySpecifier = ('fee' | 'index' | 'tip' | 'version' | ExtrinsicVarianceFieldsKeySpecifier)[];
-export type ExtrinsicVarianceFieldsFieldPolicy = {
+export interface ExtrinsicVarianceFieldsFieldPolicy {
 	fee?: FieldPolicy<any> | FieldReadFunction<any>,
 	index?: FieldPolicy<any> | FieldReadFunction<any>,
 	tip?: FieldPolicy<any> | FieldReadFunction<any>,
 	version?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type IdentityKeySpecifier = ('account' | 'accountId' | 'certIssued' | 'certIssuedAggregate' | 'certIssued_connection' | 'certReceived' | 'certReceivedAggregate' | 'certReceived_connection' | 'createdIn' | 'createdInId' | 'createdOn' | 'expireOn' | 'id' | 'index' | 'isMember' | 'lastChangeOn' | 'linkedAccount' | 'linkedAccountAggregate' | 'linkedAccount_connection' | 'membershipHistory' | 'membershipHistoryAggregate' | 'membershipHistory_connection' | 'name' | 'ownerKeyChange' | 'ownerKeyChangeAggregate' | 'ownerKeyChange_connection' | 'smithCertIssued' | 'smithCertIssuedAggregate' | 'smithCertIssued_connection' | 'smithCertReceived' | 'smithCertReceivedAggregate' | 'smithCertReceived_connection' | 'smithStatus' | 'status' | 'udHistory' | IdentityKeySpecifier)[];
-export type IdentityFieldPolicy = {
+export interface IdentityFieldPolicy {
 	account?: FieldPolicy<any> | FieldReadFunction<any>,
 	accountId?: FieldPolicy<any> | FieldReadFunction<any>,
 	certIssued?: FieldPolicy<any> | FieldReadFunction<any>,
@@ -707,36 +705,36 @@ export type IdentityFieldPolicy = {
 	smithStatus?: FieldPolicy<any> | FieldReadFunction<any>,
 	status?: FieldPolicy<any> | FieldReadFunction<any>,
 	udHistory?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type IdentityConnectionKeySpecifier = ('edges' | 'pageInfo' | IdentityConnectionKeySpecifier)[];
-export type IdentityConnectionFieldPolicy = {
+export interface IdentityConnectionFieldPolicy {
 	edges?: FieldPolicy<any> | FieldReadFunction<any>,
 	pageInfo?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type IdentityEdgeKeySpecifier = ('cursor' | 'node' | IdentityEdgeKeySpecifier)[];
-export type IdentityEdgeFieldPolicy = {
+export interface IdentityEdgeFieldPolicy {
 	cursor?: FieldPolicy<any> | FieldReadFunction<any>,
 	node?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type ItemsCounterKeySpecifier = ('id' | 'level' | 'total' | 'type' | ItemsCounterKeySpecifier)[];
-export type ItemsCounterFieldPolicy = {
+export interface ItemsCounterFieldPolicy {
 	id?: FieldPolicy<any> | FieldReadFunction<any>,
 	level?: FieldPolicy<any> | FieldReadFunction<any>,
 	total?: FieldPolicy<any> | FieldReadFunction<any>,
 	type?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type ItemsCounterConnectionKeySpecifier = ('edges' | 'pageInfo' | ItemsCounterConnectionKeySpecifier)[];
-export type ItemsCounterConnectionFieldPolicy = {
+export interface ItemsCounterConnectionFieldPolicy {
 	edges?: FieldPolicy<any> | FieldReadFunction<any>,
 	pageInfo?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type ItemsCounterEdgeKeySpecifier = ('cursor' | 'node' | ItemsCounterEdgeKeySpecifier)[];
-export type ItemsCounterEdgeFieldPolicy = {
+export interface ItemsCounterEdgeFieldPolicy {
 	cursor?: FieldPolicy<any> | FieldReadFunction<any>,
 	node?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type MembershipEventKeySpecifier = ('blockNumber' | 'event' | 'eventId' | 'eventType' | 'id' | 'identity' | 'identityId' | MembershipEventKeySpecifier)[];
-export type MembershipEventFieldPolicy = {
+export interface MembershipEventFieldPolicy {
 	blockNumber?: FieldPolicy<any> | FieldReadFunction<any>,
 	event?: FieldPolicy<any> | FieldReadFunction<any>,
 	eventId?: FieldPolicy<any> | FieldReadFunction<any>,
@@ -744,14 +742,14 @@ export type MembershipEventFieldPolicy = {
 	id?: FieldPolicy<any> | FieldReadFunction<any>,
 	identity?: FieldPolicy<any> | FieldReadFunction<any>,
 	identityId?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type MembershipEventAggregateKeySpecifier = ('aggregate' | 'nodes' | MembershipEventAggregateKeySpecifier)[];
-export type MembershipEventAggregateFieldPolicy = {
+export interface MembershipEventAggregateFieldPolicy {
 	aggregate?: FieldPolicy<any> | FieldReadFunction<any>,
 	nodes?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type MembershipEventAggregateFieldsKeySpecifier = ('avg' | 'count' | 'max' | 'min' | 'stddev' | 'stddevPop' | 'stddevSamp' | 'sum' | 'varPop' | 'varSamp' | 'variance' | MembershipEventAggregateFieldsKeySpecifier)[];
-export type MembershipEventAggregateFieldsFieldPolicy = {
+export interface MembershipEventAggregateFieldsFieldPolicy {
 	avg?: FieldPolicy<any> | FieldReadFunction<any>,
 	count?: FieldPolicy<any> | FieldReadFunction<any>,
 	max?: FieldPolicy<any> | FieldReadFunction<any>,
@@ -763,90 +761,90 @@ export type MembershipEventAggregateFieldsFieldPolicy = {
 	varPop?: FieldPolicy<any> | FieldReadFunction<any>,
 	varSamp?: FieldPolicy<any> | FieldReadFunction<any>,
 	variance?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type MembershipEventAvgFieldsKeySpecifier = ('blockNumber' | MembershipEventAvgFieldsKeySpecifier)[];
-export type MembershipEventAvgFieldsFieldPolicy = {
+export interface MembershipEventAvgFieldsFieldPolicy {
 	blockNumber?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type MembershipEventConnectionKeySpecifier = ('edges' | 'pageInfo' | MembershipEventConnectionKeySpecifier)[];
-export type MembershipEventConnectionFieldPolicy = {
+export interface MembershipEventConnectionFieldPolicy {
 	edges?: FieldPolicy<any> | FieldReadFunction<any>,
 	pageInfo?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type MembershipEventEdgeKeySpecifier = ('cursor' | 'node' | MembershipEventEdgeKeySpecifier)[];
-export type MembershipEventEdgeFieldPolicy = {
+export interface MembershipEventEdgeFieldPolicy {
 	cursor?: FieldPolicy<any> | FieldReadFunction<any>,
 	node?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type MembershipEventMaxFieldsKeySpecifier = ('blockNumber' | 'eventId' | 'id' | 'identityId' | MembershipEventMaxFieldsKeySpecifier)[];
-export type MembershipEventMaxFieldsFieldPolicy = {
+export interface MembershipEventMaxFieldsFieldPolicy {
 	blockNumber?: FieldPolicy<any> | FieldReadFunction<any>,
 	eventId?: FieldPolicy<any> | FieldReadFunction<any>,
 	id?: FieldPolicy<any> | FieldReadFunction<any>,
 	identityId?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type MembershipEventMinFieldsKeySpecifier = ('blockNumber' | 'eventId' | 'id' | 'identityId' | MembershipEventMinFieldsKeySpecifier)[];
-export type MembershipEventMinFieldsFieldPolicy = {
+export interface MembershipEventMinFieldsFieldPolicy {
 	blockNumber?: FieldPolicy<any> | FieldReadFunction<any>,
 	eventId?: FieldPolicy<any> | FieldReadFunction<any>,
 	id?: FieldPolicy<any> | FieldReadFunction<any>,
 	identityId?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type MembershipEventStddevFieldsKeySpecifier = ('blockNumber' | MembershipEventStddevFieldsKeySpecifier)[];
-export type MembershipEventStddevFieldsFieldPolicy = {
+export interface MembershipEventStddevFieldsFieldPolicy {
 	blockNumber?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type MembershipEventStddevPopFieldsKeySpecifier = ('blockNumber' | MembershipEventStddevPopFieldsKeySpecifier)[];
-export type MembershipEventStddevPopFieldsFieldPolicy = {
+export interface MembershipEventStddevPopFieldsFieldPolicy {
 	blockNumber?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type MembershipEventStddevSampFieldsKeySpecifier = ('blockNumber' | MembershipEventStddevSampFieldsKeySpecifier)[];
-export type MembershipEventStddevSampFieldsFieldPolicy = {
+export interface MembershipEventStddevSampFieldsFieldPolicy {
 	blockNumber?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type MembershipEventSumFieldsKeySpecifier = ('blockNumber' | MembershipEventSumFieldsKeySpecifier)[];
-export type MembershipEventSumFieldsFieldPolicy = {
+export interface MembershipEventSumFieldsFieldPolicy {
 	blockNumber?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type MembershipEventVarPopFieldsKeySpecifier = ('blockNumber' | MembershipEventVarPopFieldsKeySpecifier)[];
-export type MembershipEventVarPopFieldsFieldPolicy = {
+export interface MembershipEventVarPopFieldsFieldPolicy {
 	blockNumber?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type MembershipEventVarSampFieldsKeySpecifier = ('blockNumber' | MembershipEventVarSampFieldsKeySpecifier)[];
-export type MembershipEventVarSampFieldsFieldPolicy = {
+export interface MembershipEventVarSampFieldsFieldPolicy {
 	blockNumber?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type MembershipEventVarianceFieldsKeySpecifier = ('blockNumber' | MembershipEventVarianceFieldsKeySpecifier)[];
-export type MembershipEventVarianceFieldsFieldPolicy = {
+export interface MembershipEventVarianceFieldsFieldPolicy {
 	blockNumber?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type NodeKeySpecifier = ('id' | NodeKeySpecifier)[];
-export type NodeFieldPolicy = {
+export interface NodeFieldPolicy {
 	id?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type PageInfoKeySpecifier = ('endCursor' | 'hasNextPage' | 'hasPreviousPage' | 'startCursor' | PageInfoKeySpecifier)[];
-export type PageInfoFieldPolicy = {
+export interface PageInfoFieldPolicy {
 	endCursor?: FieldPolicy<any> | FieldReadFunction<any>,
 	hasNextPage?: FieldPolicy<any> | FieldReadFunction<any>,
 	hasPreviousPage?: FieldPolicy<any> | FieldReadFunction<any>,
 	startCursor?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type SmithCertKeySpecifier = ('createdOn' | 'id' | 'issuer' | 'issuerId' | 'receiver' | 'receiverId' | SmithCertKeySpecifier)[];
-export type SmithCertFieldPolicy = {
+export interface SmithCertFieldPolicy {
 	createdOn?: FieldPolicy<any> | FieldReadFunction<any>,
 	id?: FieldPolicy<any> | FieldReadFunction<any>,
 	issuer?: FieldPolicy<any> | FieldReadFunction<any>,
 	issuerId?: FieldPolicy<any> | FieldReadFunction<any>,
 	receiver?: FieldPolicy<any> | FieldReadFunction<any>,
 	receiverId?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type SmithCertAggregateKeySpecifier = ('aggregate' | 'nodes' | SmithCertAggregateKeySpecifier)[];
-export type SmithCertAggregateFieldPolicy = {
+export interface SmithCertAggregateFieldPolicy {
 	aggregate?: FieldPolicy<any> | FieldReadFunction<any>,
 	nodes?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type SmithCertAggregateFieldsKeySpecifier = ('avg' | 'count' | 'max' | 'min' | 'stddev' | 'stddevPop' | 'stddevSamp' | 'sum' | 'varPop' | 'varSamp' | 'variance' | SmithCertAggregateFieldsKeySpecifier)[];
-export type SmithCertAggregateFieldsFieldPolicy = {
+export interface SmithCertAggregateFieldsFieldPolicy {
 	avg?: FieldPolicy<any> | FieldReadFunction<any>,
 	count?: FieldPolicy<any> | FieldReadFunction<any>,
 	max?: FieldPolicy<any> | FieldReadFunction<any>,
@@ -858,65 +856,65 @@ export type SmithCertAggregateFieldsFieldPolicy = {
 	varPop?: FieldPolicy<any> | FieldReadFunction<any>,
 	varSamp?: FieldPolicy<any> | FieldReadFunction<any>,
 	variance?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type SmithCertAvgFieldsKeySpecifier = ('createdOn' | SmithCertAvgFieldsKeySpecifier)[];
-export type SmithCertAvgFieldsFieldPolicy = {
+export interface SmithCertAvgFieldsFieldPolicy {
 	createdOn?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type SmithCertConnectionKeySpecifier = ('edges' | 'pageInfo' | SmithCertConnectionKeySpecifier)[];
-export type SmithCertConnectionFieldPolicy = {
+export interface SmithCertConnectionFieldPolicy {
 	edges?: FieldPolicy<any> | FieldReadFunction<any>,
 	pageInfo?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type SmithCertEdgeKeySpecifier = ('cursor' | 'node' | SmithCertEdgeKeySpecifier)[];
-export type SmithCertEdgeFieldPolicy = {
+export interface SmithCertEdgeFieldPolicy {
 	cursor?: FieldPolicy<any> | FieldReadFunction<any>,
 	node?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type SmithCertMaxFieldsKeySpecifier = ('createdOn' | 'id' | 'issuerId' | 'receiverId' | SmithCertMaxFieldsKeySpecifier)[];
-export type SmithCertMaxFieldsFieldPolicy = {
+export interface SmithCertMaxFieldsFieldPolicy {
 	createdOn?: FieldPolicy<any> | FieldReadFunction<any>,
 	id?: FieldPolicy<any> | FieldReadFunction<any>,
 	issuerId?: FieldPolicy<any> | FieldReadFunction<any>,
 	receiverId?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type SmithCertMinFieldsKeySpecifier = ('createdOn' | 'id' | 'issuerId' | 'receiverId' | SmithCertMinFieldsKeySpecifier)[];
-export type SmithCertMinFieldsFieldPolicy = {
+export interface SmithCertMinFieldsFieldPolicy {
 	createdOn?: FieldPolicy<any> | FieldReadFunction<any>,
 	id?: FieldPolicy<any> | FieldReadFunction<any>,
 	issuerId?: FieldPolicy<any> | FieldReadFunction<any>,
 	receiverId?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type SmithCertStddevFieldsKeySpecifier = ('createdOn' | SmithCertStddevFieldsKeySpecifier)[];
-export type SmithCertStddevFieldsFieldPolicy = {
+export interface SmithCertStddevFieldsFieldPolicy {
 	createdOn?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type SmithCertStddevPopFieldsKeySpecifier = ('createdOn' | SmithCertStddevPopFieldsKeySpecifier)[];
-export type SmithCertStddevPopFieldsFieldPolicy = {
+export interface SmithCertStddevPopFieldsFieldPolicy {
 	createdOn?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type SmithCertStddevSampFieldsKeySpecifier = ('createdOn' | SmithCertStddevSampFieldsKeySpecifier)[];
-export type SmithCertStddevSampFieldsFieldPolicy = {
+export interface SmithCertStddevSampFieldsFieldPolicy {
 	createdOn?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type SmithCertSumFieldsKeySpecifier = ('createdOn' | SmithCertSumFieldsKeySpecifier)[];
-export type SmithCertSumFieldsFieldPolicy = {
+export interface SmithCertSumFieldsFieldPolicy {
 	createdOn?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type SmithCertVarPopFieldsKeySpecifier = ('createdOn' | SmithCertVarPopFieldsKeySpecifier)[];
-export type SmithCertVarPopFieldsFieldPolicy = {
+export interface SmithCertVarPopFieldsFieldPolicy {
 	createdOn?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type SmithCertVarSampFieldsKeySpecifier = ('createdOn' | SmithCertVarSampFieldsKeySpecifier)[];
-export type SmithCertVarSampFieldsFieldPolicy = {
+export interface SmithCertVarSampFieldsFieldPolicy {
 	createdOn?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type SmithCertVarianceFieldsKeySpecifier = ('createdOn' | SmithCertVarianceFieldsKeySpecifier)[];
-export type SmithCertVarianceFieldsFieldPolicy = {
+export interface SmithCertVarianceFieldsFieldPolicy {
 	createdOn?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type TransferKeySpecifier = ('amount' | 'blockNumber' | 'comment' | 'from' | 'fromId' | 'id' | 'timestamp' | 'to' | 'toId' | TransferKeySpecifier)[];
-export type TransferFieldPolicy = {
+export interface TransferFieldPolicy {
 	amount?: FieldPolicy<any> | FieldReadFunction<any>,
 	blockNumber?: FieldPolicy<any> | FieldReadFunction<any>,
 	comment?: FieldPolicy<any> | FieldReadFunction<any>,
@@ -926,14 +924,14 @@ export type TransferFieldPolicy = {
 	timestamp?: FieldPolicy<any> | FieldReadFunction<any>,
 	to?: FieldPolicy<any> | FieldReadFunction<any>,
 	toId?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type TransferAggregateKeySpecifier = ('aggregate' | 'nodes' | TransferAggregateKeySpecifier)[];
-export type TransferAggregateFieldPolicy = {
+export interface TransferAggregateFieldPolicy {
 	aggregate?: FieldPolicy<any> | FieldReadFunction<any>,
 	nodes?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type TransferAggregateFieldsKeySpecifier = ('avg' | 'count' | 'max' | 'min' | 'stddev' | 'stddevPop' | 'stddevSamp' | 'sum' | 'varPop' | 'varSamp' | 'variance' | TransferAggregateFieldsKeySpecifier)[];
-export type TransferAggregateFieldsFieldPolicy = {
+export interface TransferAggregateFieldsFieldPolicy {
 	avg?: FieldPolicy<any> | FieldReadFunction<any>,
 	count?: FieldPolicy<any> | FieldReadFunction<any>,
 	max?: FieldPolicy<any> | FieldReadFunction<any>,
@@ -945,24 +943,24 @@ export type TransferAggregateFieldsFieldPolicy = {
 	varPop?: FieldPolicy<any> | FieldReadFunction<any>,
 	varSamp?: FieldPolicy<any> | FieldReadFunction<any>,
 	variance?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type TransferAvgFieldsKeySpecifier = ('amount' | 'blockNumber' | TransferAvgFieldsKeySpecifier)[];
-export type TransferAvgFieldsFieldPolicy = {
+export interface TransferAvgFieldsFieldPolicy {
 	amount?: FieldPolicy<any> | FieldReadFunction<any>,
 	blockNumber?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type TransferConnectionKeySpecifier = ('edges' | 'pageInfo' | TransferConnectionKeySpecifier)[];
-export type TransferConnectionFieldPolicy = {
+export interface TransferConnectionFieldPolicy {
 	edges?: FieldPolicy<any> | FieldReadFunction<any>,
 	pageInfo?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type TransferEdgeKeySpecifier = ('cursor' | 'node' | TransferEdgeKeySpecifier)[];
-export type TransferEdgeFieldPolicy = {
+export interface TransferEdgeFieldPolicy {
 	cursor?: FieldPolicy<any> | FieldReadFunction<any>,
 	node?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type TransferMaxFieldsKeySpecifier = ('amount' | 'blockNumber' | 'comment' | 'fromId' | 'id' | 'timestamp' | 'toId' | TransferMaxFieldsKeySpecifier)[];
-export type TransferMaxFieldsFieldPolicy = {
+export interface TransferMaxFieldsFieldPolicy {
 	amount?: FieldPolicy<any> | FieldReadFunction<any>,
 	blockNumber?: FieldPolicy<any> | FieldReadFunction<any>,
 	comment?: FieldPolicy<any> | FieldReadFunction<any>,
@@ -970,9 +968,9 @@ export type TransferMaxFieldsFieldPolicy = {
 	id?: FieldPolicy<any> | FieldReadFunction<any>,
 	timestamp?: FieldPolicy<any> | FieldReadFunction<any>,
 	toId?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type TransferMinFieldsKeySpecifier = ('amount' | 'blockNumber' | 'comment' | 'fromId' | 'id' | 'timestamp' | 'toId' | TransferMinFieldsKeySpecifier)[];
-export type TransferMinFieldsFieldPolicy = {
+export interface TransferMinFieldsFieldPolicy {
 	amount?: FieldPolicy<any> | FieldReadFunction<any>,
 	blockNumber?: FieldPolicy<any> | FieldReadFunction<any>,
 	comment?: FieldPolicy<any> | FieldReadFunction<any>,
@@ -980,63 +978,63 @@ export type TransferMinFieldsFieldPolicy = {
 	id?: FieldPolicy<any> | FieldReadFunction<any>,
 	timestamp?: FieldPolicy<any> | FieldReadFunction<any>,
 	toId?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type TransferStddevFieldsKeySpecifier = ('amount' | 'blockNumber' | TransferStddevFieldsKeySpecifier)[];
-export type TransferStddevFieldsFieldPolicy = {
+export interface TransferStddevFieldsFieldPolicy {
 	amount?: FieldPolicy<any> | FieldReadFunction<any>,
 	blockNumber?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type TransferStddevPopFieldsKeySpecifier = ('amount' | 'blockNumber' | TransferStddevPopFieldsKeySpecifier)[];
-export type TransferStddevPopFieldsFieldPolicy = {
+export interface TransferStddevPopFieldsFieldPolicy {
 	amount?: FieldPolicy<any> | FieldReadFunction<any>,
 	blockNumber?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type TransferStddevSampFieldsKeySpecifier = ('amount' | 'blockNumber' | TransferStddevSampFieldsKeySpecifier)[];
-export type TransferStddevSampFieldsFieldPolicy = {
+export interface TransferStddevSampFieldsFieldPolicy {
 	amount?: FieldPolicy<any> | FieldReadFunction<any>,
 	blockNumber?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type TransferSumFieldsKeySpecifier = ('amount' | 'blockNumber' | TransferSumFieldsKeySpecifier)[];
-export type TransferSumFieldsFieldPolicy = {
+export interface TransferSumFieldsFieldPolicy {
 	amount?: FieldPolicy<any> | FieldReadFunction<any>,
 	blockNumber?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type TransferVarPopFieldsKeySpecifier = ('amount' | 'blockNumber' | TransferVarPopFieldsKeySpecifier)[];
-export type TransferVarPopFieldsFieldPolicy = {
+export interface TransferVarPopFieldsFieldPolicy {
 	amount?: FieldPolicy<any> | FieldReadFunction<any>,
 	blockNumber?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type TransferVarSampFieldsKeySpecifier = ('amount' | 'blockNumber' | TransferVarSampFieldsKeySpecifier)[];
-export type TransferVarSampFieldsFieldPolicy = {
+export interface TransferVarSampFieldsFieldPolicy {
 	amount?: FieldPolicy<any> | FieldReadFunction<any>,
 	blockNumber?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type TransferVarianceFieldsKeySpecifier = ('amount' | 'blockNumber' | TransferVarianceFieldsKeySpecifier)[];
-export type TransferVarianceFieldsFieldPolicy = {
+export interface TransferVarianceFieldsFieldPolicy {
 	amount?: FieldPolicy<any> | FieldReadFunction<any>,
 	blockNumber?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type UdHistoryKeySpecifier = ('amount' | 'blockNumber' | 'id' | 'identity' | 'identityId' | 'timestamp' | UdHistoryKeySpecifier)[];
-export type UdHistoryFieldPolicy = {
+export interface UdHistoryFieldPolicy {
 	amount?: FieldPolicy<any> | FieldReadFunction<any>,
 	blockNumber?: FieldPolicy<any> | FieldReadFunction<any>,
 	id?: FieldPolicy<any> | FieldReadFunction<any>,
 	identity?: FieldPolicy<any> | FieldReadFunction<any>,
 	identityId?: FieldPolicy<any> | FieldReadFunction<any>,
 	timestamp?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type UdHistoryConnectionKeySpecifier = ('edges' | 'pageInfo' | UdHistoryConnectionKeySpecifier)[];
-export type UdHistoryConnectionFieldPolicy = {
+export interface UdHistoryConnectionFieldPolicy {
 	edges?: FieldPolicy<any> | FieldReadFunction<any>,
 	pageInfo?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type UdHistoryEdgeKeySpecifier = ('cursor' | 'node' | UdHistoryEdgeKeySpecifier)[];
-export type UdHistoryEdgeFieldPolicy = {
+export interface UdHistoryEdgeFieldPolicy {
 	cursor?: FieldPolicy<any> | FieldReadFunction<any>,
 	node?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type UdReevalKeySpecifier = ('blockNumber' | 'event' | 'eventId' | 'id' | 'membersCount' | 'monetaryMass' | 'newUdAmount' | 'timestamp' | UdReevalKeySpecifier)[];
-export type UdReevalFieldPolicy = {
+export interface UdReevalFieldPolicy {
 	blockNumber?: FieldPolicy<any> | FieldReadFunction<any>,
 	event?: FieldPolicy<any> | FieldReadFunction<any>,
 	eventId?: FieldPolicy<any> | FieldReadFunction<any>,
@@ -1045,19 +1043,19 @@ export type UdReevalFieldPolicy = {
 	monetaryMass?: FieldPolicy<any> | FieldReadFunction<any>,
 	newUdAmount?: FieldPolicy<any> | FieldReadFunction<any>,
 	timestamp?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type UdReevalConnectionKeySpecifier = ('edges' | 'pageInfo' | UdReevalConnectionKeySpecifier)[];
-export type UdReevalConnectionFieldPolicy = {
+export interface UdReevalConnectionFieldPolicy {
 	edges?: FieldPolicy<any> | FieldReadFunction<any>,
 	pageInfo?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type UdReevalEdgeKeySpecifier = ('cursor' | 'node' | UdReevalEdgeKeySpecifier)[];
-export type UdReevalEdgeFieldPolicy = {
+export interface UdReevalEdgeFieldPolicy {
 	cursor?: FieldPolicy<any> | FieldReadFunction<any>,
 	node?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type UniversalDividendKeySpecifier = ('amount' | 'blockNumber' | 'event' | 'eventId' | 'id' | 'membersCount' | 'monetaryMass' | 'timestamp' | UniversalDividendKeySpecifier)[];
-export type UniversalDividendFieldPolicy = {
+export interface UniversalDividendFieldPolicy {
 	amount?: FieldPolicy<any> | FieldReadFunction<any>,
 	blockNumber?: FieldPolicy<any> | FieldReadFunction<any>,
 	event?: FieldPolicy<any> | FieldReadFunction<any>,
@@ -1066,19 +1064,19 @@ export type UniversalDividendFieldPolicy = {
 	membersCount?: FieldPolicy<any> | FieldReadFunction<any>,
 	monetaryMass?: FieldPolicy<any> | FieldReadFunction<any>,
 	timestamp?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type UniversalDividendConnectionKeySpecifier = ('edges' | 'pageInfo' | UniversalDividendConnectionKeySpecifier)[];
-export type UniversalDividendConnectionFieldPolicy = {
+export interface UniversalDividendConnectionFieldPolicy {
 	edges?: FieldPolicy<any> | FieldReadFunction<any>,
 	pageInfo?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type UniversalDividendEdgeKeySpecifier = ('cursor' | 'node' | UniversalDividendEdgeKeySpecifier)[];
-export type UniversalDividendEdgeFieldPolicy = {
+export interface UniversalDividendEdgeFieldPolicy {
 	cursor?: FieldPolicy<any> | FieldReadFunction<any>,
 	node?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type query_rootKeySpecifier = ('accountConnection' | 'blockConnection' | 'callConnection' | 'certConnection' | 'certEventConnection' | 'changeOwnerKeyConnection' | 'eventConnection' | 'extrinsicConnection' | 'getUdHistory_connection' | 'identityConnection' | 'itemsCounterConnection' | 'membershipEventConnection' | 'node' | 'smithCertConnection' | 'transferConnection' | 'udHistoryConnection' | 'udReevalConnection' | 'universalDividendConnection' | query_rootKeySpecifier)[];
-export type query_rootFieldPolicy = {
+export interface query_rootFieldPolicy {
 	accountConnection?: FieldPolicy<any> | FieldReadFunction<any>,
 	blockConnection?: FieldPolicy<any> | FieldReadFunction<any>,
 	callConnection?: FieldPolicy<any> | FieldReadFunction<any>,
@@ -1097,9 +1095,9 @@ export type query_rootFieldPolicy = {
 	udHistoryConnection?: FieldPolicy<any> | FieldReadFunction<any>,
 	udReevalConnection?: FieldPolicy<any> | FieldReadFunction<any>,
 	universalDividendConnection?: FieldPolicy<any> | FieldReadFunction<any>
-};
+}
 export type subscription_rootKeySpecifier = ('accountConnection' | 'blockConnection' | 'callConnection' | 'certConnection' | 'certEventConnection' | 'changeOwnerKeyConnection' | 'eventConnection' | 'extrinsicConnection' | 'getUdHistory_connection' | 'identityConnection' | 'itemsCounterConnection' | 'membershipEventConnection' | 'node' | 'smithCertConnection' | 'transferConnection' | 'udHistoryConnection' | 'udReevalConnection' | 'universalDividendConnection' | subscription_rootKeySpecifier)[];
-export type subscription_rootFieldPolicy = {
+export interface subscription_rootFieldPolicy {
 	accountConnection?: FieldPolicy<any> | FieldReadFunction<any>,
 	blockConnection?: FieldPolicy<any> | FieldReadFunction<any>,
 	callConnection?: FieldPolicy<any> | FieldReadFunction<any>,
@@ -1118,8 +1116,8 @@ export type subscription_rootFieldPolicy = {
 	udHistoryConnection?: FieldPolicy<any> | FieldReadFunction<any>,
 	udReevalConnection?: FieldPolicy<any> | FieldReadFunction<any>,
 	universalDividendConnection?: FieldPolicy<any> | FieldReadFunction<any>
-};
-export type StrictTypedTypePolicies = {
+}
+export interface StrictTypedTypePolicies {
 	Account?: Omit<TypePolicy, "fields" | "keyFields"> & {
 		keyFields?: false | AccountKeySpecifier | (() => undefined | AccountKeySpecifier),
 		fields?: AccountFieldPolicy,
@@ -1744,5 +1742,5 @@ export type StrictTypedTypePolicies = {
 		keyFields?: false | subscription_rootKeySpecifier | (() => undefined | subscription_rootKeySpecifier),
 		fields?: subscription_rootFieldPolicy,
 	}
-};
+}
 export type TypedTypePolicies = StrictTypedTypePolicies & TypePolicies;
\ No newline at end of file
diff --git a/src/app/network/indexer/indexer-types.generated.ts b/src/app/network/indexer/indexer-types.generated.ts
index a5510cdb899b41b3eef37464d7f65607141665fe..632e8cce87aeff8370cb802524fad9b2492dcc56 100644
--- a/src/app/network/indexer/indexer-types.generated.ts
+++ b/src/app/network/indexer/indexer-types.generated.ts
@@ -4788,6 +4788,16 @@ export type WotSearchLastQueryVariables = Exact<{
 
 export type WotSearchLastQuery = { __typename?: 'query_root', accountConnection: { __typename?: 'AccountConnection', pageInfo: { __typename?: 'PageInfo', endCursor: string, hasNextPage: boolean }, edges: Array<{ __typename?: 'AccountEdge', node: { __typename?: 'Account', id: string, identity?: { __typename?: 'Identity', id: string, index: number, name: string, accountId?: string | null, status?: IdentityStatusEnum | null, isMember: boolean, createdOn: number, membershipHistory: Array<{ __typename: 'MembershipEvent', id: string, eventType?: EventTypeEnum | null }> } | null } }> } };
 
+export type WotSearchByUidQueryVariables = Exact<{
+  name: Scalars['String']['input'];
+  first: Scalars['Int']['input'];
+  after?: InputMaybe<Scalars['String']['input']>;
+  orderBy?: InputMaybe<Array<AccountOrderBy> | AccountOrderBy>;
+}>;
+
+
+export type WotSearchByUidQuery = { __typename?: 'query_root', accountConnection: { __typename?: 'AccountConnection', pageInfo: { __typename?: 'PageInfo', endCursor: string, hasNextPage: boolean }, edges: Array<{ __typename?: 'AccountEdge', node: { __typename?: 'Account', id: string, identity?: { __typename?: 'Identity', id: string, index: number, name: string, accountId?: string | null, status?: IdentityStatusEnum | null, isMember: boolean, createdOn: number, membershipHistory: Array<{ __typename: 'MembershipEvent', id: string, eventType?: EventTypeEnum | null }> } | null } }> } };
+
 export const LightIdentityFragmentDoc = gql`
     fragment LightIdentity on Identity {
   id
@@ -5142,6 +5152,29 @@ export const WotSearchLastDocument = gql`
       super(apollo);
     }
   }
+export const WotSearchByUidDocument = gql`
+    query WotSearchByUid($name: String!, $first: Int!, $after: String, $orderBy: [AccountOrderBy!]) {
+  accountConnection(
+    first: $first
+    after: $after
+    orderBy: $orderBy
+    where: {identity: {name: {_eq: $name}}}
+  ) {
+    ...LightAccountConnection
+  }
+}
+    ${LightAccountConnectionFragmentDoc}`;
+
+  @Injectable({
+    providedIn: 'root'
+  })
+  export class WotSearchByUidGQL extends Apollo.Query<WotSearchByUidQuery, WotSearchByUidQueryVariables> {
+    document = WotSearchByUidDocument;
+    client = 'indexer';
+    constructor(apollo: Apollo.Apollo) {
+      super(apollo);
+    }
+  }
 
   type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>;
 
@@ -5159,7 +5192,8 @@ export const WotSearchLastDocument = gql`
       private transferConnectionByAddressGql: TransferConnectionByAddressGQL,
       private wotSearchByTextGql: WotSearchByTextGQL,
       private wotSearchByAddressGql: WotSearchByAddressGQL,
-      private wotSearchLastGql: WotSearchLastGQL
+      private wotSearchLastGql: WotSearchLastGQL,
+      private wotSearchByUidGql: WotSearchByUidGQL
     ) {}
       
     blockById(variables: BlockByIdQueryVariables, options?: QueryOptionsAlone<BlockByIdQueryVariables>) {
@@ -5225,6 +5259,14 @@ export const WotSearchLastDocument = gql`
     wotSearchLastWatch(variables: WotSearchLastQueryVariables, options?: WatchQueryOptionsAlone<WotSearchLastQueryVariables>) {
       return this.wotSearchLastGql.watch(variables, options)
     }
+    
+    wotSearchByUid(variables: WotSearchByUidQueryVariables, options?: QueryOptionsAlone<WotSearchByUidQueryVariables>) {
+      return this.wotSearchByUidGql.fetch(variables, options)
+    }
+    
+    wotSearchByUidWatch(variables: WotSearchByUidQueryVariables, options?: WatchQueryOptionsAlone<WotSearchByUidQueryVariables>) {
+      return this.wotSearchByUidGql.watch(variables, options)
+    }
   }
 
       export interface PossibleTypesResultData {
diff --git a/src/app/network/indexer/indexer-wot.gql b/src/app/network/indexer/indexer-wot.gql
index 7c29f4ecce88956645adf7cb328bbd2ae288c5a0..f6f1607a029bd45c07d416bc8e68fb7761d99864 100644
--- a/src/app/network/indexer/indexer-wot.gql
+++ b/src/app/network/indexer/indexer-wot.gql
@@ -25,3 +25,10 @@ query WotSearchLast($first: Int!, $after: String, $orderBy: [AccountOrderBy!], $
     ...LightAccountConnection
   }
 }
+
+# search identities by exact name
+query WotSearchByUid($name: String!, $first: Int!, $after: String, $orderBy: [AccountOrderBy!]) {
+  accountConnection(first: $first, after: $after, orderBy: $orderBy, where: { identity: {name: { _eq: $name } }}) {
+    ...LightAccountConnection
+  }
+}
diff --git a/src/app/network/indexer/indexer.service.ts b/src/app/network/indexer/indexer.service.ts
index 92f6ac997c4b6aefd0bb9aa944871b95b8743469..b4b961de19451c2e0b5c5f3563d37896b491c429 100644
--- a/src/app/network/indexer/indexer.service.ts
+++ b/src/app/network/indexer/indexer.service.ts
@@ -94,7 +94,21 @@ export class IndexerService extends GraphqlService<IndexerState> {
     };
 
     let data$: Observable<LightAccountConnectionFragment>;
-    if (isNotNilOrBlank(filter.address)) {
+    if (isNotNilOrBlank(filter.uid)) {
+      data$ = this.graphqlService
+        .wotSearchByUid(
+          {
+            name: filter.uid,
+            after: options.after,
+            first: options.first,
+            orderBy: { identity: { index: OrderBy.Asc } },
+          },
+          {
+            fetchPolicy: options.fetchPolicy || 'cache-first',
+          }
+        )
+        .pipe(map(({ data }) => data.accountConnection as LightAccountConnectionFragment));
+    } else if (isNotNilOrBlank(filter.address)) {
       data$ = this.graphqlService
         .wotSearchByAddress(
           {
diff --git a/src/app/shared/constants.ts b/src/app/shared/constants.ts
new file mode 100644
index 0000000000000000000000000000000000000000..8518878af99edb52278f951a654bbbc9cefd14d3
--- /dev/null
+++ b/src/app/shared/constants.ts
@@ -0,0 +1,13 @@
+export const PUBKEY_REGEXP = /^[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{43,44}$/;
+export const UID_REGEXP = /^[0-9a-zA-Z-_]{3,42}$/;
+export const ADDRESS_REGEXP = /^[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{43,44}$/;
+
+export const DATE_ISO_PATTERN = 'YYYY-MM-DDTHH:mm:ss.SSSZ';
+export const DATE_PATTERN = 'YYYY-MM-DD';
+export const DATE_MATCH_REGEXP = new RegExp(/^\d+[-]\d+[-]\d+$/g);
+export const DEFAULT_PLACEHOLDER_CHAR = '\u005F';
+export const SPACE_PLACEHOLDER_CHAR = '\u2000';
+
+export const INTEGER_REGEXP = /^[-]?\d+$/;
+export const NUMBER_REGEXP = /^[-]?\d+(\.\d+)?$/;
+export const NUMBER_RANGE_REGEXP = /^(\d+-\d+)|([><=]*\d+)$/;
diff --git a/src/app/shared/form.class.ts b/src/app/shared/form.class.ts
index 715c13de06c6aa4eeb7e9f82244475f904dd1f85..fd9c19d7d209d2fa59bfe6da947e70fdedf158aa 100644
--- a/src/app/shared/form.class.ts
+++ b/src/app/shared/form.class.ts
@@ -1,4 +1,15 @@
-import { ChangeDetectorRef, Directive, EventEmitter, Injector, Input, OnDestroy, OnInit, Output } from '@angular/core';
+import {
+  booleanAttribute,
+  ChangeDetectorRef,
+  Directive,
+  EventEmitter,
+  inject,
+  Input,
+  numberAttribute,
+  OnDestroy,
+  OnInit,
+  Output,
+} from '@angular/core';
 import { FormGroup } from '@angular/forms';
 import { BehaviorSubject, Subscription } from 'rxjs';
 
@@ -6,6 +17,10 @@ import { TranslateService } from '@ngx-translate/core';
 import { FormUtils } from '@app/shared/forms';
 import { WaitForOptions, waitForTrue } from '@app/shared/observables';
 import { SettingsService } from '@app/settings/settings.service';
+import { environment } from '@environments/environment';
+import { logPrefix } from '@app/shared/logs';
+import { FormErrorTranslator, FormErrorTranslatorOptions, IFormPathTranslator } from '@app/shared/form/form-error-translator.service';
+import { changeCaseToUnderscore } from '@app/shared/functions';
 
 export declare interface OnReady {
   ngOnReady();
@@ -42,21 +57,27 @@ export interface IAppForm {
 
 @Directive()
 // eslint-disable-next-line @angular-eslint/directive-class-suffix
-export abstract class AppForm<T> implements IAppForm, OnInit, OnDestroy {
-  error: string = null;
+export abstract class AppForm<T> implements IAppForm, IFormPathTranslator, OnInit, OnDestroy {
+  private _subscription = new Subscription();
+
+  protected readonly _debug: boolean = !environment.production;
+  protected readonly _logPrefix: string;
 
-  protected translate: TranslateService;
-  protected _cd: ChangeDetectorRef;
+  protected _form: FormGroup;
+  protected _i18nPrefix: string = 'COMMON.';
+  protected _cd: ChangeDetectorRef = inject(ChangeDetectorRef);
   protected _enable = false;
   protected ready$ = new BehaviorSubject<boolean>(false);
   protected loading$ = new BehaviorSubject<boolean>(true);
 
-  private _subscription = new Subscription();
-  private _form: FormGroup;
+  protected readonly translate: TranslateService = inject(TranslateService);
+  protected readonly errorTranslator = inject(FormErrorTranslator);
 
-  @Input() debug = false;
-  @Input() mobile: boolean;
-  @Input() tabindex: number;
+  @Input({ transform: booleanAttribute }) debug = !environment.production;
+  @Input({ transform: booleanAttribute }) mobile: boolean = inject(SettingsService).mobile;
+  @Input() errorTranslatorOptions: FormErrorTranslatorOptions;
+  @Input({ transform: numberAttribute }) tabindex: number;
+  @Input() error: string = null;
 
   get loading(): boolean {
     return this.loading$.value;
@@ -127,19 +148,34 @@ export abstract class AppForm<T> implements IAppForm, OnInit, OnDestroy {
     return this._form;
   }
 
+  get statusChanges() {
+    return this._form.statusChanges;
+  }
+
   @Output() cancel = new EventEmitter<void>();
 
   @Output() validate = new EventEmitter<T>();
 
-  protected constructor(injector: Injector, form?: FormGroup) {
-    this.translate = injector.get(TranslateService);
-    this.mobile = injector.get(SettingsService).mobile;
-    this._cd = injector.get(ChangeDetectorRef);
+  protected constructor(
+    form?: FormGroup,
+    options?: {
+      name?: string;
+    }
+  ) {
     if (form) this.setForm(form);
+
+    // Log
+    this._logPrefix = logPrefix(this.constructor, options);
   }
 
   ngOnInit() {
-    this._enable ? this.enable() : this.disable();
+    // Init defaults
+    this.errorTranslatorOptions = this.errorTranslatorOptions || {
+      pathTranslator: this, // By default, will use translateFormPath() below to translate a form's path
+    };
+
+    if (this._enable) this.enable();
+    else this.disable();
   }
 
   ngOnDestroy() {
@@ -163,7 +199,7 @@ export abstract class AppForm<T> implements IAppForm, OnInit, OnDestroy {
    * @param event
    * @param opts allow to skip validation check, using {checkValid: false}
    */
-  async doSubmit(event: any, opts?: { checkValid?: boolean }) {
+  async doSubmit(event: Event, opts?: { checkValid?: boolean }) {
     if (!this._form) {
       this.markAllAsTouched({ emitEvent: true });
       return;
@@ -183,7 +219,7 @@ export abstract class AppForm<T> implements IAppForm, OnInit, OnDestroy {
     }
 
     // Emit event
-    this.validate.emit(event);
+    this.validate.emit(this._form.value);
   }
 
   setForm(form: FormGroup) {
@@ -299,8 +335,30 @@ export abstract class AppForm<T> implements IAppForm, OnInit, OnDestroy {
     if (!opts || opts.emitEvent !== false) this.markForCheck();
   }
 
+  translateFormPath(path: string) {
+    const i18nFieldName = this.getFormPathI18nKey(path);
+    return this.translate?.instant(i18nFieldName) || i18nFieldName;
+  }
+
   /* -- protected methods -- */
 
+  protected getFormError(form: FormGroup, opts?: FormErrorTranslatorOptions): string {
+    if (!form || !this.errorTranslator) return undefined;
+    return this.errorTranslator.translateFormErrors(this.form, {
+      pathTranslator: this,
+      ...opts,
+    });
+  }
+
+  /**
+   * Translate path into a i18n key (e.g. 'pubkey' into 'COMMON.PUBKEY')
+   * @param path
+   * @protected
+   */
+  protected getFormPathI18nKey(path: string) {
+    return (this._i18nPrefix || '') + changeCaseToUnderscore(path).toUpperCase();
+  }
+
   protected registerSubscription(sub: Subscription) {
     this._subscription.add(sub);
   }
diff --git a/src/app/shared/form/form-error-translator.service.ts b/src/app/shared/form/form-error-translator.service.ts
new file mode 100644
index 0000000000000000000000000000000000000000..40db7f6c46ed4b587e06f7e717a626348ff308d9
--- /dev/null
+++ b/src/app/shared/form/form-error-translator.service.ts
@@ -0,0 +1,130 @@
+import { changeCaseToUnderscore, isEmptyArray, isNil } from '../functions';
+import { Inject, Injectable, InjectionToken, Optional } from '@angular/core';
+import { TranslateService } from '@ngx-translate/core';
+import { AbstractControl } from '@angular/forms';
+import { FormErrors } from './form-errors';
+import { SharedValidators } from './form-validators';
+import { ObjectMap } from '../types';
+import { FormErrorUtils } from '@app/shared/form/form-errors';
+
+export const APP_FORM_ERROR_I18N_KEYS = new InjectionToken<ObjectMap<string>>('appFormErrorKeys');
+
+export interface IFormPathTranslator {
+  /**
+   * Translate a path on a form, into an i18n string
+   * @param path
+   */
+  translateFormPath: (path: string) => string;
+}
+
+export interface FormErrorTranslatorOptions {
+  i18nPrefix?: string;
+  pathTranslator?: IFormPathTranslator;
+  separator?: string;
+  recursive?: boolean;
+}
+
+@Injectable({ providedIn: 'root' })
+export class FormErrorTranslator implements IFormPathTranslator {
+  private readonly errorI18nKeys: ObjectMap<string>;
+
+  constructor(
+    private translate: TranslateService,
+    @Optional() @Inject(APP_FORM_ERROR_I18N_KEYS) errorI18nKeys: ObjectMap<string>
+  ) {
+    this.errorI18nKeys = {
+      ...SharedValidators.I18N_ERROR_KEYS,
+      ...errorI18nKeys,
+    };
+  }
+
+  translateFormErrors(control: AbstractControl, opts?: FormErrorTranslatorOptions): string {
+    if (!control || !control.invalid) return '';
+
+    const separator = (opts && opts.separator) || ', ';
+    const recursive = !opts || opts.recursive !== false;
+    const errors = FormErrorUtils.getFormErrors(control, { recursive });
+    return (
+      errors &&
+      Object.keys(errors).reduce((res, path) => {
+        const childControl = control.get(path);
+        // Should be a control map of errors
+        if (childControl) {
+          // Try to convert the control path
+          const i18nPath = this.translateFormPath(path, opts);
+
+          // OK, we have a field name: use it
+          const columnErrors = Object.keys(childControl.errors).map((errorKey) => this.translateError(errorKey, childControl.errors[errorKey]));
+          if (isEmptyArray(columnErrors)) return res;
+          // Add separator
+          if (res.length) res += separator;
+          return res + i18nPath + ': ' + columnErrors.join(separator);
+        }
+
+        // Or try as global form error
+        const formError = this.translateError(path, errors[path]);
+        if (isNil(formError)) return res;
+        return res + (res.length ? separator : '') + formError;
+      }, '')
+    );
+  }
+
+  translateErrors(errors: FormErrors, opts?: FormErrorTranslatorOptions): string {
+    const separator = (opts && opts.separator) || ', ';
+    return (
+      errors &&
+      Object.keys(errors).reduce((res, path) => {
+        const pathErrors = errors[path];
+        // Should be a control map of errors
+
+        if (pathErrors) {
+          // Try to convert the control path
+          const i18nPath = this.translateFormPath(path, opts);
+
+          // OK, we have a field name: use it
+          const columnErrors = Object.keys(pathErrors).map((errorKey) => this.translateError(errorKey, pathErrors[errorKey]));
+          if (isEmptyArray(columnErrors)) return res;
+          // Add separator
+          if (res.length) res += separator;
+          return res + i18nPath + ': ' + columnErrors.join(separator);
+        }
+
+        // Or try as global form error
+        const formError = this.translateError(path, pathErrors);
+        if (isNil(formError)) return res;
+        return res + (res.length ? separator : '') + formError;
+      }, '')
+    );
+  }
+
+  translateFormPath(path: string, opts?: FormErrorTranslatorOptions): string {
+    if (opts?.pathTranslator) {
+      return opts?.pathTranslator.translateFormPath(path);
+    }
+    const i18nKey = ((opts && opts.i18nPrefix) || '') + changeCaseToUnderscore(path).toUpperCase();
+    return this.translate.instant(i18nKey);
+  }
+
+  translateError(errorKey: string, errorContent?: any) {
+    const i18nKey =
+      this.errorI18nKeys[errorKey] ||
+      // Try to generate a standard error key, like 'ERROR.FIELD_xxx_xxx'
+      'ERROR.FIELD_' + changeCaseToUnderscore(errorKey).toUpperCase();
+
+    let i18nMessage = this.translate.instant(i18nKey, errorContent);
+    if (i18nKey !== i18nMessage) return i18nMessage;
+
+    // Try to use the error content, as an i18n key
+    if (typeof errorContent === 'string') {
+      i18nMessage = this.translate.instant(errorContent);
+      if (errorContent !== i18nMessage) return i18nMessage;
+    }
+
+    // Not translated: show error
+    console.error(
+      `[form-error-adapter] Cannot translate error key '${errorKey}'. Please add more formErrorsKey into APP_FORM_ERROR_I18N_KEYS injection token`
+    );
+
+    return errorKey;
+  }
+}
diff --git a/src/app/shared/form/form-errors.ts b/src/app/shared/form/form-errors.ts
new file mode 100644
index 0000000000000000000000000000000000000000..6cd1a3a16fb58cfb164f89dc86b350fe9eac6eff
--- /dev/null
+++ b/src/app/shared/form/form-errors.ts
@@ -0,0 +1,78 @@
+import { AbstractControl, FormArray, FormGroup, ValidationErrors } from '@angular/forms';
+
+export interface FormErrors {
+  [key: string]: ValidationErrors;
+}
+
+export abstract class FormErrorUtils {
+  static getFormErrors(
+    control: AbstractControl,
+    opts?: {
+      controlName?: string;
+      result?: FormErrors;
+      recursive?: boolean;
+    }
+  ): FormErrors {
+    if (!control || control.valid) return undefined;
+
+    opts = opts || {};
+    opts.result = opts.result || {};
+
+    // Form group
+    if (control instanceof FormGroup) {
+      // Copy errors
+      if (control.errors) {
+        if (opts.controlName) {
+          opts.result[opts.controlName] = {
+            ...control.errors,
+          };
+        } else {
+          opts.result = {
+            ...opts.result,
+            ...control.errors,
+          };
+        }
+      }
+
+      if (!opts || opts.recursive !== false) {
+        // Loop on children controls
+        for (const key in control.controls) {
+          const child = control.controls[key];
+          if (child?.enabled) {
+            this.getFormErrors(child, {
+              ...opts,
+              controlName: opts.controlName ? [opts.controlName, key].join('.') : key,
+              result: opts.result, // Make sure to keep the same result object
+            });
+          }
+        }
+      }
+    }
+
+    // Form array
+    else if (control instanceof FormArray) {
+      control.controls.forEach((child, index) => {
+        this.getFormErrors(child, {
+          ...opts,
+          controlName: (opts.controlName || '') + '.' + index,
+          result: opts.result, // Make sure to keep the same result object
+        });
+      });
+    }
+
+    // Other type of control (e.g. simple control)
+    else if (control.errors) {
+      if (opts.controlName) {
+        opts.result[opts.controlName] = {
+          ...control.errors,
+        };
+      } else {
+        opts.result = {
+          ...opts.result,
+          ...control.errors,
+        };
+      }
+    }
+    return opts.result;
+  }
+}
diff --git a/src/app/shared/form/form-validators.ts b/src/app/shared/form/form-validators.ts
new file mode 100644
index 0000000000000000000000000000000000000000..d8bc4ba1b1817a85de11b1242f9125d0c203655a
--- /dev/null
+++ b/src/app/shared/form/form-validators.ts
@@ -0,0 +1,407 @@
+import { AbstractControl, FormControl, UntypedFormControl, UntypedFormGroup, ValidationErrors, ValidatorFn } from '@angular/forms';
+import { isMoment, Moment, unitOfTime } from 'moment';
+import { ADDRESS_REGEXP, PUBKEY_REGEXP, UID_REGEXP } from '../constants';
+import { isEmptyArray, isNil, isNilOrBlank, isNotNil, isNotNilOrBlank, toBoolean } from '../functions';
+import { fromDateISOString } from '../dates';
+
+// @dynamic
+export class SharedValidators {
+  private static _DOUBLE_REGEXP_CACHE = {
+    NO_LIMIT: /^-?\d+([.,]\d*)?$/,
+    1: /^-?\d+([.,]\d)?$/, // 1 decimal max
+    2: /^-?\d+([.,]\d{1,2})?$/, // 2 decimals max
+    3: /^-?\d+([.,]\d{1,3})?$/, // 3 decimals max
+  };
+
+  private static getDoubleRegexp(maxDecimals: number): RegExp {
+    if (isNil(maxDecimals)) return this._DOUBLE_REGEXP_CACHE.NO_LIMIT;
+
+    if (maxDecimals < 0) throw new Error(`Invalid maxDecimals value: ${maxDecimals}`);
+    const regexp = this._DOUBLE_REGEXP_CACHE[maxDecimals];
+    if (regexp) return regexp;
+
+    // New: add to cache
+    this._DOUBLE_REGEXP_CACHE[maxDecimals] = new RegExp(`^-?\\d+([.,]\\d{1,${maxDecimals}})?$`);
+    return this._DOUBLE_REGEXP_CACHE[maxDecimals];
+  }
+
+  static readonly I18N_ERROR_KEYS = {
+    required: 'ERROR.FIELD_REQUIRED',
+    min: 'ERROR.FIELD_MIN',
+    max: 'ERROR.FIELD_MAX',
+    minlength: 'ERROR.FIELD_TOO_SHORT_WITH_LENGTH',
+    maxlength: 'ERROR.FIELD_TOO_LONG_WITH_LENGTH',
+    accent: 'ERROR.FIELD_ACCENT',
+    pubkey: 'ERROR.FIELD_NOT_VALID_PUBKEY',
+    address: 'ERROR.FIELD_NOT_VALID_ADDRESS',
+    uid: 'ERROR.INVALID_USER_ID',
+    date: 'ERROR.FIELD_NOT_VALID_DATE',
+    dateIsAfter: 'ERROR.FIELD_NOT_VALID_DATE_AFTER',
+    dateIsBefore: 'ERROR.FIELD_NOT_VALID_DATE_BEFORE',
+    dateRange: 'ERROR.FIELD_NOT_VALID_DATE_RANGE',
+    dateMinDuration: 'ERROR.FIELD_NOT_VALID_DATE_MIN_DURATION',
+    dateMaxDuration: 'ERROR.FIELD_NOT_VALID_DATE_MAX_DURATION',
+    maxDecimals: 'ERROR.FIELD_MAXIMUM_DECIMALS',
+    decimal: 'ERROR.FIELD_NOT_VALID_DECIMAL',
+    integer: 'ERROR.FIELD_NOT_INT',
+    email: 'ERROR.FIELD_NOT_VALID_EMAIL',
+    pattern: 'ERROR.FIELD_NOT_VALID_PATTERN',
+    unique: 'ERROR.FIELD_NOT_UNIQUE',
+  };
+
+  static empty(control: UntypedFormControl): ValidationErrors | null {
+    if (isNotNilOrBlank(control.value)) {
+      return { empty: true };
+    }
+    return null;
+  }
+
+  static pubkey(control: UntypedFormControl): ValidationErrors | null {
+    const value = control.value;
+    if (value && (typeof value !== 'string' || !PUBKEY_REGEXP.test(value))) {
+      return { pubkey: true };
+    }
+    return null;
+  }
+
+  static address(control: UntypedFormControl): ValidationErrors | null {
+    const value = control.value;
+    if (value && (typeof value !== 'string' || !ADDRESS_REGEXP.test(value))) {
+      return { address: true };
+    }
+    return null;
+  }
+
+  static uid(control: FormControl<string>): ValidationErrors {
+    const value = control.value;
+    if (value && (typeof value !== 'string' || !UID_REGEXP.test(value))) {
+      return { uid: true };
+    }
+    return null;
+  }
+
+  static integer(control: UntypedFormControl): ValidationErrors | null {
+    if (isNilOrBlank(control.value)) return null;
+    const value = parseFloat(control.value);
+    if (isNaN(value) || (value | 0) !== value) {
+      return { integer: true };
+    }
+    return null;
+  }
+
+  static decimal(opts?: { maxDecimals?: number }): ValidatorFn {
+    const regexp = this.getDoubleRegexp(opts?.maxDecimals);
+    return (control: UntypedFormControl): ValidationErrors | null => {
+      const value = control.value;
+      if (Number.isNaN(value)) {
+        // DEBUG
+        //console.debug("WARN: Getting a NaN value (decimal was expected) !");
+        return null;
+      }
+      if (isNotNil(value) && value !== '' && !regexp.test(value as string)) {
+        return isNotNil(opts?.maxDecimals) ? { maxDecimals: { maxDecimals: opts.maxDecimals } } : { decimal: true };
+      }
+      return null;
+    };
+  }
+
+  /**
+   * Check precision. e.g. if precision=0.5 then value=0.6 is invalid, but 1.5 is valid
+   *
+   * @param precision
+   */
+  static precision(precision: number): ValidatorFn {
+    if (isNil(precision)) throw new Error('Required a not nil precision');
+
+    // WARN: we should define a multiplier, because modulo in javascript will only work on integer
+    // (e.g. "7 % 0.1" in javascript will NOT return zero (but 0.09999999999999962)
+    const precisionNbDecimals = (precision.toString().split('.')[1] || '').length;
+    const multiplier = Math.pow(10, precisionNbDecimals);
+    const multipliedPrecision = Math.round(multiplier * precision);
+
+    // The validator function
+    return (control: UntypedFormControl): ValidationErrors | null => {
+      const value = control.value;
+      if (isNilOrBlank(value) || Number.isNaN(value)) {
+        return null;
+      }
+      // WARN: Convert value into integer, before applying modulo operator
+      const mod = Math.round(+value * multiplier) % multipliedPrecision;
+      if (mod !== 0) {
+        // DEBUG
+        //console.debug(`WARN Getting a ${value} with an invalid precision (expected precision is: ${precision})`);
+        return { precision: { precision } };
+      }
+      return null;
+    };
+  }
+
+  static date(control: UntypedFormControl): ValidationErrors | null {
+    const value = control.value;
+    const date = !value || isMoment(value) ? value : fromDateISOString(value);
+    if (date && (!date.isValid() || date.year() < 1900)) {
+      return { date: true };
+    }
+    return null;
+  }
+
+  static dateIsAfter(previousValue: Moment, errorParam: string, granularity?: unitOfTime.StartOf): ValidatorFn {
+    return (control: AbstractControl): ValidationErrors | null => {
+      const value = fromDateISOString(control.value);
+      if (isNotNil(value) && isNotNil(previousValue) && value.isSameOrBefore(previousValue, granularity)) {
+        // Return the error
+        return { dateIsAfter: { minDate: errorParam } };
+      }
+      return null;
+    };
+  }
+
+  static dateIsBefore(maxValue: Moment, errorParam: string, granularity?: unitOfTime.StartOf): ValidatorFn {
+    return (control: AbstractControl): ValidationErrors | null => {
+      const value = fromDateISOString(control.value);
+      if (isNotNil(value) && isNotNil(maxValue) && value.isSameOrAfter(maxValue, granularity)) {
+        // Return the error
+        return { dateIsBefore: { maxDate: errorParam } };
+      }
+      return null;
+    };
+  }
+
+  static dateRangeEnd(startDateFieldName: string, msg?: string): ValidatorFn {
+    const errorCode = msg ? 'msg' : 'dateRange';
+    const error = msg ? { msg } : { dateRange: true };
+    return (control: AbstractControl): ValidationErrors | null => {
+      // Form group not created yet: skip
+      if (!control.parent) return null;
+
+      const startControl = control.parent.get(startDateFieldName);
+      if (!startControl) {
+        console.warn(`Cannot find brother control '${startDateFieldName}' in the parent form`);
+        return null;
+      }
+      const startDate = fromDateISOString(startControl.value);
+      const endDate = fromDateISOString(control.value);
+      // Error if value <= beforeDate
+      if (isNotNil(endDate) && isNotNil(startDate) && endDate.isSameOrBefore(startDate)) {
+        return error;
+      }
+      // OK: clear existing errors
+      SharedValidators.clearError(control, errorCode);
+      return null;
+    };
+  }
+
+  static dateRangeStart(endDateFieldName: string, msg?: string): ValidatorFn {
+    const errorCode = msg ? 'msg' : 'dateRange';
+    const error = msg ? { msg } : { dateRange: true };
+    return (control: AbstractControl): ValidationErrors | null => {
+      // Form group not created yet: skip
+      if (!control.parent) return null;
+
+      const endDateControl = control.parent.get(endDateFieldName);
+      if (!endDateControl) {
+        console.warn(`Cannot find control '${endDateFieldName}' in the parent form`);
+        return null;
+      }
+      const endDate = fromDateISOString(endDateControl.value);
+      const startDate = fromDateISOString(control.value);
+      // Error if value <= beforeDate
+      if (isNotNil(startDate) && isNotNil(endDate) && startDate.isSameOrAfter(endDate)) {
+        return error;
+      }
+      // OK: clear existing errors
+      SharedValidators.clearError(control, errorCode);
+      return null;
+    };
+  }
+
+  static copyParentErrors(errorNames?: string[]): ValidatorFn {
+    return (control: AbstractControl): ValidationErrors | null => {
+      // Skip if control already has some errors
+      if (control.errors) return null;
+      // Skip if parent form group not created yet
+      if (!control.parent) return null;
+
+      // Form group not created yet
+      if (!control.parent) return null;
+
+      const errors = control.parent.errors;
+
+      // No errors, or copy all errors
+      if (!errors || isEmptyArray(errorNames)) return errors;
+
+      // Copy only expected errors
+      return Object.keys(errors).reduce((res, key) => {
+        if (errorNames.includes(key)) {
+          res[key] = errors[key];
+        }
+        return res;
+      }, {});
+    };
+  }
+
+  static clearError(control: AbstractControl, errorCode: string) {
+    if (control.hasError(errorCode)) {
+      const errors = control.errors;
+      if (errors && errors[errorCode]) {
+        // Only one error: reset errors
+        if (Object.getOwnPropertyNames(errors).length === 1) {
+          control.setErrors(null);
+        }
+        // Other errors exists: just remove this error
+        else {
+          delete errors[errorCode];
+          control.setErrors(errors);
+        }
+      }
+    }
+  }
+}
+
+// @dynamic
+export class SharedFormGroupValidators {
+  static dateRange(startDateField: string, endDateField: string, opts?: { msg?: string; fieldOnly?: boolean } | string): ValidatorFn {
+    const msg = typeof opts === 'string' ? opts : opts?.msg;
+    const fieldOnly = typeof opts === 'object' ? opts?.fieldOnly : undefined;
+    const errorCode = isNotNilOrBlank(msg) ? 'msg' : 'dateRange';
+    const rangeError = msg ? { msg } : { dateRange: true };
+    return (group: UntypedFormGroup): ValidationErrors | null => {
+      const startDate = fromDateISOString(group.get(startDateField).value);
+      const endField = group.get(endDateField);
+      const endDate = fromDateISOString(endField.value);
+      if (isNotNil(startDate) && isNotNil(endDate) && startDate.isAfter(endDate)) {
+        // Update end field
+        endField.markAsPending();
+        endField.setErrors({
+          ...endField.errors,
+          ...rangeError,
+        });
+        // Return the error (should be applied to the parent form, by default)
+        return fieldOnly ? null : rangeError;
+      }
+      // OK: remove the existing on the end field
+      SharedValidators.clearError(endField, errorCode);
+      return null;
+    };
+  }
+
+  static dateMaxDuration(startDateField: string, endDateField: string, maxDuration: number, durationUnit?: moment.unitOfTime.Diff): ValidatorFn {
+    const maxDurationError = { dateMaxDuration: true };
+    return (group: UntypedFormGroup): ValidationErrors | null => {
+      const startDate = fromDateISOString(group.get(startDateField).value);
+      const endField = group.get(endDateField);
+      const endDate = fromDateISOString(endField.value);
+      if (isNotNil(startDate) && isNotNil(endDate) && Math.abs(startDate.diff(endDate, durationUnit)) > maxDuration) {
+        // Update end field
+        endField.markAsTouched({ onlySelf: true });
+        endField.markAsPending();
+        endField.setErrors({
+          ...endField.errors,
+          ...maxDurationError,
+        });
+        // Return the error (should be apply to the parent form)
+        return maxDurationError;
+      }
+      // OK: remove the existing on the end field
+      SharedValidators.clearError(endField, 'dateMaxDuration');
+      return null;
+    };
+  }
+
+  static dateMinDuration(startDateField: string, endDateField: string, minDuration: number, durationUnit?: moment.unitOfTime.Diff): ValidatorFn {
+    return (group: UntypedFormGroup): ValidationErrors | null => {
+      const endField = group.get(endDateField);
+      const startDate = fromDateISOString(group.get(startDateField).value);
+      const endDate = fromDateISOString(endField.value);
+      if (isNotNil(startDate) && isNotNil(endDate) && Math.abs(startDate.diff(endDate, durationUnit)) < minDuration) {
+        // Update end field
+        const endFieldErrors: ValidationErrors = endField.errors || {};
+        endFieldErrors['dateMinDuration'] = true;
+        endField.setErrors(endFieldErrors);
+        endField.markAsTouched({ onlySelf: true });
+        // Return the error (should be apply to the parent form)
+        return { dateMinDuration: true };
+      }
+      // OK: remove the existing on the end field
+      else {
+        SharedValidators.clearError(endField, 'dateMinDuration');
+      }
+      return null;
+    };
+  }
+
+  static requiredIf(
+    fieldName: string,
+    anotherFieldToCheck: string | AbstractControl,
+    opts?: { fieldOnly?: boolean; predicate?: (control: AbstractControl) => boolean }
+  ): ValidatorFn {
+    const predicate = opts?.predicate || ((control) => isNotNilOrBlank(control.value));
+    return (group: UntypedFormGroup): ValidationErrors | null => {
+      const control = group.get(fieldName);
+      const anotherControl = anotherFieldToCheck instanceof AbstractControl ? anotherFieldToCheck : group.get(anotherFieldToCheck);
+      if (!anotherControl) throw new Error('Unable to find field to check!');
+      if (isNilOrBlank(control.value) && predicate(anotherControl)) {
+        const error = { required: true };
+        control.setErrors(error);
+        control.markAsTouched({ onlySelf: true });
+        return opts?.fieldOnly ? null : error;
+      }
+      SharedValidators.clearError(control, 'required');
+      return null;
+    };
+  }
+
+  static requiredIfTrue(fieldName: string, anotherFieldToCheck: string | AbstractControl, opts?: { fieldOnly?: boolean }): ValidatorFn {
+    return (group: UntypedFormGroup): ValidationErrors | null => {
+      const control = group.get(fieldName);
+      const anotherControl = anotherFieldToCheck instanceof AbstractControl ? anotherFieldToCheck : group.get(anotherFieldToCheck);
+      if (!anotherControl) throw new Error('Unable to find field to check!');
+      if (isNilOrBlank(control.value) && toBoolean(anotherControl.value, false)) {
+        const error = { required: true };
+        control.setErrors(error);
+        control.markAsTouched({ onlySelf: true });
+        return opts?.fieldOnly ? null : error;
+      }
+      SharedValidators.clearError(control, 'required');
+      return null;
+    };
+  }
+
+  static requiredIfEmpty(fieldName: string, anotherFieldToCheck: string, opts?: { fieldOnly?: boolean }): ValidatorFn {
+    return (group: UntypedFormGroup): ValidationErrors | null => {
+      const control = group.get(fieldName);
+      if (isNilOrBlank(control.value) && isNilOrBlank(group.get(anotherFieldToCheck).value)) {
+        const error = { required: true };
+        control.setErrors(error);
+        control.markAsTouched({ onlySelf: true });
+        return opts?.fieldOnly ? null : error;
+      }
+      SharedValidators.clearError(control, 'required');
+      return null;
+    };
+  }
+
+  static propagateIfDirty(fieldName: string, fieldNameToPropagate: string, valueToPropagate: any): ValidatorFn {
+    return (group: UntypedFormGroup): null => {
+      const control = group.get(fieldName);
+      const controlToPropagate = group.get(fieldNameToPropagate);
+      if (control.dirty && controlToPropagate.value !== valueToPropagate) {
+        controlToPropagate.setValue(valueToPropagate);
+      }
+      return null;
+    };
+  }
+
+  /**
+   * Same as compose, but keep only the first errors (instead of the union)
+   *
+   * @param validators
+   */
+  first(validators: (ValidatorFn | null | undefined)[]): ValidationErrors | null {
+    return (control) =>
+      validators
+        .filter(isNotNil)
+        .map((validator) => validator(control))
+        .find(isNotNil) || null;
+  }
+}
diff --git a/src/app/shared/functions.ts b/src/app/shared/functions.ts
index a61324f76a7dbc08940986ea3b4589a8abbb4eeb..53484d0b5d434e386efffa6f4f462b0a9a1d4f95 100644
--- a/src/app/shared/functions.ts
+++ b/src/app/shared/functions.ts
@@ -2,6 +2,7 @@ import { KeysEnum, KeyValueType } from '@app/shared/types';
 import { setTimeout } from '@rx-angular/cdk/zone-less/browser';
 import { u32, u64 } from '@polkadot/types-codec';
 import { Codec } from '@polkadot/types-codec/types';
+import { INTEGER_REGEXP, NUMBER_RANGE_REGEXP, NUMBER_REGEXP, PUBKEY_REGEXP, UID_REGEXP } from '@app/shared/constants';
 
 export function isNil<T>(obj: T | null | undefined): boolean {
   return obj === undefined || obj === null;
@@ -206,19 +207,21 @@ export function sort<T>(array: T[], attribute: string, opts?: Intl.CollatorOptio
     .slice() // copy
     .sort((a, b) => compareFn(a[attribute], b[attribute]));
 }
-const INTEGER_REGEXP = /^[-]?\d+$/;
 export function isInt(value: string): boolean {
   return isNotNil(value) && INTEGER_REGEXP.test(value);
 }
-const NUMBER_REGEXP = /^[-]?\d+(\.\d+)?$/;
 export function isNumber(value: string): boolean {
   return isNotNil(value) && NUMBER_REGEXP.test(value);
 }
-
-const NUMBER_RANGE_REGEXP = /^(\d+-\d+)|([><=]*\d+)$/;
 export function isNumberRange(value: string): boolean {
   return isNotNil(value) && NUMBER_RANGE_REGEXP.test(value);
 }
+export function isValidUid(value: string): boolean {
+  return isNotNil(value) && UID_REGEXP.test(value);
+}
+export function isValidPubkey(value: string): boolean {
+  return isNotNil(value) && PUBKEY_REGEXP.test(value);
+}
 
 // eslint-disable-next-line @typescript-eslint/no-explicit-any
 export function getPropertyByPath(obj: any, path: string, defaultValue?: any): any {
diff --git a/src/app/shared/logs.ts b/src/app/shared/logs.ts
new file mode 100644
index 0000000000000000000000000000000000000000..5a493153f12e57046fb5554d298e6c14ad31b4fe
--- /dev/null
+++ b/src/app/shared/logs.ts
@@ -0,0 +1,6 @@
+import { changeCaseToUnderscore } from '@app/shared/functions';
+import { Constructor } from '@app/shared/types';
+
+export function logPrefix<T extends Constructor | Function>(constructor: T, options?: { name?: string }) {
+  return `[${options?.name || changeCaseToUnderscore(constructor.name).replace(/_/g, '-')}] `;
+}
diff --git a/src/app/shared/pages/base-page.class.ts b/src/app/shared/pages/base-page.class.ts
index 2ce90a80ecdd6d9980feff161a85ec7411d5e5e3..04a0696164750d178a22d705f3b12803babf4803 100644
--- a/src/app/shared/pages/base-page.class.ts
+++ b/src/app/shared/pages/base-page.class.ts
@@ -12,6 +12,8 @@ import { RxStateProperty, RxStateRegister, RxStateSelect } from '@app/shared/dec
 import { FormGroup } from '@angular/forms';
 import { ContextService } from '@app/shared/services/storage/context.service';
 import { AppError } from '@app/shared/types';
+import { logPrefix } from '@app/shared/logs';
+import { setTimeout } from '@rx-angular/cdk/zone-less/browser';
 
 export interface AppPageState {
   error: string;
@@ -98,12 +100,12 @@ export abstract class AppPage<S extends AppPageState = AppPageState, O extends A
     if (form) this.setForm(form);
 
     // Init state
-    if (this._options?.initialState && this._state) {
+    if (this._state && this._options?.initialState) {
       this._state.set(this._options.initialState);
     }
 
-    // DEV
-    this._logPrefix = `[${this._options.name}] `;
+    // Log
+    this._logPrefix = logPrefix(this.constructor, this._options);
   }
 
   ngOnInit() {
@@ -163,9 +165,14 @@ export abstract class AppPage<S extends AppPageState = AppPageState, O extends A
     return Promise.resolve(initialState);
   }
 
-  protected setError(err: string | { message: string }, opts = { emitEvent: true }) {
-    this.error = (typeof err === 'object' ? err.message : err) || 'ERROR.UNKNOWN_ERROR';
+  protected setError(err: string | { message: string }, opts = { emitEvent: true, hideDelay: 4000 }) {
+    const error = (typeof err === 'object' ? err.message : err) || 'ERROR.UNKNOWN_ERROR';
+    this.error = error;
     if (opts.emitEvent !== false) this.markForCheck();
+
+    setTimeout(() => {
+      if (this.error === error) this.resetError();
+    }, opts.hideDelay);
   }
 
   protected resetError(opts = { emitEvent: true }) {
@@ -228,6 +235,7 @@ export abstract class AppPage<S extends AppPageState = AppPageState, O extends A
       type: 'error',
       icon: 'alert',
       swipeGesture: 'vertical',
+      duration: 5000, // 5s (longer)
       ...opts,
     });
   }
diff --git a/src/app/shared/pipes/form.pipes.ts b/src/app/shared/pipes/form.pipes.ts
index 8fa4087a351a4def1d254d2d219ffaf178e13119..ed6ee4314570daa2a66a021e8dd77e41d0c25f97 100644
--- a/src/app/shared/pipes/form.pipes.ts
+++ b/src/app/shared/pipes/form.pipes.ts
@@ -1,7 +1,86 @@
 import { ChangeDetectorRef, OnDestroy, Pipe, PipeTransform } from '@angular/core';
-import { AbstractControl, FormArray, FormControl, FormGroup } from '@angular/forms';
+import { AbstractControl, FormArray, FormControl, FormControlStatus, FormGroup } from '@angular/forms';
 import { Subscription } from 'rxjs';
-import { equals } from '../functions';
+import { equals, isNotNil } from '../functions';
+import { FormErrorTranslator, FormErrorTranslatorOptions } from '@app/shared/form/form-error-translator.service';
+
+@Pipe({
+  name: 'formError',
+  pure: false,
+})
+export class FormErrorPipe implements PipeTransform, OnDestroy {
+  private _value = '';
+
+  private _lastForm: AbstractControl | null = null;
+  private _lastOptions: FormErrorTranslatorOptions | null = null;
+  private _onFormStatusChanges: Subscription | undefined;
+
+  constructor(
+    private service: FormErrorTranslator,
+    private _ref: ChangeDetectorRef
+  ) {}
+
+  transform(form: AbstractControl, opts?: FormErrorTranslatorOptions): string {
+    if (!form) {
+      this._dispose();
+      return '';
+    }
+
+    // if we ask another time for the same form and opts, return the last value
+    if (form === this._lastForm && equals(opts, this._lastOptions)) {
+      return this._value;
+    }
+
+    // store the query, in case it changes
+    this._lastForm = form;
+
+    // store the params, in case they change
+    this._lastOptions = opts;
+
+    // set the value
+    this._updateValue(form, opts);
+
+    // if there is a subscription to onLangChange, clean it
+    this._dispose();
+
+    // subscribe to onTranslationChange event, in case the translations change
+    if (!this._onFormStatusChanges) {
+      this._onFormStatusChanges = form.statusChanges.subscribe((status) => {
+        this._updateValue(form, opts, status);
+      });
+    }
+
+    return this._value;
+  }
+
+  ngOnDestroy(): void {
+    this._dispose();
+  }
+
+  private _updateValue(form: AbstractControl, opts?: FormErrorTranslatorOptions, status?: FormControlStatus) {
+    // Form is invalid: compute error
+    if (status ? status === 'INVALID' : form.invalid) {
+      const newValue = this.service.translateFormErrors(form, opts);
+      if (newValue !== this._value) {
+        this._value = newValue;
+        this._ref.markForCheck();
+      }
+    }
+    // For is valid (or pending): clean if need
+    else if (this._value !== undefined) {
+      this._value = undefined;
+      this._ref.markForCheck();
+    }
+  }
+
+  /**
+   * Clean any existing subscription to change events
+   */
+  private _dispose(): void {
+    this._onFormStatusChanges?.unsubscribe();
+    this._onFormStatusChanges = undefined;
+  }
+}
 
 @Pipe({
   name: 'formGet',
@@ -25,8 +104,9 @@ export class FormGetControlPipe implements PipeTransform {
   name: 'formGetArray',
 })
 export class FormGetArrayPipe implements PipeTransform {
-  transform(form: AbstractControl, path?: Array<string | number> | string): FormArray {
-    return ((form && path && form.get(path)) || form) as FormArray;
+  // eslint-disable-next-line @typescript-eslint/no-explicit-any
+  transform<TControl extends AbstractControl<any> = any>(form: AbstractControl, path?: Array<string | number> | string): FormArray<TControl> {
+    return (form && isNotNil(path) ? form.get(path) : form) as FormArray<TControl>;
   }
 }
 
@@ -34,8 +114,12 @@ export class FormGetArrayPipe implements PipeTransform {
   name: 'formGetGroup',
 })
 export class FormGetGroupPipe implements PipeTransform {
-  transform(form: AbstractControl, path?: Array<string | number> | string): FormGroup {
-    return ((form && path && form.get(path)) || form) as FormGroup;
+  // eslint-disable-next-line @typescript-eslint/no-explicit-any
+  transform<TControl extends { [K in keyof TControl]: AbstractControl<any> } = any>(
+    form: AbstractControl,
+    path?: Array<string | number> | string
+  ): FormGroup<TControl> {
+    return (form && isNotNil(path) ? form.get(path) : form) as FormGroup<TControl>;
   }
 }
 
@@ -45,8 +129,7 @@ export class FormGetGroupPipe implements PipeTransform {
 })
 export class FormGetValuePipe implements PipeTransform, OnDestroy {
   // eslint-disable-next-line @typescript-eslint/no-explicit-any
-  value: any = undefined;
-
+  private _value: any = undefined;
   private _lastControl: AbstractControl | null = null;
   private _lastPath: Array<string | number> | string;
   private _onControlValueChanges: Subscription | undefined;
@@ -62,7 +145,7 @@ export class FormGetValuePipe implements PipeTransform, OnDestroy {
 
     // if we ask another time for the same form and opts, return the last value
     if (form === this._lastControl && equals(path, this._lastPath)) {
-      return this.value;
+      return this._value;
     }
 
     // store the query, in case it changes
@@ -73,16 +156,16 @@ export class FormGetValuePipe implements PipeTransform, OnDestroy {
 
     // set the value
     const control = path ? form.get(path) : form;
-    this.value = control?.value;
+    this._value = control?.value;
 
-    // if there is a subscription to onLangChange, clean it
+    // if there is already a subscription, clean it
     this._dispose();
 
     if (control) {
       // subscribe to valueChanges event
       this._onControlValueChanges = control.valueChanges.subscribe((value) => {
-        if (value !== this.value) {
-          this.value = value;
+        if (value !== this._value) {
+          this._value = value;
           this._ref.markForCheck();
         }
       });
@@ -91,15 +174,15 @@ export class FormGetValuePipe implements PipeTransform, OnDestroy {
       if (listenStatusChanges) {
         this._onControlStatusChanges = control.statusChanges.subscribe(() => {
           const value = control.value;
-          if (value !== this.value) {
-            this.value = value;
+          if (value !== this._value) {
+            this._value = value;
             this._ref.markForCheck();
           }
         });
       }
     }
 
-    return this.value;
+    return this._value;
   }
 
   ngOnDestroy(): void {
diff --git a/src/app/shared/pipes/pipes.module.ts b/src/app/shared/pipes/pipes.module.ts
index 2ada7bbd893e2a6e4487edb17d50f9c6d79b0994..b0affc4c58070536c9dc97c659394b4dd1bd1f04 100644
--- a/src/app/shared/pipes/pipes.module.ts
+++ b/src/app/shared/pipes/pipes.module.ts
@@ -2,7 +2,7 @@ import { NgModule } from '@angular/core';
 import { CommonModule } from '@angular/common';
 import { TranslateModule } from '@ngx-translate/core';
 import { IonicModule } from '@ionic/angular';
-import { BlockTimePipe, BlocksToDurationPipe } from './block-timestamp.pipe';
+import { BlocksToDurationPipe, BlockTimePipe } from './block-timestamp.pipe';
 import { DateFormatPipe } from './date-format.pipe';
 import { DateDiffDurationPipe } from './date-diff-duration.pipe';
 import { DateFromNowPipe } from './date-from-now.pipe';
@@ -32,7 +32,7 @@ import {
   TranslatablePipe,
 } from './string.pipes';
 import { NgInitDirective } from './ng-init.pipe';
-import { FormGetArrayPipe, FormGetControlPipe, FormGetGroupPipe, FormGetPipe, FormGetValuePipe } from './form.pipes';
+import { FormErrorPipe, FormGetArrayPipe, FormGetControlPipe, FormGetGroupPipe, FormGetPipe, FormGetValuePipe } from './form.pipes';
 import { PropertyGetPipe } from './property.pipes';
 import { AmountFormatPipe } from '@app/shared/pipes/amount.pipe';
 import { AddressFormatPipe, AddressToPubkeyPipePipe } from '@app/shared/pipes/address.pipes';
@@ -84,6 +84,7 @@ import { BlockNumberPipe } from '@app/shared/pipes/block-number.pipe';
     FormGetArrayPipe,
     FormGetGroupPipe,
     FormGetValuePipe,
+    FormErrorPipe,
     // Block
     BlockTimePipe,
     BlockNumberPipe,
@@ -138,6 +139,7 @@ import { BlockNumberPipe } from '@app/shared/pipes/block-number.pipe';
     FormGetArrayPipe,
     FormGetGroupPipe,
     FormGetValuePipe,
+    FormErrorPipe,
 
     // Block
     BlockTimePipe,
diff --git a/src/app/shared/services/rx-service.class.ts b/src/app/shared/services/rx-service.class.ts
index 79eddf324a156e2e523dcf61342c0857203f76f4..2b9e7f2f7751c79751c3be6cfaf6c56bfeb369eb 100644
--- a/src/app/shared/services/rx-service.class.ts
+++ b/src/app/shared/services/rx-service.class.ts
@@ -2,6 +2,7 @@ import { Subscription } from 'rxjs';
 import { environment } from '@environments/environment';
 import { Directive, OnDestroy } from '@angular/core';
 import { RxState } from '@rx-angular/state';
+import { logPrefix } from '@app/shared/logs';
 
 export interface RxBaseServiceOptions<T extends object> {
   name?: string;
@@ -15,8 +16,8 @@ export abstract class RxBaseService<T extends object = Object, O extends RxBaseS
 {
   private _subscription: Subscription = null;
 
-  protected readonly _debug: boolean;
-  protected readonly _logPrefix: string = null;
+  protected readonly _debug = !environment.production;
+  protected readonly _logPrefix: string;
 
   get data(): T {
     return this.get();
@@ -25,12 +26,13 @@ export abstract class RxBaseService<T extends object = Object, O extends RxBaseS
   protected constructor(protected options?: O) {
     super();
 
+    // Init state
     if (options?.initialState) {
       this.set(options.initialState);
     }
 
-    this._debug = !environment.production;
-    this._logPrefix = `[${options?.name || 'base-service'}] `;
+    // Log
+    this._logPrefix = logPrefix(this.constructor, options);
   }
 
   ngOnDestroy() {
diff --git a/src/app/shared/services/service.class.ts b/src/app/shared/services/service.class.ts
index f9e10bf208723404ca84d7def366ef06c70c32d2..e86e83fd51d6311666669b826a7c75f787cf3fb2 100644
--- a/src/app/shared/services/service.class.ts
+++ b/src/app/shared/services/service.class.ts
@@ -1,6 +1,7 @@
 import { Subscription } from 'rxjs';
 import { environment } from '@environments/environment';
 import { Directive, OnDestroy } from '@angular/core';
+import { logPrefix } from '@app/shared/logs';
 
 export interface BaseServiceOptions {
   name?: string;
@@ -10,12 +11,12 @@ export interface BaseServiceOptions {
 export abstract class BaseService<O extends BaseServiceOptions = BaseServiceOptions> implements OnDestroy {
   private _subscription: Subscription = null;
 
-  protected readonly _debug: boolean;
-  protected readonly _logPrefix: string = null;
+  protected readonly _debug = !environment.production;
+  protected readonly _logPrefix: string;
 
   protected constructor(protected options?: O) {
-    this._debug = !environment.production;
-    this._logPrefix = `[${options?.name || 'base-service'}] `;
+    // Log
+    this._logPrefix = logPrefix(this.constructor, options);
   }
 
   ngOnDestroy() {
diff --git a/src/app/shared/types.ts b/src/app/shared/types.ts
index 68d5d069bbc75a401037e562f54f3e81892ceb8d..2b57f2e732c148073f720050cc6caa0f7fd193f3 100644
--- a/src/app/shared/types.ts
+++ b/src/app/shared/types.ts
@@ -47,3 +47,6 @@ export interface ListItems<T, F> {
   fetchMoreFn: FetchMoreFn<LoadResult<T>>;
   fetchSize: number;
 }
+
+// eslint-disable-next-line @typescript-eslint/no-explicit-any
+export declare type Constructor<T = any> = new (...args: any[]) => T;
diff --git a/src/app/transfer/send/transfer.page.html b/src/app/transfer/send/transfer.page.html
index 157411553c43a38ec4e363d0a979adc890d69b19..6cf58fa7318f6000b7d3ed4979824ab4b25024d3 100644
--- a/src/app/transfer/send/transfer.page.html
+++ b/src/app/transfer/send/transfer.page.html
@@ -121,7 +121,7 @@
 
   <ion-button (click)="doSubmit()" [disabled]="loading || invalid" color="tertiary">
     <ion-icon slot="start" name="paper-plane"></ion-icon>
-    <ion-label translate>TRANSFER.BTN_SEND</ion-label>
+    <ion-label translate>COMMON.BTN_SEND</ion-label>
   </ion-button>
 </ng-template>
 
diff --git a/src/app/wot/wot-details.page.html b/src/app/wot/wot-details.page.html
index cd7b8a9ce2265f0ae78bd48e0afa0c5c0f0b72c6..1e20f914a19686a82666bf333350c35769494a1a 100644
--- a/src/app/wot/wot-details.page.html
+++ b/src/app/wot/wot-details.page.html
@@ -91,12 +91,24 @@
       @if (account.meta?.index) {
         <ion-item>
           <ion-icon aria-hidden="true" slot="start" name="calendar-clear-outline"></ion-icon>
-          <ion-label>
-            <h3 translate>COMMON.UID</h3>
-            <p>{{ 'WOT.REGISTERED_SINCE' | translate }}</p>
-          </ion-label>
-
-          <ion-badge color="warning" slot="end">{{ account.meta?.uid }}</ion-badge>
+          <!-- special case for unconfirmed (UID is not known yet)-->
+          @if (account.meta.status === IdentityStatusEnum.Unconfirmed) {
+            <ion-label color="danger" [innerHTML]="'WOT.IDENTITY_UNCONFIRMED' | translate"></ion-label>
+          } @else {
+            <ion-label>
+              <h3 translate>COMMON.UID</h3>
+              <p>{{ 'WOT.REGISTERED_SINCE' | translate }}</p>
+            </ion-label>
+
+            <ion-buttons slot="end" class="vertical-alignment">
+              <ion-badge [color]="account.meta.isMember ? 'warning' : 'medium'">
+                {{ account.meta?.uid }}
+              </ion-badge>
+              @if (!account.meta.isMember) {
+                <ion-note color="danger">({{ 'WOT.STATUS_ENUM.' + account.meta.status | translate }})</ion-note>
+              }
+            </ion-buttons>
+          }
         </ion-item>
 
         <!-- Received cert count -->
diff --git a/src/app/wot/wot-details.page.ts b/src/app/wot/wot-details.page.ts
index 5dd7ec3b281c3939f073dd1aa15f8b6c2d080bcc..f70530e9faa37520aa14486be5b55e59ff8fdd5f 100644
--- a/src/app/wot/wot-details.page.ts
+++ b/src/app/wot/wot-details.page.ts
@@ -12,6 +12,7 @@ import { filter, map } from 'rxjs/operators';
 import { firstArrayValue, isNotNilOrBlank } from '@app/shared/functions';
 import { IndexerService } from '@app/network/indexer/indexer.service';
 import { address2PubkeyV1, pubkeyV1Checksum } from '@app/shared/currencies';
+import { IdentityStatusEnum } from '@app/network/indexer/indexer-types.generated';
 
 export interface WotDetailsPageState extends AppPageState {
   address: string;
@@ -155,4 +156,6 @@ export class WotDetailsPage extends AppPage<WotDetailsPageState> implements OnIn
       this.markAsLoaded();
     }
   }
+
+  protected readonly IdentityStatusEnum = IdentityStatusEnum;
 }
diff --git a/src/app/wot/wot-lookup.page.html b/src/app/wot/wot-lookup.page.html
index 68df96ce6a3f822281805046b1a6f42f86da3d93..d8e720da1566adba292cee1f13b2330b585e1071 100644
--- a/src/app/wot/wot-lookup.page.html
+++ b/src/app/wot/wot-lookup.page.html
@@ -141,7 +141,9 @@
                 </ion-text>
                 <!-- not member -->
                 @if (!item.meta?.isMember) {
-                  <ion-text color="danger" translate>WOT.NOT_MEMBER_PARENTHESIS</ion-text>
+                  <ion-text color="danger">
+                    ({{ (item.meta?.status ? 'WOT.STATUS_ENUM.' + item.meta.status : 'WOT.NOT_MEMBER_PARENTHESIS') | translate }})
+                  </ion-text>
                 }
               </p>
             </ion-label>
diff --git a/src/app/wot/wot.model.ts b/src/app/wot/wot.model.ts
index 2e1b5ebf5c364960ff3d8959b80e46654f8f6967..e0df8c99947fad1489b7bff2cba1154cf109b05b 100644
--- a/src/app/wot/wot.model.ts
+++ b/src/app/wot/wot.model.ts
@@ -1,5 +1,7 @@
 import { equals, isNil, isNilOrBlank } from '@app/shared/functions';
 import { PredefinedColors } from '@app/shared/colors/colors.utils';
+import { InjectionToken } from '@angular/core';
+import { WotController } from './wot.controller';
 
 export interface WotLookupOptions {
   debounceTime?: number;
@@ -18,6 +20,7 @@ export interface WotSearchFilter {
   searchText?: string;
   last?: boolean;
   pending?: boolean;
+  uid?: string;
 }
 
 export class WotSearchFilterUtils {
@@ -29,3 +32,5 @@ export class WotSearchFilterUtils {
     return !filter || (isNilOrBlank(filter.searchText) && isNil(filter.last) && isNilOrBlank(filter.address));
   }
 }
+
+export const APP_WOT_CONTROLLER = new InjectionToken<WotController>('WotController');
diff --git a/src/app/wot/wot.module.ts b/src/app/wot/wot.module.ts
index a1792678bebd4401b309496dc525b92700a46c20..14598f32c308a0ea668c6ad3366c036e564cea16 100644
--- a/src/app/wot/wot.module.ts
+++ b/src/app/wot/wot.module.ts
@@ -1,4 +1,4 @@
-import { NgModule } from '@angular/core';
+import { ModuleWithProviders, NgModule } from '@angular/core';
 
 import { WotLookupPage } from './wot-lookup.page';
 import { AppSharedModule } from '@app/shared/shared.module';
@@ -6,6 +6,8 @@ import { TranslateModule } from '@ngx-translate/core';
 import { WotDetailsPage } from '@app/wot/wot-details.page';
 import { AppTransferModule } from '@app/transfer/send/transfer.module';
 import { AppAccountModule } from '@app/account/account.module';
+import { WotController } from './wot.controller';
+import { APP_WOT_CONTROLLER } from './wot.model';
 
 @NgModule({
   imports: [AppSharedModule, TranslateModule.forChild(), AppTransferModule, AppAccountModule],
@@ -13,7 +15,11 @@ import { AppAccountModule } from '@app/account/account.module';
   exports: [WotLookupPage, WotDetailsPage],
 })
 export class AppWotModule {
-  constructor() {
+  static forRoot(): ModuleWithProviders<AppTransferModule> {
     console.debug('[wot] Creating module');
+    return {
+      ngModule: AppWotModule,
+      providers: [WotController, { provide: APP_WOT_CONTROLLER, useExisting: WotController }],
+    };
   }
 }
diff --git a/src/assets/i18n/en.json b/src/assets/i18n/en.json
index a484450d94fd753e925cef630101b9a1607aa4c2..fcdf4511ce70cc6d7e73ffb1442846fb91506df6 100644
--- a/src/assets/i18n/en.json
+++ b/src/assets/i18n/en.json
@@ -356,6 +356,7 @@
     "NO_CERTIFICATION": "No validated certification",
     "NO_GIVEN_CERTIFICATION": "No given certification",
     "NOT_MEMBER_PARENTHESIS": "(non-member)",
+    "IDENTITY_UNCONFIRMED": "Identity <b>not confirmed</b> (non membre)",
     "IDENTITY_REVOKED_PARENTHESIS": "(identity revoked)",
     "MEMBER_PENDING_REVOCATION_PARENTHESIS": "(being revoked)",
     "EXPIRE_IN": "Expires",
@@ -417,6 +418,14 @@
       "SENT": "Sent certifications",
       "SENT_BY": "Certifications sent by {{uid}}",
       "ERROR": "Sent certifications with error"
+    },
+    "STATUS_ENUM": {
+      "MEMBER": "Member",
+      "NOTMEMBER": "Not member",
+      "REMOVED": "Not member",
+      "REVOKED": "Revoked identity",
+      "UNCONFIRMED": "Unconfirmed identity",
+      "UNVALIDATED": "Waiting validation"
     }
   },
   "LOGIN": {
@@ -431,6 +440,7 @@
     "PASSWORD": "Password",
     "PASSWORD_HELP": "Password",
     "PUBKEY_HELP": "Public key or pseudonym",
+    "MNEMONIC": "Mnemonic phrase",
     "NO_ACCOUNT_QUESTION": "Don't have an account yet?",
     "HAVE_ACCOUNT_QUESTION": "Already have an account ?",
     "CREATE_ACCOUNT": "Create an account",
@@ -453,7 +463,9 @@
       "SCRYPT_ADVANCED": "Advanced salt",
       "FILE": "Keychain file",
       "PUBKEY": "Public key or pseudonym",
-      "SCAN": "Scan a QR code"
+      "ADDRESS": "SS58 Address",
+      "SCAN": "Scan a QR code",
+      "MNEMONIC": "Mnemonic phrase"
     },
     "SCRYPT": {
       "SIMPLE": "Light salt",
@@ -505,6 +517,7 @@
     "CERTIFICATION_COUNT": "Received certifications",
     "CERTIFICATION_COUNT_SHORT": "Certifications",
     "SIG_STOCK": "Stock of certifications to give",
+    "BTN_CONFIRM_MEMBERSHIP": "Confirm membership",
     "BTN_RECEIVE_MONEY": "Receive",
     "BTN_SELECT_ALTERNATIVES_IDENTITIES": "Switch to another identity...",
     "BTN_FIX_MEMBERSHIP": "Resubmit membership request...",
@@ -569,6 +582,7 @@
     "WALLET_LIST": {
       "TITLE": "My wallets",
       "BTN_NEW": "Add a wallet",
+      "BTN_NEW_DOTS": "Add a wallet...",
       "BTN_DOWNLOAD": "Download the list",
       "BTN_IMPORT_FILE_DOTS": "Import from a file...",
       "NO_WALLET": "No secondary wallet",
@@ -672,11 +686,15 @@
     "AMOUNT_HELP": "Amount",
     "COMMENT": "Comment",
     "COMMENT_HELP": "Comment (optional)",
+    "FEE": "+{{fee}} {{currency}} fees",
     "BTN_SEND": "Send",
     "BTN_ADD_COMMENT": "Add a comment",
     "REST": "Rest of account",
     "REST_TO": "to",
     "WARN_COMMENT_IS_PUBLIC": "Please note that <b>comments are public</b> (not encrypted).",
+    "BTN_SCAN_HELP": "Scan a QR Code",
+    "BTN_QR_CODE": "QR Code",
+    "QR_CODE_HELP": "Ask the recipient to flash this code. They can then deposit the payment later, whenever they want.",
     "MODAL": {
       "TITLE": "Transfer"
     }
@@ -731,6 +749,7 @@
     "NEED_LOGIN_FIRST": "Please sign in first.",
     "AMOUNT_REQUIRED": "Amount is required.",
     "AMOUNT_NEGATIVE": "Negative amount not allowed.",
+    "FEE_NEGATIVE": "Negative fee not allowed..",
     "NOT_ENOUGH_CREDIT": "Not enough credit.",
     "INVALID_NODE_SUMMARY": "Unreachable peer or invalid address",
     "INVALID_USER_ID": "Field 'pseudonym' must not contains spaces or special characters.",
@@ -792,6 +811,7 @@
   },
   "INFO": {
     "POPUP_TITLE": "Information",
+    "CERTIFICATION_PENDING": "Certification sent. Waiting for validation...",
     "CERTIFICATION_DONE": "Identity successfully signed",
     "NOT_ENOUGH_CREDIT": "Not enough credit",
     "TRANSFER_SENT": "Transfer request successfully sent",
@@ -929,98 +949,5 @@
       "END_NOT_LOGIN": "This guided visit has <b>ended</b>.<br/><br/>If you wish to join the currency {{currency|capitalize}}, simply click <b>{{'LOGIN.CREATE_FREE_ACCOUNT'|translate}}</b> below.",
       "END_READONLY": "This guided visit has <b>ended</b>.<br/><br/>{{'MODE.READONLY.INSTALL_HELP'|translate}}."
     }
-  },
-  "API": {
-    "COMMON": {
-      "LINK_DOC": "API documentation",
-      "LINK_DOC_HELP": "API documentation for developers",
-      "LINK_STANDARD_APP": "Standard version",
-      "LINK_STANDARD_APP_HELP": "Open standard version of {{'COMMON.APP_NAME'|translate}}",
-      "CONNECTION_ERROR": "Peer <b>{{server}}</b> unreachable or invalid address.<br/><br/>Check your Internet connection, or contact the web site administrator."
-    },
-    "HOME": {
-      "TITLE": "{{'COMMON.APP_NAME'|translate}} API Documentation",
-      "MESSAGE": "Welcome to the {{'COMMON.APP_NAME'|translate}} <b>API documentation </b>.<br/>Connect your web site to <a href=\"http://duniter.org\" target=\"_system\">Duniter</a> very easily!",
-      "MESSAGE_SHORT": "Connect your websites to <a href=\"http://duniter.org\" target=\"_system\">Duniter</a> very easily!",
-      "DOC_HEADER": "Available services:"
-    },
-    "TRANSFER": {
-      "TITLE": "{{'COMMON.APP_NAME'|translate}} - Online payment",
-      "TITLE_SHORT": "Online payment",
-      "SUMMARY": "Order summary:",
-      "AMOUNT": "Amount:",
-      "AMOUNTS_HELP": "Please select the amount:",
-      "NAME": "Name:",
-      "PUBKEY": "Public key of the recipient:",
-      "COMMENT": "Order reference:",
-      "NODE": "Peer address:",
-      "DEMO": {
-        "SALT": "demo",
-        "PASSWORD": "demo",
-        "PUBKEY": "3G28bL6deXQBYpPBpLFuECo46d3kfYMJwst7uhdVBnD1",
-        "HELP": "<b>Demonstration mode</b>: No payment will actually be sent during this simulation.<br/>Please use credentials: <b>{{'API.TRANSFER.DEMO.SALT'|translate}} / {{'API.TRANSFER.DEMO.PASSWORD'|translate}}</b>",
-        "BAD_CREDENTIALS": "Invalid credentials.<br/>In demonstration mode, credentials should be: {{'API.TRANSFER.DEMO.SALT'|translate}} / {{'API.TRANSFER.DEMO.PASSWORD'|translate}}"
-      },
-      "INFO": {
-        "SUCCESS_REDIRECTING_WITH_NAME": "Payment sent.<br/>Redirect to <b>{{name}}</b>...",
-        "SUCCESS_REDIRECTING": "Payment sent.<br/>Redirect to the seller's website...",
-        "CANCEL_REDIRECTING_WITH_NAME": "Payment cancelled.<br/>Redirect to <b>{{name}}</b>...",
-        "CANCEL_REDIRECTING": "Payment cancelled.<br/>Redirect to the seller's website..."
-      },
-      "ERROR": {
-        "TRANSFER_FAILED": "Payment failed"
-      }
-    },
-    "DOC": {
-      "DESCRIPTION_DIVIDER": "Description",
-      "URL_DIVIDER": "Calling address",
-      "PARAMETERS_DIVIDER": "Parameters",
-      "AVAILABLE_PARAMETERS": "Here is the list of al available parameters:",
-      "DEMO_DIVIDER": "Try it !",
-      "DEMO_HELP": "To test this service, click on this button. The result content will be display below.",
-      "DEMO_RESULT": "Result returned by call:",
-      "DEMO_RESULT_PEER": "Peer address used:",
-      "DEMO_SUCCEED": "<i class=\"icon ion-checkmark\"></i> Success!",
-      "DEMO_CANCELLED": "<i class=\"icon ion-close\"></i> Canceled by user",
-      "INTEGRATE_DIVIDER": "Website integration",
-      "INTEGRATE_CODE": "Code:",
-      "INTEGRATE_RESULT": "Result preview:",
-      "INTEGRATE_PARAMETERS": "Parameters",
-      "TRANSFER": {
-        "TITLE": "Payments",
-        "DESCRIPTION": "From a site (eg online marketplace) you can delegate payment in free currency to Cesium API. To do this, simply open a page at the following address:",
-        "PARAM_PUBKEY": "Recipient's public key",
-        "PARAM_PUBKEY_HELP": "Recipient's public key (required)",
-        "PARAM_AMOUNT": "Amount",
-        "PARAM_AMOUNT_HELP": "Transaction amount (required)",
-        "PARAM_COMMENT": "Reference (or comment)",
-        "PARAM_COMMENT_HELP": "Reference or comment. You will allow for example to identify the payment in the BlockChain.",
-        "PARAM_NAME": "Name (of recipient or website)",
-        "PARAM_NAME_HELP": "The name of your website. This can be a readable name (eg \"My online site\"), or a web address (eg \"www.MySite.com\").",
-        "PARAM_REDIRECT_URL": "URL redirection",
-        "PARAM_REDIRECT_URL_HELP": "URL redirection after sending payment, after the payment has been sent. Can contain the following strings, which will be replaced by the values of the transaction: \"{tx}\", \"{hash}\", \"{comment}\", \"{amount}\" and \"{pubkey}\".",
-        "PARAM_CANCEL_URL": "URL if cancelled",
-        "PARAM_CANCEL_URL_HELP": "URL in case of cancellation.  Can contain the following strings, which will be replaced: \"{comment}\", \"{amount}\" and \"{pubkey}\".",
-        "PARAM_PREFERRED_NODE": "Preferred Duniter peer",
-        "PARAM_PREFERRED_NODE_HELP": "Peer address (URL) to use preferably (\"g1.domain.com:443\" or \"https://g1.domain.com\")",
-        "EXAMPLES_HELP": "Examples of integration:",
-        "EXAMPLE_BUTTON": "HTML Button",
-        "EXAMPLE_BUTTON_DEFAULT_TEXT": "Pay in {{currency}}",
-        "EXAMPLE_BUTTON_DEFAULT_STYLE": "Custom style",
-        "EXAMPLE_BUTTON_TEXT_HELP": "Button text",
-        "EXAMPLE_BUTTON_BG_COLOR": "Background color",
-        "EXAMPLE_BUTTON_BG_COLOR_HELP": "eg: #fbc14c, yellow, lightgrey, rgb(180,180,180)",
-        "EXAMPLE_BUTTON_FONT_COLOR": "Font color",
-        "EXAMPLE_BUTTON_FONT_COLOR_HELP": "eg: black, orange, rgb(180,180,180)",
-        "EXAMPLE_BUTTON_TEXT_ICON": "Icon",
-        "EXAMPLE_BUTTON_TEXT_WIDTH": "Width",
-        "EXAMPLE_BUTTON_TEXT_WIDTH_HELP": "eg: 200px, 50%",
-        "EXAMPLE_BUTTON_ICON_NONE": "No icon",
-        "EXAMPLE_BUTTON_ICON_DUNITER": "Duniter logo",
-        "EXAMPLE_BUTTON_ICON_CESIUM": "Cesium logo",
-        "EXAMPLE_BUTTON_ICON_G1_COLOR": "Ğ1 logo",
-        "EXAMPLE_BUTTON_ICON_G1_BLACK": "Ğ1 logo (outline)"
-      }
-    }
   }
 }
diff --git a/src/assets/i18n/fr.json b/src/assets/i18n/fr.json
index 7a405c784ab26dc9d48e3be544ffba33b3fe1247..47d6ba2030a10f06161f6ce8f877faf26bb1e4a5 100644
--- a/src/assets/i18n/fr.json
+++ b/src/assets/i18n/fr.json
@@ -38,6 +38,7 @@
     "BTN_START": "Commencer",
     "BTN_CONTINUE": "Continuer",
     "BTN_CREATE": "Créer",
+    "BTN_CONFIRM": "Confirmer",
     "BTN_UNDERSTOOD": "J'ai compris",
     "BTN_OPTIONS": "Options",
     "BTN_HELP_TOUR": "Visite guidée",
@@ -363,6 +364,7 @@
     "NO_CERTIFICATION": "Aucune certification validée",
     "NO_GIVEN_CERTIFICATION": "Aucune certification émise",
     "NOT_MEMBER_PARENTHESIS": "(non membre)",
+    "IDENTITY_UNCONFIRMED": "Demande d'adhésion <b>non confirmée</b>",
     "IDENTITY_REVOKED_PARENTHESIS": "(identité révoquée)",
     "MEMBER_PENDING_REVOCATION_PARENTHESIS": "(en cours de révocation)",
     "EXPIRE_IN": "Expiration",
@@ -424,6 +426,14 @@
       "SENT": "Certifications émises",
       "SENT_BY": "Certifications émises par {{uid}}",
       "ERROR": "Certifications émises en erreur"
+    },
+    "STATUS_ENUM": {
+      "MEMBER": "Membre",
+      "NOTMEMBER": "Non membre",
+      "REMOVED": "Non membre",
+      "REVOKED": "Identité révoquée",
+      "UNCONFIRMED": "Non confirmé",
+      "UNVALIDATED": "En attente de validation"
     }
   },
   "LOGIN": {
@@ -518,6 +528,7 @@
     "CERTIFICATION_COUNT": "Certifications reçues",
     "CERTIFICATION_COUNT_SHORT": "Certifications",
     "SIG_STOCK": "Certifications envoyées",
+    "BTN_CONFIRM_MEMBERSHIP": "Confirmer mon adhésion",
     "BTN_RECEIVE_MONEY": "Encaisser",
     "BTN_SELECT_ALTERNATIVES_IDENTITIES": "Basculer vers une autre identité...",
     "BTN_FIX_MEMBERSHIP": "Renvoyer la demande d'adhésion...",
@@ -573,9 +584,9 @@
       "INPUT_WORD": "Mot n°{{number}}",
       "YOUR_SECRET_CODE": "Votre code secret"
     },
-    "POPUP_REGISTER": {
-      "TITLE": "Choisissez un pseudonyme",
-      "HELP": "Un pseudonyme est obligatoire pour devenir membre."
+    "CONFIRM_IDENTITY": {
+      "TITLE": "Confirmer mon adhésion",
+      "PSEUDO_HELP": "Choisissez un pseudonyme.<br/>Il sert aux autres membres, pour vous identifier plus facilement.<div class='hidden-xs'><br/>Il <b>ne pourra pas être modifié</b>, sans refaire un compte.</div><br/><br/>Il ne doit contenir <b>ni espace, ni de caractère accentué</b>.<div class='hidden-xs'><br/>Exemple : <span class='gray'>SophieDupond, MarcelChemin, etc.</span>"
     },
     "SELECT_IDENTITY_MODAL": {
       "TITLE": "Sélection de l'identité",
@@ -692,7 +703,6 @@
     "COMMENT": "Commentaire",
     "COMMENT_HELP": "Commentaire",
     "FEE": "+{{fee}} {{currency}} frais",
-    "BTN_SEND": "Envoyer",
     "BTN_ADD_COMMENT": "Ajouter un commentaire",
     "REST": "Reste du compte",
     "REST_TO": "à",
@@ -722,8 +732,23 @@
     "FIELD_MAX": "Valeur maximale : {{max}}",
     "FIELD_ACCENT": "Caractères accentués et virgules non autorisés",
     "FIELD_NOT_NUMBER": "Valeur numérique attendue",
+    "FIELD_MAXIMUM_DECIMALS": "Trop de décimales (max : {{maxDecimals}})",
+    "FIELD_NOT_VALID_DECIMAL": "Valeur décimale attendue",
     "FIELD_NOT_INT": "Valeur entière attendue",
     "FIELD_NOT_EMAIL": "Adresse email non valide",
+    "FIELD_NOT_VALID_DATE": "Date invalide",
+    "FIELD_NOT_VALID_DATE_AFTER": "Doit être postérieure à {{minDate}}",
+    "FIELD_NOT_VALID_DATE_BEFORE": "Doit être antérieure à {{maxDate}}",
+    "FIELD_NOT_VALID_DATE_RANGE": "Dates incohérentes",
+    "FIELD_NOT_VALID_DATE_MAX_DURATION": "Durée trop longue",
+    "FIELD_NOT_VALID_DATE_MIN_DURATION": "Durée trop courte",
+    "FIELD_NOT_VALID_HOUR_MINUTE": "Heure/minute invalide",
+    "FIELD_NOT_VALID_DATE_TIME": "Date/heure invalide",
+    "FIELD_NOT_VALID_LATITUDE": "Latitude invalide",
+    "FIELD_NOT_VALID_LONGITUDE": "Longitude invalide",
+    "FIELD_NOT_VALID_PATTERN": "Format incorrect",
+    "FIELD_NOT_VALID_PUBKEY": "Clé publique invalide",
+    "FIELD_NOT_VALID_ADDRESS": "Addresse SS58 invalide",
     "PASSWORD_NOT_CONFIRMED": "Ne correspond pas au mot de passe",
     "SALT_NOT_CONFIRMED": "Ne correspond pas à l'identifiant secret",
     "SEND_IDENTITY_FAILED": "Échec de l'inscription",
@@ -757,7 +782,7 @@
     "FEE_NEGATIVE": "Frais négatif non autorisé.",
     "NOT_ENOUGH_CREDIT": "Crédit insuffisant.",
     "INVALID_NODE_SUMMARY": "Nœud injoignable ou adresse invalide.",
-    "INVALID_USER_ID": "Le pseudonyme ne doit contenir ni espace ni caractère spécial ou accentué.",
+    "INVALID_USER_ID": "Ne doit contenir ni espace ni caractère spécial ou accentué.",
     "INVALID_COMMENT": "Le champ 'référence' ne doit pas contenir de caractères accentués.",
     "INVALID_PUBKEY": "La clé publique n'a pas le format attendu.",
     "INVALID_PUBKEY_CHECKSUM": "Somme de contrôle invalide.",
@@ -818,6 +843,8 @@
     "POPUP_TITLE": "Information",
     "CERTIFICATION_PENDING": "Certification envoyée. En attente de validation...",
     "CERTIFICATION_DONE": "Certification validée",
+    "CONFIRM_IDENTITY_PENDING": "Confirmation d'adhésion envoyée. En attente de validation...",
+    "CONFIRM_IDENTITY_DONE": "Confirmation d'adhésion validée",
     "NOT_ENOUGH_CREDIT": "Crédit insuffisant",
     "TRANSFER_SENT": "Virement envoyé",
     "COPY_TO_CLIPBOARD_DONE": "Copié dans le presse-papier",
@@ -956,98 +983,5 @@
       "END_NOT_LOGIN": "Cette visite guidée est <b>terminée</b> !<br/><br/>Si vous souhaitez rejoindre la monnaie {{currency|capitalize}}, il vous suffira de cliquer sur <b>{{'LOGIN.CREATE_FREE_ACCOUNT'|translate}}</b> ci-dessous.",
       "END_READONLY": "Cette visite guidée est <b>terminée</b>.<br/><br/>{{'MODE.READONLY.INSTALL_HELP'|translate}}."
     }
-  },
-  "API": {
-    "COMMON": {
-      "LINK_DOC": "Documentation API",
-      "LINK_DOC_HELP": "Documentation pour les développeurs",
-      "LINK_STANDARD_APP": "Version classique",
-      "LINK_STANDARD_APP_HELP": "Ouvrir la version classique de {{'COMMON.APP_NAME'|translate}}",
-      "CONNECTION_ERROR": "Nœud <b>{{server}}</b> injoignable ou adresse invalide.<br/><br/>Vérifiez votre connexion Internet, ou contactez l'administrateur du site."
-    },
-    "HOME": {
-      "TITLE": "Documentation API {{'COMMON.APP_NAME'|translate}}",
-      "MESSAGE": "Bienvenue dans la <b>documentation de l'API</b> {{'COMMON.APP_NAME'|translate}}.<br/>Connectez vos sites web à <a href=\"http://duniter.org\" target=\"_system\">Duniter</a> très simplement !",
-      "MESSAGE_SHORT": "Connectez vos sites à <a href=\"http://duniter.org\" target=\"_system\">Duniter</a> très simplement !",
-      "DOC_HEADER": "Services disponibles :"
-    },
-    "TRANSFER": {
-      "TITLE": "{{'COMMON.APP_NAME'|translate}} - Paiement en ligne",
-      "TITLE_SHORT": "Paiement en ligne",
-      "SUMMARY": "Récapitulatif du paiement :",
-      "AMOUNT": "Montant :",
-      "AMOUNTS_HELP": "Veuillez choisir le montant :",
-      "NAME": "Nom :",
-      "PUBKEY": "Clé publique du destinataire :",
-      "COMMENT": "Référence de l'opération :",
-      "NODE": "Adresse du nœud :",
-      "DEMO": {
-        "SALT": "demo",
-        "PASSWORD": "demo",
-        "PUBKEY": "3G28bL6deXQBYpPBpLFuECo46d3kfYMJwst7uhdVBnD1",
-        "HELP": "<b>Mode démonstration</b> : Aucun paiement ne sera réellement envoyé pendant cette simulation.<br/>Veuillez utiliser les identifiants : <b>{{'API.TRANSFER.DEMO.SALT'|translate}} / {{'API.TRANSFER.DEMO.PASSWORD'|translate}}</b>",
-        "BAD_CREDENTIALS": "Vérifiez votre saisie.<br/>En mode démonstration, les identifiants sont : {{'API.TRANSFER.DEMO.SALT'|translate}} / {{'API.TRANSFER.DEMO.PASSWORD'|translate}}"
-      },
-      "INFO": {
-        "SUCCESS_REDIRECTING_WITH_NAME": "Paiement envoyé.<br/>Redirection vers <b>{{name}}</b>...",
-        "SUCCESS_REDIRECTING": "Paiement envoyé.<br/>Redirection vers le site du vendeur...",
-        "CANCEL_REDIRECTING_WITH_NAME": "Paiement annulé.<br/>Redirection vers <b>{{name}}</b>...",
-        "CANCEL_REDIRECTING": "Paiement annulé.<br/>Redirection vers le site du vendeur..."
-      },
-      "ERROR": {
-        "TRANSFER_FAILED": "Échec du paiement"
-      }
-    },
-    "DOC": {
-      "DESCRIPTION_DIVIDER": "Description",
-      "URL_DIVIDER": "Adresse d'appel",
-      "PARAMETERS_DIVIDER": "Paramètres",
-      "AVAILABLE_PARAMETERS": "Voici la liste des paramètres possibles :",
-      "DEMO_DIVIDER": "Tester",
-      "DEMO_HELP": "Pour tester ce service, cliquez sur le bouton ci-contre. Le résultat s'affichera en dessous.",
-      "DEMO_RESULT": "Résultat retourné par l'appel :",
-      "DEMO_RESULT_PEER": "Adresse du nœud utilisé :",
-      "DEMO_SUCCEED": "<i class=\"icon ion-checkmark\"></i> Succès !",
-      "DEMO_CANCELLED": "<i class=\"icon ion-close\"></i> Annulé par l'utilisateur",
-      "INTEGRATE_DIVIDER": "Intégrer",
-      "INTEGRATE_CODE": "Code :",
-      "INTEGRATE_RESULT": "Prévisualisation du résultat :",
-      "INTEGRATE_PARAMETERS": "Paramètres",
-      "TRANSFER": {
-        "TITLE": "Paiements",
-        "DESCRIPTION": "Depuis un site (ex: vente en ligne) vous pouvez déléguer le paiement en monnaie libre à Cesium API. Pour cela, il vous suffit de déclencher l'ouverture d'une page sur l'adresse suivante :",
-        "PARAM_PUBKEY": "Clé publique du destinataire",
-        "PARAM_PUBKEY_HELP": "Clé publique du destinataire (obligatoire)",
-        "PARAM_AMOUNT": "Montant",
-        "PARAM_AMOUNT_HELP": "Montant de la transaction (obligatoire). Valeurs multiples autorisées, en utilisant un séparateur (point-virgule, barre verticale ou espace).",
-        "PARAM_COMMENT": "Référence (ou commentaire)",
-        "PARAM_COMMENT_HELP": "Référence ou commentaire. Vous permettra par exemple d'identifier le paiement dans la BlockChain.",
-        "PARAM_NAME": "Nom (du destinataire ou du site web)",
-        "PARAM_NAME_HELP": "Le nom du destinataire, ou du site web appelant. Cela peut être un nom lisible (\"Mon site en ligne\"), ou encore une pseudo-adresse web (\"MonSite.com\").",
-        "PARAM_REDIRECT_URL": "Adresse web de redirection",
-        "PARAM_REDIRECT_URL_HELP": "Adresse web (URL) de redirection, appelé quand le paiement a été envoyé. Peut contenir les chaînes suivantes, qui seront remplacées par les valeurs de la transaction : \"{tx}\", \"{hash}\", \"{comment}\", \"{amount}\", \"{pubkey}\" et \"{node}\".",
-        "PARAM_CANCEL_URL": "Adresse web d'annulation",
-        "PARAM_CANCEL_URL_HELP": "Adresse web (URL) en cas d'annulation du paiement, par l'utilisateur. Peut contenir les chaînes suivantes, qui seront remplacées dynamiquement : \"{comment}\", \"{amount}\" et \"{pubkey}\".",
-        "PARAM_PREFERRED_NODE": "Adresse du nœud préféré",
-        "PARAM_PREFERRED_NODE_HELP": "Adresse (URL) du nœud Duniter à utiliser de préférence (\"g1.domaine.com:443\" ou \"https://g1.domaine.com\").",
-        "EXAMPLES_HELP": "Voici des exemples d'intégration :",
-        "EXAMPLE_BUTTON": "Bouton HTML",
-        "EXAMPLE_BUTTON_DEFAULT_TEXT": "Payer en {{currency|currencySymbol}}",
-        "EXAMPLE_BUTTON_DEFAULT_STYLE": "Style personnalisé",
-        "EXAMPLE_BUTTON_TEXT_HELP": "Texte du bouton",
-        "EXAMPLE_BUTTON_BG_COLOR": "Couleur du fond",
-        "EXAMPLE_BUTTON_BG_COLOR_HELP": "Exemple : #fbc14c, black, lightgrey, rgb(180,180,180)",
-        "EXAMPLE_BUTTON_FONT_COLOR": "Couleur du texte",
-        "EXAMPLE_BUTTON_FONT_COLOR_HELP": "Exemple : black, orange, rgb(180,180,180)",
-        "EXAMPLE_BUTTON_TEXT_ICON": "Icône",
-        "EXAMPLE_BUTTON_TEXT_WIDTH": "Largeur",
-        "EXAMPLE_BUTTON_TEXT_WIDTH_HELP": "Exemple : 200px, 50%",
-        "EXAMPLE_BUTTON_ICON_NONE": "Aucune",
-        "EXAMPLE_BUTTON_ICON_DUNITER": "Logo Duniter",
-        "EXAMPLE_BUTTON_ICON_CESIUM": "Logo Cesium",
-        "EXAMPLE_BUTTON_ICON_G1_COLOR": "Logo Ğ1",
-        "EXAMPLE_BUTTON_ICON_G1_BLACK": "Logo Ğ1 (noir)"
-      }
-    }
   }
 }
diff --git a/src/manifest.json b/src/manifest.json
index a3ef3272675f80add0293f65ff4054c39b7cadc1..e4374c48cc8c3d270e348969dfe05b945bc33a36 100644
--- a/src/manifest.json
+++ b/src/manifest.json
@@ -2,7 +2,7 @@
   "short_name": "Cesium",
   "name": "Cesium2",
   "manifest_version": 2,
-  "version": "2.0.0-alpha41",
+  "version": "2.0.0-alpha42",
   "default_locale": "fr",
   "description": "Cesium Wallet for Ğ1 libre currency",
   "icons": [
diff --git a/src/theme/_cesium.scss b/src/theme/_cesium.scss
index a1f3690755e9c6f8884ae91de42f9e645add2aa6..3f430b3a6955ae8135fc78f374ebd58bd87b0d85 100644
--- a/src/theme/_cesium.scss
+++ b/src/theme/_cesium.scss
@@ -20,6 +20,14 @@
   visibility: hidden;
 }
 
+ion-buttons[slot='end'].vertical-alignment {
+  flex-direction: column;
+  ion-note {
+    width: 100%;
+    text-align: end;
+  }
+}
+
 /* -- error message -- */
 .item.error,
 ion-item.error {
diff --git a/src/zone-flags.ts b/src/zone-flags.ts
index 1a45f391c5141d06d4222a67710624731ff2a8ac..ad0be3db93307d2e3e945566aa6bce2c46039624 100644
--- a/src/zone-flags.ts
+++ b/src/zone-flags.ts
@@ -10,17 +10,13 @@ zoneConfig.global.disable.requestAnimationFrame();
 zoneConfig.global.disable.geolocation();
 zoneConfig.global.disable.canvas();
 zoneConfig.global.disable.XHR();
+zoneConfig.global.disable.ZoneAwarePromise();
 
 zoneConfig.events.disable.UNPATCHED_EVENTS([
-  'mousemove',
-  'mouseover',
-  // TODO: check if can disabled this events:
-  'scroll',
+  //'mousemove',
+  //'mouseover',
+  //'scroll',
 ]);
 
-// FIXME disable zone in .then() functions
-//zoneConfig.global.disable.ZoneAwarePromise();
-
-// FIXME: need to patch progression toolbar, to call markForCheck()
-// Otherwise, the trip editor still show the loading bar
+// FIXME: cannot disable timers for now (execution error at startup)
 //zoneConfig.global.disable.timers();