2.0.1 • Published 1 year ago

@identity.com/gateway-solana-client v2.0.1

Weekly downloads
-
License
MIT
Repository
github
Last release
1 year ago

Solana Gateway Client

A typescript client library for interacting with Identity.com's On-Chain Identity Gateway

Features

The gateway-solana-client library provides the following features:

  1. AdminService provides create, update, close, and retrieve Network account methods.
  2. NetworkService provides create, update, close, retreive and setState of Gatekeeper methods.
  3. GatekeeperService provides issue, refresh, setState, setData, change the associated gatekeeper, expire, and verify of pass account methods.
  4. Typescript Client library for AdminService, NetworkService, and GatewayService.
  5. It is built on Solana blockchain and is based on the versatile Anchor framework.
  6. Supports multiple networks (devnet, testnet, mainnet-beta, etc) and multiple wallets (sollet, solflare, etc).
  7. On a Network and Gatekeeper level, the Gateway Protocol offers flexible payment configuration for Gateway Passes (e.g. pay for pass on issue, pay for pass on refresh, pay for pass on verify, etc).
  8. The Gateway Protocol enables the usage of non-transferrable permissioned Gateway passes (mirroring properties of SBTs) that convey some property to the pass holder.
  9. Requirements and characteristics of a pass are defined within a Gatekeeper Network. Gatekeepers, belonging to Gatekeeper Networks are authoritative Issuers of Gateway Passes.

Client library

Installation

In TS/JS project:

yarn add @identity.com/gateway-solana-client # or npm install @identity.com/gateway-solana-client

Usage - Setup and Resolution

AdminService

The AdminService class controls all network operations within the client. It can be built with or without Anchor, though the build methods differ slightly.

    const program = anchor.workspace.SolanaAnchorGateway as anchor.Program<SolanaAnchorGateway>;
    const programProvider = program.provider as anchor.AnchorProvider;
    const authorityKeypair = Keypair.generate();
    const guardianAuthority = new anchor.Wallet(authorityKeypair);
    const networkAuthority = Keypair.generate();

    // with anchor 
    const service = await AdminService.buildFromAnchor(
        program,
        networkAuthority.publicKey,
        {
            clusterType: 'localnet',
            wallet: guardianAuthority,
        },
        programProvider
    );
    
    // without anchor
    const service = await AdminService.build(
        network: PublicKey,
        options: GatewayServiceOptions = {
            clusterType: SOLANA_MAINNET,
        }
    );

NetworkService

The NetworkService class controls all gatekeeper operations within the client. It can be built with or without Anchor, though the build methods differ slightly. Must be built with an existing network already in place.

    const program = anchor.workspace.SolanaAnchorGateway as anchor.Program<SolanaAnchorGateway>;
    const programProvider = program.provider as anchor.AnchorProvider;
    const guardianAuthority = Keypair.generate();
    const networkAuthority = Keypair.generate();
    const gatekeeperAuthority = Keypair.generate();

    // PDA for a gatekeeper — derived from network's account and a provided authority
    [gatekeeperDataAccount] = await NetworkService.createGatekeeperAddress(
      gatekeeperAuthority.publicKey,
      networkAuthority.publicKey
    );

    // with anchor 
    const networkService = await NetworkService.buildFromAnchor(
      program,
      gatekeeperAuthority.publicKey,
      gatekeeperDataAccount,
      {
        clusterType: 'devnet',
        wallet: new anchor.Wallet(gatekeeperAuthority),
      },
      programProvider
    );

    // without anchor
    const service = await AdminService.build(
      gatekeeperAuthority.publicKey,
      gatekeeperDataAccount,
      options: GatewayServiceOptions = {
        clusterType: SOLANA_MAINNET,
      }
    );

GatekeeperService

The GatekeeperService class controls all pass operations within the client. It can be built with or without Anchor, though the build methods differ slightly. Must be built with both an existing network and gatekeeper in place.

    const program = anchor.workspace.SolanaAnchorGateway as anchor.Program<SolanaAnchorGateway>;
    const programProvider = program.provider as anchor.AnchorProvider;
    const guardianAuthority = Keypair.generate();
    const networkAuthority = Keypair.generate();
    const gatekeeperAuthority = Keypair.generate();

    // Built AdminService
    const adminService: AdminService;
    // Built NetworkService
    const networkService: NetworkService;
    // pre-existing network
    const networkPDA: PublicKey;
    // pre-existing gatekeeper
    const gatekeeperPDA: PublicKey

    // with anchor
    const gatekeeperService = await GatekeeperService.buildFromAnchor(
        program,
        networkPDA,
        gatekeeperPDA,
        options: GatewayServiceOptions = {
            clusterType: 'devnet',
        },
        programProvider
    );

    // without anchor
    const gatekeeperService = await GatekeeperService.build(
        networkPDA,
        gatekeeperPDA,
        options: GatewayServiceOptions = {
            clusterType: SOLANA_MAINNET,
        }
    );

