Accommodate changes for participant role and KYC ID (#15)

Part of [Sumsub KYC integration in onboarding app](https://www.notion.so/Sumsub-KYC-integration-in-onboarding-app-607b598c9c1d4d12adc71725e2ab5e7e)
Follows cerc-io/laconicd#43

Co-authored-by: Nabarun <nabarun@deepstacksoft.com>
Reviewed-on: cerc-io/registry-sdk#15
Co-authored-by: Prathamesh Musale <prathamesh.musale0@gmail.com>
Co-committed-by: Prathamesh Musale <prathamesh.musale0@gmail.com>
This commit is contained in:
Prathamesh Musale 2024-07-26 15:41:00 +00:00 committed by nabarun
parent 022c55268c
commit 3a828b47ae
14 changed files with 321 additions and 41 deletions

View File

@ -4,13 +4,14 @@
Run following scripts when [proto files](./proto/) are updated. Run following scripts when [proto files](./proto/) are updated.
1. Install dependencies * Install dependencies:
```bash
yarn
```
2. Generate typescript code for the proto files ```bash
yarn
```
```bash * Generate typescript bindings for the proto files:
./scripts/proto-gen.sh
``` ```bash
./scripts/proto-gen.sh
```

View File

@ -1,6 +1,6 @@
{ {
"name": "@cerc-io/registry-sdk", "name": "@cerc-io/registry-sdk",
"version": "0.2.2", "version": "0.2.3",
"main": "dist/index.js", "main": "dist/index.js",
"types": "dist/index.d.ts", "types": "dist/index.d.ts",
"repository": "git@github.com:cerc-io/registry-sdk.git", "repository": "git@github.com:cerc-io/registry-sdk.git",

View File

@ -8,28 +8,36 @@ option go_package = "git.vdb.to/cerc-io/laconicd/x/onboarding";
// Params defines the parameters of the onboarding module. // Params defines the parameters of the onboarding module.
message Params { message Params {
bool onboarding_enabled = 1 [ bool onboarding_enabled = 1
(gogoproto.moretags) = "json:\"onboarding_enabled\" yaml:\"onboarding_enabled\"" [ (gogoproto.moretags) =
]; "json:\"onboarding_enabled\" yaml:\"onboarding_enabled\"" ];
} }
// Participant defines the data that will be stored for each enrolled participant // Participant defines the data that will be stored for each enrolled
// participant
message Participant { message Participant {
string cosmos_address = 1 [ // participant's cosmos (laconic) address
(gogoproto.moretags) = "json:\"cosmos_address\" yaml:\"cosmos_address\"" string cosmos_address = 1
]; [ (gogoproto.moretags) =
"json:\"cosmos_address\" yaml:\"cosmos_address\"" ];
string nitro_address = 2 [ // participant's Nitro address
(gogoproto.moretags) = "json:\"nitro_address\" yaml:\"nitro_address\"" string nitro_address = 2
]; [ (gogoproto.moretags) =
"json:\"nitro_address\" yaml:\"nitro_address\"" ];
// participant's role (participant | validator)
string role = 3 [ (gogoproto.moretags) = "json:\"role\" yaml:\"role\"" ];
// participant's KYC receipt ID
string kyc_id = 4
[ (gogoproto.moretags) = "json:\"kyc_id\" yaml:\"kyc_id\"" ];
} }
// EthPayload defines the payload that is signed by the ethereum private key // EthPayload defines the payload that is signed by the ethereum private key
message EthPayload { message EthPayload {
string address = 1 [ string address = 1
(gogoproto.moretags) = "json:\"address\" yaml:\"address\"" [ (gogoproto.moretags) = "json:\"address\" yaml:\"address\"" ];
];
string msg = 2 [ string msg = 2 [ (gogoproto.moretags) = "json:\"msg\" yaml:\"msg\"" ];
(gogoproto.moretags) = "json:\"msg\" yaml:\"msg\""
];
} }

View File

@ -12,7 +12,8 @@ option go_package = "git.vdb.to/cerc-io/laconicd/x/onboarding";
// Query defines the gRPC querier service for onboarding module // Query defines the gRPC querier service for onboarding module
service Query { service Query {
// Participants queries Participants list // Participants queries Participants list
rpc Participants(QueryParticipantsRequest) returns (QueryParticipantsResponse) { rpc Participants(QueryParticipantsRequest)
returns (QueryParticipantsResponse) {
option (google.api.http).get = "/cerc/onboarding/v1/participants"; option (google.api.http).get = "/cerc/onboarding/v1/participants";
} }
} }

View File

@ -15,9 +15,9 @@ service Msg {
// OnboardParticipant defines a method for enrolling a new validator. // OnboardParticipant defines a method for enrolling a new validator.
rpc OnboardParticipant(MsgOnboardParticipant) rpc OnboardParticipant(MsgOnboardParticipant)
returns (MsgOnboardParticipantResponse) { returns (MsgOnboardParticipantResponse) {
option (google.api.http).post = "/cerc/onboarding/v1/onboard_participant"; option (google.api.http).post = "/cerc/onboarding/v1/onboard_participant";
}; };
} }
// MsgOnboardParticipant defines a SDK message for enrolling a new validator. // MsgOnboardParticipant defines a SDK message for enrolling a new validator.
@ -28,7 +28,10 @@ message MsgOnboardParticipant {
string participant = 1; string participant = 1;
EthPayload eth_payload = 2 [ (gogoproto.nullable) = false ]; EthPayload eth_payload = 2 [ (gogoproto.nullable) = false ];
string eth_signature = 3; string eth_signature = 3;
string role = 4;
string kyc_id = 5;
} }
// MsgOnboardParticipantResponse defines the Msg/OnboardParticipant response type. // MsgOnboardParticipantResponse defines the Msg/OnboardParticipant response
// type.
message MsgOnboardParticipantResponse {} message MsgOnboardParticipantResponse {}

View File

@ -58,6 +58,11 @@ service Query {
returns (QueryGetRegistryModuleBalanceResponse) { returns (QueryGetRegistryModuleBalanceResponse) {
option (google.api.http).get = "/cerc/registry/v1/balance"; option (google.api.http).get = "/cerc/registry/v1/balance";
} }
// Authorities queries all authorities
rpc Authorities(QueryAuthoritiesRequest) returns (QueryAuthoritiesResponse) {
option (google.api.http).get = "/cerc/registry/v1/authorities";
}
} }
// QueryParamsRequest is request type for registry params // QueryParamsRequest is request type for registry params
@ -152,6 +157,16 @@ message QueryWhoisResponse {
]; ];
} }
// QueryAuthoritiesRequest is request type to get all authorities
message QueryAuthoritiesRequest { string owner = 1; }
// QueryAuthoritiesResponse is response type for authorities request
message QueryAuthoritiesResponse {
repeated AuthorityEntry authorities = 1 [ (gogoproto.nullable) = false ];
// pagination defines the pagination in the response.
cosmos.base.query.v1beta1.PageResponse pagination = 2;
}
// QueryLookupLrnRequest is request type for LookupLrn // QueryLookupLrnRequest is request type for LookupLrn
message QueryLookupLrnRequest { string lrn = 1; } message QueryLookupLrnRequest { string lrn = 1; }

