Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 19 additions & 1 deletion ccip-sdk/src/cct/solana/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,13 @@ import { describe, it } from 'node:test'

import { Connection } from '@solana/web3.js'

import { SolanaTokenManager } from './index.ts'
import {
type RegisterAdminMethod,
type TokenAuthorityType,
REGISTER_ADMIN_METHODS,
SolanaTokenManager,
TOKEN_AUTHORITY_TYPES,
} from './index.ts'
import type {
GetTokenPoolStateParams,
GetTokenPoolStateResult,
Expand All @@ -28,6 +34,8 @@ describe('SolanaTokenManager (cct/solana)', () => {
assert.equal(typeof cct.deployToken, 'function')
assert.equal(typeof cct.generateUnsignedCreateTokenAccount, 'function')
assert.equal(typeof cct.createTokenAccount, 'function')
assert.equal(typeof cct.generateUnsignedTransferAuthority, 'function')
assert.equal(typeof cct.transferAuthority, 'function')

// Token admin registry operations
assert.equal(typeof cct.generateUnsignedAcceptAdmin, 'function')
Expand Down Expand Up @@ -74,6 +82,16 @@ describe('SolanaTokenManager (cct/solana)', () => {
assert.equal(typeof cct.getTokenPoolState, 'function')
})

it('exports public operation constants', () => {
const authorityType: TokenAuthorityType = TOKEN_AUTHORITY_TYPES.MINT
const registrationMethod: RegisterAdminMethod = REGISTER_ADMIN_METHODS.OWNER

assert.equal(authorityType, 'mint')
assert.equal(TOKEN_AUTHORITY_TYPES.FREEZE, 'freeze')
assert.equal(registrationMethod, 'owner')
assert.equal(REGISTER_ADMIN_METHODS.CCIP_ADMIN, 'ccip-admin')
})

it('creates from a connection provider', async (t) => {
const chain = stubChain()
const connection = new Connection('http://localhost:8899')
Expand Down
68 changes: 68 additions & 0 deletions ccip-sdk/src/cct/solana/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,16 @@ import {
type ExecuteCreateTokenAccountResult,
type ExecuteDeployTokenParams,
type ExecuteDeployTokenResult,
type ExecuteTransferAuthorityParams,
type ExecuteTransferAuthorityResult,
type GenerateCreateTokenAccountParams,
type GenerateCreateTokenAccountResult,
type GenerateDeployTokenParams,
type GenerateDeployTokenResult,
type GenerateTransferAuthorityParams,
type GenerateTransferAuthorityResult,
CreateTokenAccount,
TransferAuthority,
} from './token/operations/index.ts'
import {
type ExecuteAcceptAdminParams,
Expand Down Expand Up @@ -144,6 +149,7 @@ export class SolanaTokenManager extends TokenManager<typeof ChainFamily.Solana>
readonly chain: SolanaChain
// Token operations
readonly #createTokenAccount = new CreateTokenAccount()
readonly #transferAuthority = new TransferAuthority()

// Token admin registry operations
readonly #acceptAdmin = new AcceptAdmin()
Expand Down Expand Up @@ -309,6 +315,66 @@ export class SolanaTokenManager extends TokenManager<typeof ChainFamily.Solana>
return this.#createTokenAccount.execute(this.chain, opts)
}

/**
* Builds unsigned instructions for an immediate SPL Token mint and/or freeze authority transfer.
*
* @remarks
* Once confirmed, the current authority loses the selected roles. Set `authorityTypes` to
* `['mint']`, `['freeze']`, or both. Set `newAuthority` to null to permanently revoke the selected
* roles; a revoked role cannot be transferred or restored. All selected roles must have the same
* current authority. The instructions are atomic: no role changes if any selected transfer fails.
* `authority` defaults to `payer`. For an SPL Token multisig authority, provide `multisigSigners`
* and collect member signatures externally.
*
* @throws {@link CCTParamsInvalidError} If an address or authority role selection is invalid.
* @throws {@link CCIPTokenMintNotFoundError} If the mint does not exist.
* @throws {@link CCIPTokenMintInvalidError} If the mint is not owned by an SPL Token program.
*
* @example
* ```ts
* const cct = SolanaTokenManager.fromChain(chain)
* const unsigned = await cct.generateUnsignedTransferAuthority({
* payer: currentAuthority,
* tokenAddress: mint,
* newAuthority,
* authorityTypes: ['mint'],
* })
* ```
*/
generateUnsignedTransferAuthority(
opts: GenerateTransferAuthorityParams,
): Promise<GenerateTransferAuthorityResult> {
return this.#transferAuthority.generate(this.chain, opts)
}

/**
* Immediately transfers SPL Token mint and/or freeze authority using the executing wallet.
*
* @remarks
* Once confirmed, the current authority loses the selected roles. Set `authorityTypes` to
* `['mint']`, `['freeze']`, or both. Set `newAuthority` to null to permanently revoke the selected
* roles; a revoked role cannot be transferred or restored. All selected roles must have the same
* current authority. The transaction is atomic: no role changes if any selected transfer fails.
* SPL Token multisig authorities require `multisigSigners` and external member signatures; use
* {@link generateUnsignedTransferAuthority}.
*
* @throws {@link CCIPWalletInvalidError} If `wallet` cannot sign Solana transactions.
* @throws {@link CCTParamsInvalidError} If an address or authority role selection is invalid, or
* `authority` does not match the executing wallet.
* @throws {@link CCIPTokenMintNotFoundError} If the mint does not exist.
* @throws {@link CCIPTokenMintInvalidError} If the mint is not owned by an SPL Token program.
* @throws {@link CCTTxFailedError} If simulation or the SPL Token program rejects the transaction.
*
* @example
* ```ts
* const cct = SolanaTokenManager.fromChain(chain)
* await cct.transferAuthority({ wallet, tokenAddress: mint, newAuthority, authorityTypes: ['mint'] })
* ```
*/
transferAuthority(opts: ExecuteTransferAuthorityParams): Promise<ExecuteTransferAuthorityResult> {
return this.#transferAuthority.execute(this.chain, opts)
}

/**
* Builds unsigned SPL Token multisig creation instructions.
* The pool signer PDA occupies `threshold` slots; non-pool signers must meet the threshold independently.
Expand Down Expand Up @@ -1672,6 +1738,8 @@ export {
deriveTokenPoolSignerPda,
resolveTokenPoolProgram,
} from './programs/token-pool.ts'
export { TOKEN_AUTHORITY_TYPES } from './token/operations/transfer-authority.ts'
export { REGISTER_ADMIN_METHODS } from './token-admin-registry/operations/register-admin.ts'
export type { TransactionResult } from '../operation.ts'
export type { SerializedSolanaTxEncoding } from './serialize.ts'
export type * from './token/operations/index.ts'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,13 @@ export * from './append-to-lookup-table.ts'
export * from './create-lookup-table.ts'
export * from './get-supported-tokens.ts'
export * from './get-token-admin-registry.ts'
export * from './register-admin.ts'
export { RegisterAdmin } from './register-admin.ts'
export type {
ExecuteRegisterAdminParams,
ExecuteRegisterAdminResult,
GenerateRegisterAdminParams,
GenerateRegisterAdminResult,
RegisterAdminMethod,
} from './register-admin.ts'
export * from './set-pool.ts'
export * from './transfer-admin.ts'
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import { submit } from '../../submit.ts'
import { parsePublicKey, validateAuthorityMatchesWallet } from '../../validate.ts'

/** Authorization paths used to register a token in the TokenAdminRegistry. */
const REGISTER_ADMIN_METHODS = {
export const REGISTER_ADMIN_METHODS = {
OWNER: 'owner',
CCIP_ADMIN: 'ccip-admin',
} as const
Expand Down
8 changes: 8 additions & 0 deletions ccip-sdk/src/cct/solana/token/operations/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,10 @@
export * from './create-token-account.ts'
export * from './deploy-token.ts'
export { TransferAuthority } from './transfer-authority.ts'
export type {
ExecuteTransferAuthorityParams,
ExecuteTransferAuthorityResult,
GenerateTransferAuthorityParams,
GenerateTransferAuthorityResult,
TokenAuthorityType,
} from './transfer-authority.ts'
Loading
Loading