solana_kit_attestation_service
Solana Attestation Service program client for the Solana Kit Dart SDK.
Provides instruction builders, account codecs, PDA helpers, and a schema-driven attestation data codec for the Solana Attestation Service, the on-chain protocol for verifiable credentials: issuers register credentials, declare schemas, and issue attestations that verifiers can fetch and decode.
Installation
Installation
Install the package directly:
dependencies:
"solana_kit_attestation_service": ^
If your app uses several Solana Kit packages together, you can also depend on the umbrella package instead:
dart pub add solana_kit
Inside this monorepo, Dart workspace resolution uses the local package automatically.
How generated program clients work
Generated program clients share one API shape, so what you learn in one program transfers to the next:
- Program address constant — a
...ProgramAddressconstant identifies the program on-chain. - Identification helpers —
identify...Programandidentify...Instructionmatch programs and instructions without string comparisons. - Instruction builders and parsers —
get...Instructionencodes parameters,parse...Instructiondecodes a transaction instruction back into typed arguments. - Account codecs —
get...AccountCodecanddecode...Accountturn on-chain bytes into typed account objects. - Plan helpers —
get...InstructionPlanhelpers compose multi-instruction flows (such as creating an account before acting on it) into transaction plans the standard executor can run.
Errors thrown by these helpers and by transaction execution surface as SolanaError; match program-specific failures with the program error helpers.
Match program errors from your program
Transaction failures surface as SolanaError values. When a transaction fails with a custom program error, the RPC response identifies the failing instruction by index — pair it with the transaction message to attribute the error to a program and match custom error codes.
import 'package:solana_kit_addresses/solana_kit_addresses.dart';
import 'package:solana_kit_programs/solana_kit_programs.dart';
Future<void> handleTransactionFailure(Object error) async {
const myProgramAddress = Address('11111111111111111111111111111111');
final transactionMessage = TransactionMessageInput(
instructions: {0: InstructionInput(programAddress: myProgramAddress)},
);
if (isProgramError(error, transactionMessage, myProgramAddress, 42)) {
// Custom program error code 42 from this program.
} else if (isProgramError(error, transactionMessage, myProgramAddress)) {
// Any other custom error from this program.
}
}
transactionMessage is a lightweight TransactionMessageInput — a map from instruction index to InstructionInput(programAddress: ...). Build it from the same instructions you sent, so matching stays accurate even when the transaction mixes instructions from several programs.
Concepts and usage
The Solana Attestation Service is an open, permissionless protocol for verifiable on-chain credentials. In Dart, use solana_kit_attestation_service for generated instruction builders, account codecs, PDAs, and a schema-driven attestation data codec.
An issuer registers a Credential with its authorized signers, declares a Schema that names and types its fields, and issues Attestations whose payloads are encoded exactly as the schema declares. Verifiers fetch an attestation, decode its payload with the schema, and check the signer and expiry.
| Model | Use |
|---|---|
| Credential | Register an issuer and rotate its authorized signers. |
| Schema | Declare a versioned, pausable field layout under a credential. |
| Attestation | Store a schema-conformant payload (optionally tokenized as a Token-2022 NFT). |
The canonical flow is create-credential, create-schema, create-attestation, then verify:
import 'dart:typed_data';
import 'package:solana_kit/solana_kit.dart';
import 'package:solana_kit_attestation_service/solana_kit_attestation_service.dart';
Future<void> main() async {
const authority = Address('tbFevHibEdBNFJfZ7xKC8k1th8pt2YPEXTk4sGMxCGa');
final (credential, _) = await findCredentialPda(
seeds: const CredentialSeeds(authority: authority, name: 'my-credential'),
);
final (schema, _) = await findSchemaPda(
seeds: SchemaSeeds(credential: credential, name: 'person', version: 1),
);
final instruction = getCreateAttestationInstruction(
programAddress: solanaAttestationServiceProgramAddress,
payer: authority,
authority: authority,
credential: credential,
schema: schema,
attestation: authority,
systemProgram: systemProgramAddress,
nonce: authority,
data: Uint8List.fromList([0]),
expiry: BigInt.zero,
);
print(instruction.programAddress);
}
Encoding attestation data
An attestation stores its payload as raw bytes laid out by its schema. serializeAttestationData turns a field map into that byte blob using the schema's declared layout, and deserializeAttestationData reads it back:
import 'package:solana_kit_attestation_service/solana_kit_attestation_service.dart';
Future<void> encodeData(Schema schema) async {
final data = serializeAttestationData(schema, {'name': 'Alice', 'age': 42});
final decoded = deserializeAttestationData(schema, data);
print(decoded['name']); // Alice
}
Encoding requires the data map's keys to match the schema exactly: a missing field, or one the schema does not declare, throws an ArgumentError naming the field instead of silently producing an incomplete attestation.
Fields declared as strings decode strictly: bytes that are not valid UTF-8 (raw hashes, ciphertext) are surfaced losslessly as 0x-prefixed hex strings instead of replacement characters. A char field holds exactly one Unicode character and is encoded as its 4-byte little-endian code point, matching the Rust program.
Reading schema accounts
The generated Schema account keeps its name, description, layout, and fieldNames as raw length-prefixed byte blobs, exactly as stored on-chain. Decode them with the typed helpers:
import 'package:solana_kit_attestation_service/solana_kit_attestation_service.dart';
Future<void> readSchema(Schema schema) async {
final name = decodeSchemaText(schema.name);
final fieldNames = decodeSchemaFieldNames(schema.fieldNames);
final layout = decodeSchemaLayout(schema.layout);
print('$name declares $fieldNames as $layout');
}
Instructions
| Instruction | Discriminator | Description |
|---|---|---|
CreateCredential |
0 | Register a credential (issuer) with its authorized signers. |
CreateSchema |
1 | Declare a schema layout under a credential. |
ChangeSchemaStatus |
2 | Pause or unpause a schema. |
ChangeAuthorizedSigners |
3 | Rotate a credential's authorized signers. |
ChangeSchemaDescription |
4 | Update a schema's description. |
ChangeSchemaVersion |
5 | Create a new version of a schema. |
CreateAttestation |
6 | Issue an attestation conforming to a schema. |
CloseAttestation |
7 | Close an attestation and reclaim rent. |
TokenizeSchema |
9 | Create the schema mint for tokenized attestations. |
CreateTokenizedAttestation |
10 | Issue an attestation as a Token-2022 NFT. |
CloseTokenizedAttestation |
11 | Close a tokenized attestation and burn its mint. |
EmitEvent |
228 | Emit an event through the program's event authority. |
Discriminant 8 is unused. The program's entrypoint assigns EmitEvent the first byte of its event instruction tag (228), and TokenizeSchema starts at 9.
Upstream reference
Generated layer mirrors solana-foundation/solana-attestation-service at commit 5b64cf09843d62ca800f7d73f8438ad3505de70e.
Libraries
- solana_kit_attestation_service
- Solana Attestation Service program client for the Solana Kit Dart SDK.