View File

@ -440,7 +440,7 @@ export class Registry {
/** /**
* Onboard participant. * Onboard participant.
*/ */
async onboardParticipant ({ ethPayload, ethSignature }: MessageMsgOnboardParticipant, privateKey: string, fee: StdFee): Promise<MsgOnboardParticipantResponse> { async onboardParticipant ({ ethPayload, ethSignature, role, kycId }: MessageMsgOnboardParticipant, privateKey: string, fee: StdFee): Promise<MsgOnboardParticipantResponse> {
const account = new Account(Buffer.from(privateKey, 'hex')); const account = new Account(Buffer.from(privateKey, 'hex'));
await account.init(); await account.init();
const laconicClient = await this.getLaconicClient(account); const laconicClient = await this.getLaconicClient(account);
@ -449,6 +449,8 @@ export class Registry {
account.address, account.address,
ethPayload, ethPayload,
ethSignature, ethSignature,
role,
kycId,
fee fee
); );
} }

View File

@ -394,6 +394,8 @@ export class LaconicClient extends SigningStargateClient {
signer: string, signer: string,
ethPayload: EthPayload, ethPayload: EthPayload,
ethSignature: string, ethSignature: string,
role: string,
kycId: string,
fee: StdFee | 'auto' | number, fee: StdFee | 'auto' | number,
memo = '' memo = ''
) { ) {
@ -402,7 +404,9 @@ export class LaconicClient extends SigningStargateClient {
value: { value: {
participant: signer, participant: signer,
ethPayload, ethPayload,
ethSignature ethSignature,
role,
kycId
} }
}; };