Usage - network Manipulation

The following are instructions that can be executed against a network.

When manipulating a network one generally needs two authoritative elements:

  1. An authority, a (native) Verification Method with a Capability Invocation flag, that is allowed to manipulate the network.
  2. A fee payer, a Solana account that covers the cost of the transaction execution.

Create a Network Account

creates a new network account

    await adminService.createNetwork(data: CreateNetworkData, authority?: PublicKey).rpc();

In order to use createNetwork instruction, you need to pass in the parameter, CreateNetworkData.

    export type CreateNetworkData = {
      // the number of keys needed to change the `auth_keys`.  
      authThreshold: number;
      // the length of time a pass lasts in seconds. `0` means does not expire. 
      passExpireTime: number;
      // The fees for this network, it's type feeStructure is defined below. 
      fees: FeeStructure[]; 
      // Keys with permissions on the network, it's type AuthKeyStructure is defined below.
      authKeys: AuthKeyStructure[]; 
      // A set of all supported tokens on the network, it's type supportedToken is defined below.
      supportedTokens: SupportedToken[]; 
    };
    export type FeeStructure = {
      token: PublicKey;
      issue: number;
      refresh: number;
      expire: number;
      verify: number;
    };
    export type AuthKeyStructure = {
      flags: number;
      key: PublicKey;
    };
    export type SupportedToken = {
      key: PublicKey;
      settlementInfo: SettlementInfo;
    };

Update a Network Account

updates an existing network account with new data (e.g. new guardian authority)

    await adminService.updateNetwork(data: UpdateNetworkData, authority?: PublicKey).rpc();

In order to use updateNetwork instruction, you need to pass in the parameter, UpdateNetworkData.

    export type UpdateNetworkData = {
      // The number of keys needed to change the `auth_keys`.  
      authThreshold: number;
      // The length of time a pass lasts in seconds. `0` means does not expire.
      passExpireTime: number; 
      // The fees for this network, it's type feeStructure is defined below.
      fees: UpdateFeeStructure; 
      // Keys with permissions on the network, it's type AuthKeyStructure is defined below.
      authKeys: UpdateAuthKeytructure; 
      // Features on the network, index relates to which feature it is. 
      // There are 32 bytes of data available for each feature.
      networkFeatures: number; 
      // A set of all supported tokens on the network, it's type UpdateSupportedToken is defined below.
      supportedTokens: UpdateSupportedTokens; 
    };
    export type AuthKeyStructure = {
      flags: number;
      key: PublicKey;
    };
    export type UpdateSupportedTokens = {
      add: SupportedToken[];
      remove: PublicKey[];
    };

Close a Network Account

Close a network account. This will also close all gatekeepers associated with the network.

    // destination - account that receives the rent back.
    await adminService.closeNetwork(destination: PublicKey, authority?: PublicKey).rpc();
     

Retrieve a Network Account

Retrieves a network account information

    await adminService.getNetworkAccount(account: PublicKey).rpc();

Below is the return types.

    export type NetworkAccount = {
      version: number;
      authority: PublicKey;
      networkIndex: number;
      authThreshold: number;
      passExpireTime: number;
      fees: FeeStructure[];
      authKeys: AuthKeyStructure[];
      networkFeatures: number;
      // Hash Set
      supportedTokens: SupportedToken[];
      // Hash Set
      gatekeepers: PublicKey[];
    };

Usage - gatekeeper Manipulation

The following are instructions that can be executed against a gatekeeper.

When manipulating a DID one generally needs two authoritative elements:

  1. An authority, a (native) Verification Method with a Capability Invocation flag, that is allowed to manipulate the network.
  2. A fee payer, a Solana account that covers the cost of the transaction execution.

Create a Gatekeeper Account

creates a new gatekeeper account

    await networkService.createGatekeeper(
      network: PublicKey, 
      stakingAccount: PublicKey, 
      payer: PublicKey, 
      data: CreateGatekeeperData
    ).rpc();

In order to use createGatekeeper instruction, you need to pass in the parameter, CreateGatekeeperData.

    export type CreateGatekeeperData = {
      // The fees for this gatekeeper  
      tokenFees: FeeStructure[];
      // The number of keys needed to change the `auth_keys`
      authThreshold: number;
      // The keys with permissions on this gatekeeper
      authKeys: AuthKeyStructure[]; 
    };

