@identity.com/gateway-solana-client
v2.0.1
Published
Gateway Client on Solana
Downloads
34
Readme
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:
- AdminService provides create, update, close, and retrieve Network account methods.
- NetworkService provides create, update, close, retreive and setState of Gatekeeper methods.
- GatekeeperService provides issue, refresh, setState, setData, change the associated gatekeeper, expire, and verify of pass account methods.
- Typescript Client library for AdminService, NetworkService, and GatewayService.
- It is built on Solana blockchain and is based on the versatile Anchor framework.
- Supports multiple networks (devnet, testnet, mainnet-beta, etc) and multiple wallets (sollet, solflare, etc).
- 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).
- The Gateway Protocol enables the usage of non-transferrable permissioned Gateway passes (mirroring properties of SBTs) that convey some property to the pass holder.
- 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:
- An
authority
, a (native) Verification Method with aCapability Invocation
flag, that is allowed to manipulate the network. - 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:
- An
authority
, a (native) Verification Method with aCapability Invocation
flag, that is allowed to manipulate the network. - 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