View File

@ -10,6 +10,9 @@ const { chainId, rpcEndpoint, gqlEndpoint, privateKey, fee } = getConfig();
jest.setTimeout(90 * 1000); jest.setTimeout(90 * 1000);
const DUMMY_ROLE = 'validator';
const DUMMY_KYC_ID = 'dummyKycId';
const onboardingEnabledTests = () => { const onboardingEnabledTests = () => {
let registry: Registry; let registry: Registry;
let ethWallet: Wallet; let ethWallet: Wallet;
@ -32,7 +35,9 @@ const onboardingEnabledTests = () => {
await registry.onboardParticipant({ await registry.onboardParticipant({
ethPayload, ethPayload,
ethSignature ethSignature,
role: DUMMY_ROLE,
kycId: DUMMY_KYC_ID
}, privateKey, fee); }, privateKey, fee);
}); });
@ -41,10 +46,12 @@ const onboardingEnabledTests = () => {
const cosmosAccount = await DirectSecp256k1Wallet.fromKey(account._privateKey, 'laconic'); const cosmosAccount = await DirectSecp256k1Wallet.fromKey(account._privateKey, 'laconic');
const [cosmosWallet] = await cosmosAccount.getAccounts(); const [cosmosWallet] = await cosmosAccount.getAccounts();
const expectedParticipants = [ const expectedParticipants: Participant[] = [
{ {
cosmosAddress: cosmosWallet.address, cosmosAddress: cosmosWallet.address,
nitroAddress: ethWallet.address nitroAddress: ethWallet.address,
role: DUMMY_ROLE,
kycId: DUMMY_KYC_ID
} }
]; ];
const participants = await registry.getParticipants(); const participants = await registry.getParticipants();
@ -76,7 +83,9 @@ const onboardingDisabledTests = () => {
try { try {
await registry.onboardParticipant({ await registry.onboardParticipant({
ethPayload, ethPayload,
ethSignature ethSignature,
role: DUMMY_ROLE,
kycId: DUMMY_KYC_ID
}, privateKey, fee); }, privateKey, fee);
} catch (error: any) { } catch (error: any) {
expect(error.toString()).toContain(errorMsg); expect(error.toString()).toContain(errorMsg);

View File

@ -9,10 +9,19 @@ export interface Params {
onboardingEnabled: boolean; onboardingEnabled: boolean;
} }
/** Participant defines the data that will be stored for each enrolled participant */ /**
* Participant defines the data that will be stored for each enrolled
* participant
*/
export interface Participant { export interface Participant {
/** participant's cosmos (laconic) address */
cosmosAddress: string; cosmosAddress: string;
/** participant's Nitro address */
nitroAddress: string; nitroAddress: string;
/** participant's role (participant | validator) */
role: string;
/** participant's KYC receipt ID */
kycId: string;
} }
/** EthPayload defines the payload that is signed by the ethereum private key */ /** EthPayload defines the payload that is signed by the ethereum private key */
@ -77,7 +86,7 @@ export const Params = {
}; };
function createBaseParticipant(): Participant { function createBaseParticipant(): Participant {
return { cosmosAddress: "", nitroAddress: "" }; return { cosmosAddress: "", nitroAddress: "", role: "", kycId: "" };
} }
export const Participant = { export const Participant = {
@ -91,6 +100,12 @@ export const Participant = {
if (message.nitroAddress !== "") { if (message.nitroAddress !== "") {
writer.uint32(18).string(message.nitroAddress); writer.uint32(18).string(message.nitroAddress);
} }
if (message.role !== "") {
writer.uint32(26).string(message.role);
}
if (message.kycId !== "") {
writer.uint32(34).string(message.kycId);
}
return writer; return writer;
}, },
@ -107,6 +122,12 @@ export const Participant = {
case 2: case 2:
message.nitroAddress = reader.string(); message.nitroAddress = reader.string();
break; break;
case 3:
message.role = reader.string();
break;
case 4:
message.kycId = reader.string();
break;
default: default:
reader.skipType(tag & 7); reader.skipType(tag & 7);
break; break;
@ -123,6 +144,8 @@ export const Participant = {
nitroAddress: isSet(object.nitroAddress) nitroAddress: isSet(object.nitroAddress)
? String(object.nitroAddress) ? String(object.nitroAddress)
: "", : "",
role: isSet(object.role) ? String(object.role) : "",
kycId: isSet(object.kycId) ? String(object.kycId) : "",
}; };
}, },
@ -132,6 +155,8 @@ export const Participant = {
(obj.cosmosAddress = message.cosmosAddress); (obj.cosmosAddress = message.cosmosAddress);
message.nitroAddress !== undefined && message.nitroAddress !== undefined &&
(obj.nitroAddress = message.nitroAddress); (obj.nitroAddress = message.nitroAddress);
message.role !== undefined && (obj.role = message.role);
message.kycId !== undefined && (obj.kycId = message.kycId);
return obj; return obj;
}, },
@ -141,6 +166,8 @@ export const Participant = {
const message = createBaseParticipant(); const message = createBaseParticipant();
message.cosmosAddress = object.cosmosAddress ?? ""; message.cosmosAddress = object.cosmosAddress ?? "";
message.nitroAddress = object.nitroAddress ?? ""; message.nitroAddress = object.nitroAddress ?? "";
message.role = object.role ?? "";
message.kycId = object.kycId ?? "";
return message; return message;
}, },
}; };

