Skip to content

Commit

Permalink
add access control program integration tests
Browse files Browse the repository at this point in the history
  • Loading branch information
makarychev committed Jul 30, 2024
1 parent cee7d1a commit 04fd09f
Show file tree
Hide file tree
Showing 8 changed files with 907 additions and 2 deletions.
5 changes: 5 additions & 0 deletions app/src/idl/transfer_restrictions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1926,6 +1926,11 @@ export type TransferRestrictions = {
"code": 6008,
"name": "escrowAccountsMismatch",
"msg": "Escrow accounts mismatch"
},
{
"code": 6009,
"name": "invalidHolderIndex",
"msg": "Invalid transfer restriction holder index"
}
],
"types": [
Expand Down
154 changes: 154 additions & 0 deletions tests/access_control/burn-securities.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
import * as anchor from "@coral-xyz/anchor";
import { assert } from "chai";
import {
Keypair,
PublicKey
} from "@solana/web3.js";

import {
TestEnvironment,
TestEnvironmentParams,
} from "../helpers/test_environment";
import { solToLamports, topUpWallet } from "../utils";
import { TOKEN_2022_PROGRAM_ID } from "@solana/spl-token";

describe("Access Control burn securities", () => {
const testEnvironmentParams: TestEnvironmentParams = {
mint: {
decimals: 6,
name: "XYZ Token",
symbol: "XYZ",
uri: "https://e.com",
},
initialSupply: 1_000_000_000_000,
maxHolders: 10000,
};
let testEnvironment: TestEnvironment;
let reserveAdminWalletRole: PublicKey;
let reserveAdminTokenAccountPubkey: PublicKey;

before(async () => {
testEnvironment = new TestEnvironment(testEnvironmentParams);
await testEnvironment.setup();

[reserveAdminWalletRole] = testEnvironment.accessControlHelper.walletRolePDA(testEnvironment.reserveAdmin.publicKey);
reserveAdminTokenAccountPubkey = testEnvironment.mintHelper.getAssocciatedTokenAddress(testEnvironment.reserveAdmin.publicKey);
});

it("fails to burn more than maxTotalSupply", async () => {
const { supply: currentSupply } = await testEnvironment.mintHelper.getMint();
const amount = new anchor.BN(currentSupply.toString()).addn(1);
try {
await testEnvironment.accessControlHelper.burnSecurities(
amount,
testEnvironment.reserveAdmin.publicKey,
reserveAdminTokenAccountPubkey,
testEnvironment.reserveAdmin,
);
assert.fail("Expected an error");
} catch (error) {
const res = error.logs.some((log: string) =>
log === "Program log: Error: insufficient funds"
);
assert.isTrue(res);
}
});

it("does not allow burning by non-reserve admin", async () => {
const amount = new anchor.BN(1_000_000);
try {
await testEnvironment.accessControlHelper.burnSecurities(
amount,
testEnvironment.reserveAdmin.publicKey,
reserveAdminTokenAccountPubkey,
testEnvironment.walletsAdmin,
);
assert.fail("Expected an error");
} catch ({ error }) {
assert.equal(error.errorCode.code, "Unauthorized");
assert.equal(error.errorMessage, "Unauthorized");
}
});

it("fails when signer is not the authority", async () => {
const amount = new anchor.BN(1_000_000);
const reserveAdminPretender = new Keypair();
await topUpWallet(testEnvironment.connection, reserveAdminPretender.publicKey, solToLamports(1));

try {
await testEnvironment.accessControlHelper.program.methods
.burnSecurities(amount)
.accountsStrict({
authority: testEnvironment.reserveAdmin.publicKey,
authorityWalletRole: reserveAdminWalletRole,
accessControl: testEnvironment.accessControlHelper.accessControlPubkey,
securityMint: testEnvironment.mintKeypair.publicKey,
targetAccount: reserveAdminTokenAccountPubkey,
targetAuthority: testEnvironment.reserveAdmin.publicKey,
tokenProgram: TOKEN_2022_PROGRAM_ID,
})
.signers([reserveAdminPretender])
.rpc({ commitment: testEnvironment.confirmOptions });
assert.fail("Expected an error");
} catch (error) {
assert.equal(
error.toString(),
`Error: unknown signer: ${reserveAdminPretender.publicKey.toBase58()}`
);
}
});

const attackerTestEnvironmentParams: TestEnvironmentParams = {
mint: {
decimals: 6,
name: "XYZ Token",
symbol: "XYZ",
uri: "https://e.com",
},
initialSupply: 1_000_000_000_000,
maxHolders: 10000,
};
let attackerEnvironment: TestEnvironment;
it("fails when attacker subtitute authority, wallet role and signer", async () => {
attackerEnvironment = new TestEnvironment(attackerTestEnvironmentParams);
await attackerEnvironment.setup();
const amount = new anchor.BN(1_000_000);
const [attackerReserveAdminWalletRole] = attackerEnvironment.accessControlHelper.walletRolePDA(attackerEnvironment.reserveAdmin.publicKey);
try {
await testEnvironment.accessControlHelper.program.methods
.burnSecurities(amount)
.accountsStrict({
authority: attackerEnvironment.reserveAdmin.publicKey,
authorityWalletRole: attackerReserveAdminWalletRole,
accessControl: testEnvironment.accessControlHelper.accessControlPubkey,
securityMint: testEnvironment.mintKeypair.publicKey,
targetAccount: reserveAdminTokenAccountPubkey,
targetAuthority: testEnvironment.reserveAdmin.publicKey,
tokenProgram: TOKEN_2022_PROGRAM_ID,
})
.signers([attackerEnvironment.reserveAdmin])
.rpc({ commitment: testEnvironment.confirmOptions });
assert.fail("Expected an error");
} catch ({ error }) {
assert.equal(error.errorCode.code, "ConstraintSeeds");
assert.equal(error.errorMessage, "A seeds constraint was violated");
}
});

it("burn securities", async () => {
const amount = new anchor.BN(1_000_000);
const { supply: supplyBeforeBurn } = await testEnvironment.mintHelper.getMint();
const { amount: reserveAdminAmountBefore } = await testEnvironment.mintHelper.getAccount(reserveAdminTokenAccountPubkey);
await testEnvironment.accessControlHelper.burnSecurities(
amount,
testEnvironment.reserveAdmin.publicKey,
reserveAdminTokenAccountPubkey,
testEnvironment.reserveAdmin,
);

const { supply: supplyAfterBurn } = await testEnvironment.mintHelper.getMint();
const { amount: reserveAdminAmountAfter } = await testEnvironment.mintHelper.getAccount(reserveAdminTokenAccountPubkey);
assert.equal(reserveAdminAmountAfter, reserveAdminAmountBefore - BigInt(amount.toString()));
assert.equal(supplyAfterBurn, supplyBeforeBurn - BigInt(amount.toString()));
});
});
Loading

0 comments on commit 04fd09f

Please sign in to comment.