Update a Gatekeeper Account

updates an existing gatekeeper account

    await networkService.updateGatekeeper(
        data: UpdateGatekeeperData,
        stakingAccount: PublicKey,
        payer?: PublicKey,
        authority?: PublicKey
    ).rpc();

In order to use updateGatekeeper instruction, you need to pass in the parameter, UpdateGatekeeperData.

    export type UpdateGatekeeperData = {
      // The fees for this gatekeeper, it's type UpdateFeeStructure is defined below.  
      tokenFees: UpdateFeeStructure;
      // The number of keys needed to change the `auth_keys` 
      authThreshold: number;
      // The keys with permissions on this   gatekeeper, it's type UpdateAuthKeytructure is defined below.
      authKeys: UpdateAuthKeytructure; 
    };
    export type UpdateFeeStructure = {
      add: FeeStructure[];
      remove: PublicKey[];
    };
    export type UpdateAuthKeytructure = {
      add: AuthKeyStructure[];
      remove: PublicKey[];
    };

Set a Gatekeeper Account's State

sets the state of an existing gatekeeper account 0,1,2 = active, frozen, halted

    await networkService.setGatekeeperState(
        state: GatekeeperState,
        stakingAccount: PublicKey,
        payer?: PublicKey,
        authority?: PublicKey
    ).rpc();
    await networkService.setGatekeeperState(
        state: GatekeeperState,
        authority?: PublicKey
    ).rpc();

Close a Gatekeeper Account

Close a gatekeeper account. This will also close all passes associated with the gatekeeper.

    await networkService.closeNetwork(
        network: PublicKey,
        destination?: PublicKey,
        payer?: PublicKey,
        authority?: PublicKey
    ).rpc();

Retrieve a Gatekeeper Account

Retrieves a gatekeeper account information

    await networkService.getGatekeeperAccount(account: PublicKey).rpc();

Below is the return types.

    export type GatekeeperAccount = {
      // The version of this struct, should be 0 until a new version is released  
      version: number; 
      // The initial authority key
      authority: PublicKey; 
      // The [`GatekeeperNetwork`] this gatekeeper is on
      gatekeeperNetwork: PublicKey;
      // The staking account of this gatekeeper 
      stakingAccount: PublicKey;
      // The fees for this gatekeeper
      tokenFees: FeeStructure[]; 
      // The keys with permissions on this gatekeeper
      authKeys: AuthKeyStructure[]; 
      // The state of gatekeeper, default is   Active, it can be frozen or be revoked.
      state: GatekeeperState; 
    };
    export enum GatekeeperState {
      Active,
      Frozen,
      Halted,
    };

Usage - pass Manipulation

Issue a Pass Account

issues a new pass account

    await gatekeeperService.issuePass(
        data: IssuePassData,
        payer?: PublicKey,
        authority?: PublicKey
    ).rpc();

TODO: IssuePassData

Refresh a Pass Account

refreshes an existing pass account

    await gatekeeperService.refreshPass(
        data: RefreshPassData,
        payer?: PublicKey,
        authority?: PublicKey
    ).rpc();

TODO: RefreshPassData

Set State for a Pass Account

sets the state of an existing pass account 0,1,2 = active, frozen, halted

    await gatekeeperService.setPassState(
        state: PassState,
        pass: PublicKey,
        payer?: PublicKey,
        authority?: PublicKey
    ).rpc();

TODO: PassState

Set Data for a Pass Account

sets the data of an existing pass account

    await gatekeeperService.setPassData(
        data: SetPassData,
        pass: PublicKey,
        payer?: PublicKey,
        authority?: PublicKey
    ).rpc();

TODO: SetPassData

Change the Associated Gatekeeper for a Pass Account

changes the associated gatekeeper of an existing pass account

    await gatekeeperService.changePassGatekeeper(
        gatekeeper: PublicKey,
        pass: PublicKey,
        payer?: PublicKey,
        authority?: PublicKey
    ).rpc();

Expire a Pass Account

expires an existing pass account

    await gatekeeperService.expirePass(
        pass: PublicKey,
        payer?: PublicKey,
        authority?: PublicKey
    ).rpc();

Verify a Pass Account

verifies an existing pass account

    await gatekeeperService.verifyPass(
        pass: PublicKey,
        payer?: PublicKey,
        authority?: PublicKey
    ).rpc();

Contributing

Note: Before contributing to this project, please check out the code of conduct and contributing guidelines.

Gateway uses yarn

yarn

Running the tests

E2E tests

Install Solana locally by following the steps described here. Also, install Anchor by using the information found here

yarn test