View File

@ -11,13 +11,24 @@ export interface MsgOnboardParticipant {
participant: string; participant: string;
ethPayload?: EthPayload; ethPayload?: EthPayload;
ethSignature: string; ethSignature: string;
role: string;
kycId: string;
} }
/** MsgOnboardParticipantResponse defines the Msg/OnboardParticipant response type. */ /**
* MsgOnboardParticipantResponse defines the Msg/OnboardParticipant response
* type.
*/
export interface MsgOnboardParticipantResponse {} export interface MsgOnboardParticipantResponse {}
function createBaseMsgOnboardParticipant(): MsgOnboardParticipant { function createBaseMsgOnboardParticipant(): MsgOnboardParticipant {
return { participant: "", ethPayload: undefined, ethSignature: "" }; return {
participant: "",
ethPayload: undefined,
ethSignature: "",
role: "",
kycId: "",
};
} }
export const MsgOnboardParticipant = { export const MsgOnboardParticipant = {
@ -34,6 +45,12 @@ export const MsgOnboardParticipant = {
if (message.ethSignature !== "") { if (message.ethSignature !== "") {
writer.uint32(26).string(message.ethSignature); writer.uint32(26).string(message.ethSignature);
} }
if (message.role !== "") {
writer.uint32(34).string(message.role);
}
if (message.kycId !== "") {
writer.uint32(42).string(message.kycId);
}
return writer; return writer;
}, },
@ -56,6 +73,12 @@ export const MsgOnboardParticipant = {
case 3: case 3:
message.ethSignature = reader.string(); message.ethSignature = reader.string();
break; break;
case 4:
message.role = reader.string();
break;
case 5:
message.kycId = reader.string();
break;
default: default:
reader.skipType(tag & 7); reader.skipType(tag & 7);
break; break;
@ -73,6 +96,8 @@ export const MsgOnboardParticipant = {
ethSignature: isSet(object.ethSignature) ethSignature: isSet(object.ethSignature)
? String(object.ethSignature) ? String(object.ethSignature)
: "", : "",
role: isSet(object.role) ? String(object.role) : "",
kycId: isSet(object.kycId) ? String(object.kycId) : "",
}; };
}, },
@ -86,6 +111,8 @@ export const MsgOnboardParticipant = {
: undefined); : undefined);
message.ethSignature !== undefined && message.ethSignature !== undefined &&
(obj.ethSignature = message.ethSignature); (obj.ethSignature = message.ethSignature);
message.role !== undefined && (obj.role = message.role);
message.kycId !== undefined && (obj.kycId = message.kycId);
return obj; return obj;
}, },
@ -99,6 +126,8 @@ export const MsgOnboardParticipant = {
? EthPayload.fromPartial(object.ethPayload) ? EthPayload.fromPartial(object.ethPayload)
: undefined; : undefined;
message.ethSignature = object.ethSignature ?? ""; message.ethSignature = object.ethSignature ?? "";
message.role = object.role ?? "";
message.kycId = object.kycId ?? "";
return message; return message;
}, },
}; };

