import { AccountUpdate, assert, Bool, DeployArgs, method, Permissions, Provable, PublicKey, SmartContract, State, state, VerificationKey, } from "o1js"; import { FungibleTokenAdminBase } from "./FungibleTokenContract.js"; export interface FungibleTokenAdminDeployProps extends Exclude { adminPublicKey: PublicKey; } /** A contract that grants permissions for administrative actions on a token. * * We separate this out into a dedicated contract. That way, when issuing a token, a user can * specify their own rules for administrative actions, without changing the token contract itself. * * The advantage is that third party applications that only use the token in a non-privileged way * can integrate against the unchanged token contract. */ export class FungibleTokenAdmin extends SmartContract implements FungibleTokenAdminBase { @state(PublicKey) private adminPublicKey = State(); async deploy(props: FungibleTokenAdminDeployProps) { await super.deploy(props); this.adminPublicKey.set(props.adminPublicKey); this.account.permissions.set({ ...Permissions.default(), setVerificationKey: Permissions.VerificationKey.impossibleDuringCurrentVersion(), setPermissions: Permissions.impossible(), }); } /** Update the verification key. * Note that because we have set the permissions for setting the verification key to `impossibleDuringCurrentVersion()`, this will only be possible in case of a protocol update that requires an update. */ @method async updateVerificationKey(vk: VerificationKey) { this.account.verificationKey.set(vk); } private async ensureAdminSignature() { const admin = await Provable.witnessAsync(PublicKey, async () => { let pk = await this.adminPublicKey.fetch(); assert(pk !== undefined, "could not fetch admin public key"); return pk; }); this.adminPublicKey.requireEquals(admin); return AccountUpdate.createSigned(admin); } @method.returns(Bool) public async canMint(_accountUpdate: AccountUpdate) { await this.ensureAdminSignature(); return Bool(true); } @method.returns(Bool) public async canChangeAdmin(_admin: PublicKey) { await this.ensureAdminSignature(); return Bool(true); } @method.returns(Bool) public async canPause(): Promise { await this.ensureAdminSignature(); return Bool(true); } @method.returns(Bool) public async canResume(): Promise { await this.ensureAdminSignature(); return Bool(true); } @method.returns(Bool) public async canChangeVerificationKey(_vk: VerificationKey): Promise { await this.ensureAdminSignature(); return Bool(true); } }