aere-contracts/test/memory-vault.test.js
Aere Network a13a649b77
Some checks are pending
contracts-ci / Install (lockfile) → compile → full test suite (push) Waiting to run
contracts-ci / PQC known-answer tests (NIST vectors) (push) Waiting to run
contracts-ci / Coverage (scoped, with artifacts) (push) Waiting to run
Initial public release
Aere Network public source. Everything here can be checked against the live
chain (chain id 2800, https://rpc.aere.network).

Scope note, stated up front rather than buried: consensus on chain 2800 is
classical secp256k1 ECDSA QBFT. The post-quantum work in this repository is at
the signature, precompile, account and transport layers. Nothing here makes the
consensus post-quantum, and no document in it should be read as claiming so.
2026-07-20 01:02:37 +03:00

121 lines
5.2 KiB
JavaScript

const { expect } = require("chai");
const { ethers } = require("hardhat");
describe("AereAgentMemoryVault", () => {
let user, agent1, agent2, outsider;
let v;
const SLOT_PREFS = ethers.keccak256(ethers.toUtf8Bytes("user.preferences"));
const SLOT_TONE = ethers.keccak256(ethers.toUtf8Bytes("user.tone"));
const HASH = ethers.keccak256(ethers.toUtf8Bytes("encrypted-blob"));
beforeEach(async () => {
[user, agent1, agent2, outsider] = await ethers.getSigners();
const F = await ethers.getContractFactory("AereAgentMemoryVault");
v = await F.deploy();
await v.waitForDeployment();
});
async function nowTs() {
return (await ethers.provider.getBlock("latest")).timestamp;
}
it("user grants permission + agent writes + head updates", async () => {
await v.connect(user).grant(agent1.address, SLOT_PREFS, true, true, 0);
await expect(
v.connect(agent1).write(user.address, SLOT_PREFS, HASH, "ipfs://blob")
).to.emit(v, "EntryWritten").withArgs(user.address, SLOT_PREFS, agent1.address, 1n, HASH, "ipfs://blob");
const head = await v.headOf(user.address, SLOT_PREFS);
expect(head.contentHash).to.equal(HASH);
expect(head.writer).to.equal(agent1.address);
expect(head.version).to.equal(1n);
expect(await v.nextVersion(user.address, SLOT_PREFS)).to.equal(1n);
});
it("write reverts without canWrite or with empty hash", async () => {
await expect(
v.connect(agent1).write(user.address, SLOT_PREFS, HASH, "")
).to.be.revertedWithCustomError(v, "NotWriter");
await v.connect(user).grant(agent1.address, SLOT_PREFS, true, false, 0); // read-only
await expect(
v.connect(agent1).write(user.address, SLOT_PREFS, HASH, "")
).to.be.revertedWithCustomError(v, "NotWriter");
await v.connect(user).grant(agent1.address, SLOT_PREFS, true, true, 0);
await expect(
v.connect(agent1).write(user.address, SLOT_PREFS, ethers.ZeroHash, "")
).to.be.revertedWithCustomError(v, "EmptyHash");
});
it("permission expiry blocks new writes", async () => {
const t = await nowTs();
await v.connect(user).grant(agent1.address, SLOT_PREFS, true, true, t + 5);
await v.connect(agent1).write(user.address, SLOT_PREFS, HASH, "");
await ethers.provider.send("evm_increaseTime", [10]);
await ethers.provider.send("evm_mine", []);
await expect(
v.connect(agent1).write(user.address, SLOT_PREFS, HASH, "")
).to.be.revertedWithCustomError(v, "PermissionExpired");
});
it("grant with already-elapsed validUntil reverts", async () => {
const t = await nowTs();
await expect(
v.connect(user).grant(agent1.address, SLOT_PREFS, true, true, t - 1)
).to.be.revertedWithCustomError(v, "InvalidValidity");
});
it("user revoke blocks future writes + flips canReadNow", async () => {
await v.connect(user).grant(agent1.address, SLOT_PREFS, true, true, 0);
expect(await v.canReadNow(user.address, agent1.address, SLOT_PREFS)).to.equal(true);
await v.connect(user).revoke(agent1.address, SLOT_PREFS);
expect(await v.canReadNow(user.address, agent1.address, SLOT_PREFS)).to.equal(false);
await expect(
v.connect(agent1).write(user.address, SLOT_PREFS, HASH, "")
).to.be.revertedWithCustomError(v, "NotWriter");
});
it("revoke without prior grant reverts", async () => {
await expect(
v.connect(user).revoke(agent1.address, SLOT_PREFS)
).to.be.revertedWithCustomError(v, "NoSuchPermission");
});
it("portability — second agent gets the same head after fresh grant", async () => {
await v.connect(user).grant(agent1.address, SLOT_PREFS, true, true, 0);
await v.connect(agent1).write(user.address, SLOT_PREFS, HASH, "ipfs://v1");
await v.connect(agent1).write(user.address, SLOT_PREFS, HASH, "ipfs://v2");
const headV1 = await v.headOf(user.address, SLOT_PREFS);
expect(headV1.version).to.equal(2n);
// User onboards agent2 with read-only access.
await v.connect(user).grant(agent2.address, SLOT_PREFS, true, false, 0);
expect(await v.canReadNow(user.address, agent2.address, SLOT_PREFS)).to.equal(true);
const headRead = await v.headOf(user.address, SLOT_PREFS);
expect(headRead.version).to.equal(2n);
// But agent2 cannot write yet.
await expect(
v.connect(agent2).write(user.address, SLOT_PREFS, HASH, "")
).to.be.revertedWithCustomError(v, "NotWriter");
});
it("each user namespace is isolated", async () => {
await v.connect(user).grant(agent1.address, SLOT_PREFS, true, true, 0);
await v.connect(agent1).write(user.address, SLOT_PREFS, HASH, "");
// outsider's namespace untouched.
const otherHead = await v.headOf(outsider.address, SLOT_PREFS);
expect(otherHead.version).to.equal(0n);
// Agent has no permission in outsider's namespace.
await expect(
v.connect(agent1).write(outsider.address, SLOT_PREFS, HASH, "")
).to.be.revertedWithCustomError(v, "NotWriter");
});
it("per-slot grain: granting one slot does not grant another", async () => {
await v.connect(user).grant(agent1.address, SLOT_PREFS, true, true, 0);
await expect(
v.connect(agent1).write(user.address, SLOT_TONE, HASH, "")
).to.be.revertedWithCustomError(v, "NotWriter");
});
});