View File

@ -5,6 +5,7 @@ import {
NameAuthority, NameAuthority,
NameRecord, NameRecord,
NameEntry, NameEntry,
AuthorityEntry,
} from "./registry"; } from "./registry";
import { import {
PageRequest, PageRequest,
@ -118,6 +119,18 @@ export interface QueryWhoisResponse {
nameAuthority?: NameAuthority; nameAuthority?: NameAuthority;
} }
/** QueryAuthoritiesRequest is request type to get all authorities */
export interface QueryAuthoritiesRequest {
owner: string;
}
/** QueryAuthoritiesResponse is response type for authorities request */
export interface QueryAuthoritiesResponse {
authorities: AuthorityEntry[];
/** pagination defines the pagination in the response. */
pagination?: PageResponse;
}
/** QueryLookupLrnRequest is request type for LookupLrn */ /** QueryLookupLrnRequest is request type for LookupLrn */
export interface QueryLookupLrnRequest { export interface QueryLookupLrnRequest {
lrn: string; lrn: string;
@ -1460,6 +1473,151 @@ export const QueryWhoisResponse = {
}, },
}; };
function createBaseQueryAuthoritiesRequest(): QueryAuthoritiesRequest {
return { owner: "" };
}
export const QueryAuthoritiesRequest = {
encode(
message: QueryAuthoritiesRequest,
writer: _m0.Writer = _m0.Writer.create()
): _m0.Writer {
if (message.owner !== "") {
writer.uint32(10).string(message.owner);
}
return writer;
},
decode(
input: _m0.Reader | Uint8Array,
length?: number
): QueryAuthoritiesRequest {
const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input);
let end = length === undefined ? reader.len : reader.pos + length;
const message = createBaseQueryAuthoritiesRequest();
while (reader.pos < end) {
const tag = reader.uint32();
switch (tag >>> 3) {
case 1:
message.owner = reader.string();
break;
default:
reader.skipType(tag & 7);
break;
}
}
return message;
},
fromJSON(object: any): QueryAuthoritiesRequest {
return {
owner: isSet(object.owner) ? String(object.owner) : "",
};
},
toJSON(message: QueryAuthoritiesRequest): unknown {
const obj: any = {};
message.owner !== undefined && (obj.owner = message.owner);
return obj;
},
fromPartial<I extends Exact<DeepPartial<QueryAuthoritiesRequest>, I>>(
object: I
): QueryAuthoritiesRequest {
const message = createBaseQueryAuthoritiesRequest();
message.owner = object.owner ?? "";
return message;
},
};
function createBaseQueryAuthoritiesResponse(): QueryAuthoritiesResponse {
return { authorities: [], pagination: undefined };
}
export const QueryAuthoritiesResponse = {
encode(
message: QueryAuthoritiesResponse,
writer: _m0.Writer = _m0.Writer.create()
): _m0.Writer {
for (const v of message.authorities) {
AuthorityEntry.encode(v!, writer.uint32(10).fork()).ldelim();
}
if (message.pagination !== undefined) {
PageResponse.encode(
message.pagination,
writer.uint32(18).fork()
).ldelim();
}
return writer;
},
decode(
input: _m0.Reader | Uint8Array,
length?: number
): QueryAuthoritiesResponse {
const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input);
let end = length === undefined ? reader.len : reader.pos + length;
const message = createBaseQueryAuthoritiesResponse();
while (reader.pos < end) {
const tag = reader.uint32();
switch (tag >>> 3) {
case 1:
message.authorities.push(
AuthorityEntry.decode(reader, reader.uint32())
);
break;
case 2:
message.pagination = PageResponse.decode(reader, reader.uint32());
break;
default:
reader.skipType(tag & 7);
break;
}
}
return message;
},
fromJSON(object: any): QueryAuthoritiesResponse {
return {
authorities: Array.isArray(object?.authorities)
? object.authorities.map((e: any) => AuthorityEntry.fromJSON(e))
: [],
pagination: isSet(object.pagination)
? PageResponse.fromJSON(object.pagination)
: undefined,
};
},
toJSON(message: QueryAuthoritiesResponse): unknown {
const obj: any = {};
if (message.authorities) {
obj.authorities = message.authorities.map((e) =>
e ? AuthorityEntry.toJSON(e) : undefined
);
} else {
obj.authorities = [];
}
message.pagination !== undefined &&
(obj.pagination = message.pagination
? PageResponse.toJSON(message.pagination)
: undefined);
return obj;
},
fromPartial<I extends Exact<DeepPartial<QueryAuthoritiesResponse>, I>>(
object: I
): QueryAuthoritiesResponse {
const message = createBaseQueryAuthoritiesResponse();
message.authorities =
object.authorities?.map((e) => AuthorityEntry.fromPartial(e)) || [];
message.pagination =
object.pagination !== undefined && object.pagination !== null
? PageResponse.fromPartial(object.pagination)
: undefined;
return message;
},
};
function createBaseQueryLookupLrnRequest(): QueryLookupLrnRequest { function createBaseQueryLookupLrnRequest(): QueryLookupLrnRequest {
return { lrn: "" }; return { lrn: "" };
} }
@ -1907,6 +2065,10 @@ export interface Query {
GetRegistryModuleBalance( GetRegistryModuleBalance(
request: QueryGetRegistryModuleBalanceRequest request: QueryGetRegistryModuleBalanceRequest
): Promise<QueryGetRegistryModuleBalanceResponse>; ): Promise<QueryGetRegistryModuleBalanceResponse>;
/** Authorities queries all authorities */
Authorities(
request: QueryAuthoritiesRequest
): Promise<QueryAuthoritiesResponse>;
} }
export class QueryClientImpl implements Query { export class QueryClientImpl implements Query {
@ -1922,6 +2084,7 @@ export class QueryClientImpl implements Query {
this.LookupLrn = this.LookupLrn.bind(this); this.LookupLrn = this.LookupLrn.bind(this);
this.ResolveLrn = this.ResolveLrn.bind(this); this.ResolveLrn = this.ResolveLrn.bind(this);
this.GetRegistryModuleBalance = this.GetRegistryModuleBalance.bind(this); this.GetRegistryModuleBalance = this.GetRegistryModuleBalance.bind(this);
this.Authorities = this.Authorities.bind(this);
} }
Params(request: QueryParamsRequest): Promise<QueryParamsResponse> { Params(request: QueryParamsRequest): Promise<QueryParamsResponse> {
const data = QueryParamsRequest.encode(request).finish(); const data = QueryParamsRequest.encode(request).finish();
@ -2026,6 +2189,20 @@ export class QueryClientImpl implements Query {
QueryGetRegistryModuleBalanceResponse.decode(new _m0.Reader(data)) QueryGetRegistryModuleBalanceResponse.decode(new _m0.Reader(data))
); );
} }
Authorities(
request: QueryAuthoritiesRequest
): Promise<QueryAuthoritiesResponse> {
const data = QueryAuthoritiesRequest.encode(request).finish();
const promise = this.rpc.request(
"cerc.registry.v1.Query",
"Authorities",
data
);
return promise.then((data) =>
QueryAuthoritiesResponse.decode(new _m0.Reader(data))
);
}
} }
interface Rpc { interface Rpc {

View File

@ -426,6 +426,8 @@ export class RegistryClient {
getParticipants { getParticipants {
cosmosAddress cosmosAddress
nitroAddress nitroAddress
role
kycId
} }
}`; }`;

View File

@ -12,7 +12,7 @@ export const onboardingTypes: ReadonlyArray<[string, GeneratedType]> = [
export interface MsgOnboardParticipantEncodeObject extends EncodeObject { export interface MsgOnboardParticipantEncodeObject extends EncodeObject {
readonly typeUrl: '/cerc.onboarding.v1.MsgOnboardParticipant'; readonly typeUrl: '/cerc.onboarding.v1.MsgOnboardParticipant';
readonly value: Partial<MsgOnboardParticipant>; readonly value: MsgOnboardParticipant;
} }
interface ethPayload { interface ethPayload {
@ -23,4 +23,6 @@ interface ethPayload {
export interface MessageMsgOnboardParticipant { export interface MessageMsgOnboardParticipant {
ethPayload: ethPayload ethPayload: ethPayload
ethSignature: string ethSignature: string
role: string
kycId: string
} }