{"id":27994445,"url":"https://github.com/metaplex-foundation/mpl-token-auth-rules","last_synced_at":"2025-08-14T18:35:18.756Z","repository":{"id":64404971,"uuid":"566921393","full_name":"metaplex-foundation/mpl-token-auth-rules","owner":"metaplex-foundation","description":"A program that provides the ability to create and execute rules to restrict common token operations such as transferring and selling.","archived":false,"fork":false,"pushed_at":"2024-12-02T12:08:09.000Z","size":10095,"stargazers_count":25,"open_issues_count":4,"forks_count":28,"subscribers_count":5,"default_branch":"main","last_synced_at":"2025-05-08T19:11:56.232Z","etag":null,"topics":["blockchain","metaplex","nft","rust","solana"],"latest_commit_sha":null,"homepage":"https://mpl-token-auth-rules.typedoc.metaplex.com","language":"HTML","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/metaplex-foundation.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-11-16T17:37:30.000Z","updated_at":"2025-02-20T13:00:45.000Z","dependencies_parsed_at":"2023-11-30T01:33:27.695Z","dependency_job_id":"893d67b5-d480-4e07-b076-99611b76595d","html_url":"https://github.com/metaplex-foundation/mpl-token-auth-rules","commit_stats":{"total_commits":361,"total_committers":8,"mean_commits":45.125,"dds":"0.24376731301939059","last_synced_commit":"bbdd42085205b027c863817eea9dc3660096f4e6"},"previous_names":[],"tags_count":35,"template":false,"template_full_name":"stegaBOB/solana-program-template","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/metaplex-foundation%2Fmpl-token-auth-rules","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/metaplex-foundation%2Fmpl-token-auth-rules/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/metaplex-foundation%2Fmpl-token-auth-rules/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/metaplex-foundation%2Fmpl-token-auth-rules/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/metaplex-foundation","download_url":"https://codeload.github.com/metaplex-foundation/mpl-token-auth-rules/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253133115,"owners_count":21859112,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["blockchain","metaplex","nft","rust","solana"],"created_at":"2025-05-08T19:12:05.627Z","updated_at":"2025-05-08T19:12:06.233Z","avatar_url":"https://github.com/metaplex-foundation.png","language":"HTML","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Metaplex Token Authorization Rules\nA program that provides the ability to create and execute rules to restrict common token operations such as transferring and selling.\n\nRead the official documentation [here](https://developers.metaplex.com/token-auth-rules).\n\n## Overview\nAuthorization rules are variants of a `Rule` enum that implements a `validate()` function.\n\nThere are **Primitive Rules** and **Composed Rules** that are created by combining of one or more primitive rules.\n\n**Primitive Rules** store any accounts or data needed for evaluation, and at runtime will produce a true or false output based on accounts and a well-defined `Payload` that are passed into the `validate()` function.\n\n**Composed Rules** return a true or false based on whether any or all of the primitive rules return true.  Composed rules can then be combined into higher-level composed rules that implement more complex boolean logic.  Because of the recursive definition of the `Rule` enum, calling `validate()` on a top-level composed rule will start at the top and validate at every level, down to the component primitive rules.\n\n## Getting Started\n\nThe packages below can be used to interact with Token Authorization Rules (Token Auth Rules) program.\n\n### TypeScript\n```sh\nnpm install @metaplex-foundation/mpl-token-auth-rules\n```\n\n[See typedoc documentation](https://mpl-token-auth-rules-js-docs.vercel.app/).\n\n### Rust\n```sh\ncargo add mpl-token-auth-rules\n```\n\n[See crate documentation](https://docs.rs/mpl-token-auth-rules/latest/mpl_token_auth_rules/).\n\n## Building\n\nFrom the root directory of the repository:\n\n- Install the required packages:\n```sh\npnpm install\n```\n\n- Build the program:\n```sh\npnpm programs:build\n```\n\nThis will create the program binary at `\u003cROOT\u003e/programs/.bin`\n\n## Testing\n\nToken Auth Rules includes three sets of tests: BPF, TypeScript for the JS Client, and Legacy Typescript for the Solita-based JS Client.\n\n### BPF\n\nFrom the root directory of the repository:\n```sh\npnpm programs:test\n```\n\n### TypeScript\n\nFrom the root directory of the repository:\n```sh\npnpm validator\n```\n\nThis will start a local validator using [Amman](https://github.com/metaplex-foundation/amman).\n\nAfter starting the validator, go to the folder `\u003cROOT\u003e/clients/js` and run:\n```sh\npnpm install\n```\n\nThis will install the required packages for the tests. Then, run:\n```sh\npnpm build \u0026\u0026 pnpm test\n```\n\n###  Legacy Typescript\n\nFollow all the same steps as for the TypeScript tests above, including starting the validator in the root directory, but for building and running the tests, navigate to the folder `\u003cROOT\u003e/clients/js-solita`.\n\n## CLI\n\nThe folder `cli` contains a typescript CLI to manage rule set revisions:\n```\nUsage: auth [options] [command]\n\nCLI for managing RuleSet revisions.\n\nOptions:\n  -V, --version      output the version number\n  -h, --help         display help for command\n\nCommands:\n  create [options]   creates a new rule set revision\n  convert [options]  converts a rule set revision from V1 to V2\n  print [options]    prints the latest rule set revision as a JSON object\n  help [command]     display help for command\n```\n\nTo start the CLI, navigate to the folder `./cli` and run\n```\n$ yarn install\n```\n\nThen, the CLI can be used as\n```\n$ yarn start \u003cCOMMAND\u003e\n```\n\nThe folder `./examples` contain several examples of rule sets. You will need to replace the `owner` pubkey value with the pubkey used to run the CLI.\n\n\u003e Note that you need to first build the JS SDK.\n\n## Examples\n\n### Rust\n**Note: Additional Rust examples can be found in the [program/tests](https://github.com/metaplex-foundation/mpl-token-auth-rules/tree/main/program/tests) directory.**\n```rust\nuse mpl_token_auth_rules::{\n    instruction::{\n        builders::{CreateOrUpdateBuilder, ValidateBuilder},\n        CreateOrUpdateArgs, InstructionBuilder, ValidateArgs,\n    },\n    payload::{Payload, PayloadType},\n    state::{CompareOp, Rule, RuleSetV1},\n};\nuse num_derive::ToPrimitive;\nuse rmp_serde::Serializer;\nuse serde::Serialize;\nuse solana_client::rpc_client::RpcClient;\nuse solana_sdk::{\n    instruction::AccountMeta, native_token::LAMPORTS_PER_SOL, signature::Signer,\n    signer::keypair::Keypair, transaction::Transaction,\n};\n\n#[repr(C)]\n#[derive(ToPrimitive)]\npub enum Operation {\n    OwnerTransfer,\n    Delegate,\n    SaleTransfer,\n}\n\nimpl ToString for Operation {\n    fn to_string(\u0026self) -\u003e String {\n        match self {\n            Operation::OwnerTransfer =\u003e \"OwnerTransfer\".to_string(),\n            Operation::Delegate =\u003e \"Delegate\".to_string(),\n            Operation::SaleTransfer =\u003e \"SaleTransfer\".to_string(),\n        }\n    }\n}\n\nfn main() {\n    let url = \"https://api.devnet.solana.com\".to_string();\n\n    let rpc_client = RpcClient::new(url);\n\n    let payer = Keypair::new();\n\n    let signature = rpc_client\n        .request_airdrop(\u0026payer.pubkey(), LAMPORTS_PER_SOL)\n        .unwrap();\n\n    loop {\n        let confirmed = rpc_client.confirm_transaction(\u0026signature).unwrap();\n        if confirmed {\n            break;\n        }\n    }\n\n    // --------------------------------\n    // Create RuleSet\n    // --------------------------------\n    // Find RuleSet PDA.\n    let (rule_set_addr, _ruleset_bump) = mpl_token_auth_rules::pda::find_rule_set_address(\n        payer.pubkey(),\n        \"test rule_set\".to_string(),\n    );\n\n    // Additional signer.\n    let adtl_signer = Keypair::new();\n\n    // Create some rules.\n    let adtl_signer_rule = Rule::AdditionalSigner {\n        account: adtl_signer.pubkey(),\n    };\n\n    let amount_rule = Rule::Amount {\n        amount: 1,\n        operator: CompareOp::LtEq,\n        field: \"Amount\".to_string(),\n    };\n\n    let overall_rule = Rule::All {\n        rules: vec![adtl_signer_rule, amount_rule],\n    };\n\n    // Create a RuleSet.\n    let mut rule_set = RuleSetV1::new(\"test rule_set\".to_string(), payer.pubkey());\n    rule_set\n        .add(Operation::OwnerTransfer.to_string(), overall_rule)\n        .unwrap();\n\n    println!(\"{:#?}\", rule_set);\n\n    // Serialize the RuleSet using RMP serde.\n    let mut serialized_rule_set = Vec::new();\n    rule_set\n        .serialize(\u0026mut Serializer::new(\u0026mut serialized_rule_set))\n        .unwrap();\n\n    // Create a `create` instruction.\n    let create_ix = CreateOrUpdateBuilder::new()\n        .payer(payer.pubkey())\n        .rule_set_pda(rule_set_addr)\n        .build(CreateOrUpdateArgs::V1 {\n            serialized_rule_set,\n        })\n        .unwrap()\n        .instruction();\n\n    // Add it to a transaction.\n    let latest_blockhash = rpc_client.get_latest_blockhash().unwrap();\n    let create_tx = Transaction::new_signed_with_payer(\n        \u0026[create_ix],\n        Some(\u0026payer.pubkey()),\n        \u0026[\u0026payer],\n        latest_blockhash,\n    );\n\n    // Send and confirm transaction.\n    let signature = rpc_client.send_and_confirm_transaction(\u0026create_tx).unwrap();\n    println!(\"Create tx signature: {}\", signature);\n\n    // --------------------------------\n    // Validate Operation\n    // --------------------------------\n    // Create a Keypair to simulate a token mint address.\n    let mint = Keypair::new().pubkey();\n\n    // Store the payload of data to validate against the rule definition.\n    let payload = Payload::from([(\"Amount\".to_string(), PayloadType::Number(1))]);\n\n    // Create a `validate` instruction with the additional signer.\n    let validate_ix = ValidateBuilder::new()\n        .rule_set_pda(rule_set_addr)\n        .mint(mint)\n        .additional_rule_accounts(vec![AccountMeta::new_readonly(adtl_signer.pubkey(), true)])\n        .build(ValidateArgs::V1 {\n            operation: Operation::OwnerTransfer.to_string(),\n            payload,\n            update_rule_state: false,\n            rule_set_revision: None,\n        })\n        .unwrap()\n        .instruction();\n\n    // Add it to a transaction.\n    let latest_blockhash = rpc_client.get_latest_blockhash().unwrap();\n    let validate_tx = Transaction::new_signed_with_payer(\n        \u0026[validate_ix],\n        Some(\u0026payer.pubkey()),\n        \u0026[\u0026payer, \u0026adtl_signer],\n        latest_blockhash,\n    );\n\n    // Send and confirm transaction.\n    let signature = rpc_client\n        .send_and_confirm_transaction(\u0026validate_tx)\n        .unwrap();\n    println!(\"Validate tx signature: {}\", signature);\n}\n```\n\n### JavaScript\n**Note: Additional JS examples can be found in the [/cli/](https://github.com/metaplex-foundation/mpl-token-auth-rules/tree/cli) source along with the example rulesets in [/cli/examples/](https://github.com/metaplex-foundation/mpl-token-auth-rules/tree/cli/examples)**\n```js\nimport { createCreateInstruction, createTokenAuthorizationRules, PREFIX, PROGRAM_ID } from './helpers/mpl-token-auth-rules';\nimport { Keypair, Connection, PublicKey, Transaction, SystemProgram } from '@solana/web3.js';\nimport {\n  findRuleSetPDA,\n  getRuleSetRevisionFromJson,\n  serializeRuleSetRevision,\n} from '@metaplex-foundation/mpl-token-auth-rules';\n\nexport const findRuleSetPDA = async (payer: PublicKey, name: string) =\u003e {\n    return await PublicKey.findProgramAddress(\n        [\n            Buffer.from(PREFIX),\n            payer.toBuffer(),\n            Buffer.from(name),\n        ],\n        PROGRAM_ID,\n    );\n}\n\nexport const createTokenAuthorizationRules = async (\n    connection: Connection,\n    payer: Keypair,\n    name: string,\n    data: Uint8Array,\n) =\u003e {\n    const ruleSetAddress = await findRuleSetPDA(payer.publicKey, name);\n\n    let createIX = createCreateOrUpdateInstruction(\n        {\n            payer: payer.publicKey,\n            ruleSetPda: ruleSetAddress[0],\n            systemProgram: SystemProgram.programId,\n        },\n        {\n            createOrUpdateArgs: {__kind: \"V1\", serializedRuleSet: data },\n        },\n        PROGRAM_ID,\n    )\n\n    const tx = new Transaction().add(createIX);\n\n    const { blockhash } = await connection.getLatestBlockhash();\n    tx.recentBlockhash = blockhash;\n    tx.feePayer = payer.publicKey;\n    const sig = await connection.sendTransaction(tx, [payer]);\n    await connection.confirmTransaction(sig, \"finalized\");\n    return ruleSetAddress[0];\n}\n\nconst connection = new Connection(\"\u003cYOUR_RPC_HERE\u003e\", \"finalized\");\nlet payer = Keypair.generate()\n\nconst revision = getRuleSetRevisionFromJson(JSON.parse(fs.readFileSync(\"./examples/v2/pubkey-list-match.json\")));\n// Create the rule set revision\nawait createTokenAuthorizationRules(connection, payer, name, serializeRuleSetRevision(revision));\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmetaplex-foundation%2Fmpl-token-auth-rules","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmetaplex-foundation%2Fmpl-token-auth-rules","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmetaplex-foundation%2Fmpl-token-auth-rules/lists"}