@layerzerolabs/lz-sui-sdk-v2
Version:
143 lines (126 loc) • 5.01 kB
text/typescript
import { bcs } from '@mysten/sui/bcs'
import { SuiClient } from '@mysten/sui/client'
import { Transaction, TransactionArgument, TransactionResult } from '@mysten/sui/transactions'
import { ModuleManager } from '../../module-manager'
import { ObjectOptions } from '../../types'
import { asAddress, executeSimulate } from '../../utils'
const MODULE_NAME = 'package_whitelist_validator'
export const ValidatorErrorCode = {
// PTB Whitelist related errors
EInvalidWitness: 1,
} as const
export class PackageWhitelistValidator {
public packageId: string
public readonly client: SuiClient
private readonly objects: ObjectOptions
constructor(
packageId: string,
client: SuiClient,
objects: ObjectOptions,
private readonly moduleManager: ModuleManager
) {
this.packageId = packageId
this.client = client
this.objects = objects
}
// === Whitelist Management Functions ===
/**
* Add a package to the whitelist using a LayerZero witness
* This function is permissionless and allows packages to self-register
* by providing a valid LayerZeroWitness type
* @param tx - The transaction to add the move call to
* @param witness - The LayerZero witness from the package
* @template T - The witness type that must be named "_witness::LayerZeroWitness"
*/
addWhitelistMoveCall(tx: Transaction, witness: TransactionArgument, witnessType: string): void {
tx.moveCall({
target: this.#target('add_whitelist'),
typeArguments: [witnessType],
arguments: [tx.object(this.objects.packageWhitelistValidator), witness],
})
}
// === View Functions ===
/**
* Check if a package is whitelisted
* @param tx - The transaction to add the move call to
* @param packageAddress - The package address to check
* @returns Transaction result containing the whitelist status
*/
isWhitelistedMoveCall(tx: Transaction, packageAddress: string | TransactionArgument): TransactionResult {
return tx.moveCall({
target: this.#target('is_whitelisted'),
arguments: [tx.object(this.objects.packageWhitelistValidator), asAddress(tx, packageAddress)],
})
}
/**
* Validate multiple packages at once
* @param tx - The transaction to add the move call to
* @param packageAddresses - Array of package addresses to validate
* @returns Transaction result containing the validation status
*/
validateMoveCall(tx: Transaction, packageAddresses: string[]): TransactionResult {
return tx.moveCall({
target: this.#target('validate'),
arguments: [
tx.object(this.objects.packageWhitelistValidator),
tx.pure(bcs.vector(bcs.Address).serialize(packageAddresses)),
],
})
}
/**
* Check if a package is whitelisted
* @param packageAddress - The package address to check
* @returns Promise<boolean> - True if the package is whitelisted
*/
async isWhitelisted(packageAddress: string): Promise<boolean> {
return executeSimulate(
this.client,
(tx) => {
this.isWhitelistedMoveCall(tx, packageAddress)
},
(result) => bcs.Bool.parse(result[0].value)
)
}
// === Utility Functions ===
/**
* Extract package ID from a witness type name
* @param witnessTypeName - The full type name of the witness
* @returns string | null - The package ID if extraction is successful
*/
extractPackageFromWitness(witnessTypeName: string): string | null {
// Pattern: "0x123abc::my_package_witness::LayerZeroWitness"
const parts = witnessTypeName.split('::')
if (parts.length >= 3) {
const packageId = parts[0]
if (packageId.startsWith('0x') && packageId.length > 2) {
return packageId
}
}
return null
}
// === Batch Operations ===
/**
* Validate multiple packages at once using the contract's validate function
* @param packageAddresses - Array of package addresses to validate
* @returns Promise<boolean> - True if all packages are whitelisted
*/
async validate(packageAddresses: string[]): Promise<boolean> {
return executeSimulate(
this.client,
(tx) => {
this.validateMoveCall(tx, packageAddresses)
},
(result) => bcs.Bool.parse(result[0].value)
)
}
/**
* Generate the full target path for move calls
* @param name - The function name to call
* @param module_name - The module name (defaults to MODULE_NAME)
* @returns The full module path for the move call
* @private
*/
#target(name: string, module_name = MODULE_NAME): string {
return `${this.packageId}::${module_name}::${name}`
}
}