hoodquidity/packages/contracts/lib/openzeppelin-contracts/test/proxy/Proxy.behaviour.js
Денис Зефиров dba2811447 Hoodquidity: liquidity campaigns for Robinhood Chain stock token markets
Full build: Vite/React acid-terminal frontend (BEARER design system,
Panchang/Sentient/Fragment Mono, neon layer, palette audit script),
HoodquidityVaults Foundry contracts (single+dual deposits via Chainlink-style
feeds, hybrid exit, 10% platform fee, boost, Genesis LP), Reown AppKit wallet
connect with Robinhood Chain testnet (46630), live data from Dexscreener and
onchain reads, partner portal, design-sync setup for claude.ai/design.

Deploy: static via Forgejo Actions platform, BUILD_DIR=apps/web/dist (.env).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-11 08:32:28 +04:00

200 lines
6.5 KiB
JavaScript

const { ethers } = require('hardhat');
const { expect } = require('chai');
const { getAddressInSlot, ImplementationSlot } = require('../helpers/storage');
module.exports = function shouldBehaveLikeProxy({ allowUninitialized = false, allowNonContractAddress = false } = {}) {
if (!allowNonContractAddress) {
it('cannot be initialized with a non-contract address', async function () {
const initializeData = '0x00'; // non empty data to avoid uninitialized error
const contractFactory = await ethers.getContractFactory('ERC1967Proxy');
await expect(this.createProxy(this.nonContractAddress, initializeData))
.to.be.revertedWithCustomError(contractFactory, 'ERC1967InvalidImplementation')
.withArgs(this.nonContractAddress);
});
}
const assertProxyInitialization = function ({ value, balance }) {
it('sets the implementation address', async function () {
expect(await getAddressInSlot(this.proxy, ImplementationSlot)).to.equal(this.implementation);
});
it('initializes the proxy', async function () {
const dummy = this.implementation.attach(this.proxy);
expect(await dummy.value()).to.equal(value);
});
it('has expected balance', async function () {
expect(await ethers.provider.getBalance(this.proxy)).to.equal(balance);
});
};
describe('without initialization', function () {
if (allowUninitialized) {
const initializeData = '0x';
describe('when not sending balance', function () {
beforeEach('creating proxy', async function () {
this.proxy = await this.createProxy(this.implementation, initializeData);
});
assertProxyInitialization({ value: 0n, balance: 0n });
});
describe('when sending some balance', function () {
const value = 10n ** 5n;
it('reverts', async function () {
await expect(this.createProxy(this.implementation, initializeData, { value })).to.be.reverted;
});
});
} else {
it('reverts without initialization', async function () {
const initializeData = '0x'; // empty data causes uninitialized error
const contractFactory = await ethers.getContractFactory('ERC1967Proxy');
await expect(this.createProxy(this.implementation, initializeData)).to.be.revertedWithCustomError(
contractFactory,
'ERC1967ProxyUninitialized',
);
});
}
});
describe('initialization without parameters', function () {
describe('non payable', function () {
const expectedInitializedValue = 10n;
beforeEach(function () {
this.initializeData = this.implementation.interface.encodeFunctionData('initializeNonPayable');
});
describe('when not sending balance', function () {
beforeEach('creating proxy', async function () {
this.proxy = await this.createProxy(this.implementation, this.initializeData);
});
assertProxyInitialization({
value: expectedInitializedValue,
balance: 0n,
});
});
describe('when sending some balance', function () {
const value = 10n ** 5n;
it('reverts', async function () {
await expect(this.createProxy(this.implementation, this.initializeData, { value })).to.be.reverted;
});
});
});
describe('payable', function () {
const expectedInitializedValue = 100n;
beforeEach(function () {
this.initializeData = this.implementation.interface.encodeFunctionData('initializePayable');
});
describe('when not sending balance', function () {
beforeEach('creating proxy', async function () {
this.proxy = await this.createProxy(this.implementation, this.initializeData);
});
assertProxyInitialization({
value: expectedInitializedValue,
balance: 0n,
});
});
describe('when sending some balance', function () {
const value = 10e5;
beforeEach('creating proxy', async function () {
this.proxy = await this.createProxy(this.implementation, this.initializeData, { value });
});
assertProxyInitialization({
value: expectedInitializedValue,
balance: value,
});
});
});
});
describe('initialization with parameters', function () {
describe('non payable', function () {
const expectedInitializedValue = 10n;
beforeEach(function () {
this.initializeData = this.implementation.interface.encodeFunctionData('initializeNonPayableWithValue', [
expectedInitializedValue,
]);
});
describe('when not sending balance', function () {
beforeEach('creating proxy', async function () {
this.proxy = await this.createProxy(this.implementation, this.initializeData);
});
assertProxyInitialization({
value: expectedInitializedValue,
balance: 0,
});
});
describe('when sending some balance', function () {
const value = 10e5;
it('reverts', async function () {
await expect(this.createProxy(this.implementation, this.initializeData, { value })).to.be.reverted;
});
});
});
describe('payable', function () {
const expectedInitializedValue = 42n;
beforeEach(function () {
this.initializeData = this.implementation.interface.encodeFunctionData('initializePayableWithValue', [
expectedInitializedValue,
]);
});
describe('when not sending balance', function () {
beforeEach('creating proxy', async function () {
this.proxy = await this.createProxy(this.implementation, this.initializeData);
});
assertProxyInitialization({
value: expectedInitializedValue,
balance: 0n,
});
});
describe('when sending some balance', function () {
const value = 10n ** 5n;
beforeEach('creating proxy', async function () {
this.proxy = await this.createProxy(this.implementation, this.initializeData, { value });
});
assertProxyInitialization({
value: expectedInitializedValue,
balance: value,
});
});
});
describe('reverting initialization', function () {
beforeEach(function () {
this.initializeData = this.implementation.interface.encodeFunctionData('reverts');
});
it('reverts', async function () {
await expect(this.createProxy(this.implementation, this.initializeData)).to.be.reverted;
});
});
});
};