Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

77 test coverage for handler #101

Merged
merged 15 commits into from
Jul 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions test/foundry/abstract/OffchainAssetReceiptVaultTest.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,16 @@ import {Test, Vm} from "forge-std/Test.sol";
import {ICloneableFactoryV2} from "rain.factory/interface/ICloneableFactoryV2.sol";
import {CloneFactory} from "rain.factory/concrete/CloneFactory.sol";
import {
OffchainAssetReceiptVaultConfig,
OffchainAssetReceiptVault,
ReceiptVaultConstructionConfig
} from "contracts/concrete/vault/OffchainAssetReceiptVault.sol";
import {LibOffchainAssetVaultCreator} from "../lib/LibOffchainAssetVaultCreator.sol";
import {Receipt as ReceiptContract} from "contracts/concrete/receipt/Receipt.sol";

contract OffchainAssetReceiptVaultTest is Test {
event OffchainAssetReceiptVaultInitialized(address sender, OffchainAssetReceiptVaultConfig config);

ICloneableFactoryV2 internal immutable iFactory;
OffchainAssetReceiptVault internal immutable iImplementation;
ReceiptContract internal immutable receiptImplementation;
Expand All @@ -30,4 +33,22 @@ contract OffchainAssetReceiptVaultTest is Test {
{
return LibOffchainAssetVaultCreator.createVault(iFactory, iImplementation, admin, name, symbol);
}

function getReceipt(Vm.Log[] memory logs) internal pure returns (ReceiptContract) {
// Find the OffchainAssetReceiptVaultInitialized event log
address receiptAddress = address(0);
bool eventFound = false; // Flag to indicate whether the event log was found
for (uint256 i = 0; i < logs.length; i++) {
if (logs[i].topics[0] == OffchainAssetReceiptVaultInitialized.selector) {
// Decode the event data
(, OffchainAssetReceiptVaultConfig memory config) =
abi.decode(logs[i].data, (address, OffchainAssetReceiptVaultConfig));
receiptAddress = config.receiptVaultConfig.receipt;
eventFound = true; // Set the flag to true since event log was found
break;
}
}
// Return an receipt contract
return ReceiptContract(receiptAddress);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,31 +10,6 @@ import {Receipt as ReceiptContract} from "../../../../../contracts/concrete/rece

contract ConfiscateReceiptTest is OffchainAssetReceiptVaultTest {
event ConfiscateReceipt(address sender, address confiscatee, uint256 id, uint256 confiscated, bytes justification);
event OffchainAssetReceiptVaultInitialized(address sender, OffchainAssetReceiptVaultConfig config);

/// Get Receipt from event
function getReceipt() internal returns (ReceiptContract) {
Vm.Log[] memory logs = vm.getRecordedLogs();

// Find the OffchainAssetReceiptVaultInitialized event log
address receiptAddress = address(0);
bool eventFound = false; // Flag to indicate whether the event log was found
for (uint256 i = 0; i < logs.length; i++) {
if (logs[i].topics[0] == OffchainAssetReceiptVaultInitialized.selector) {
// Decode the event data
(, OffchainAssetReceiptVaultConfig memory config) =
abi.decode(logs[i].data, (address, OffchainAssetReceiptVaultConfig));
receiptAddress = config.receiptVaultConfig.receipt;
eventFound = true; // Set the flag to true since event log was found
break;
}
}

// Assert that the event log was found
assertTrue(eventFound, "OffchainAssetReceiptVaultInitialized event log not found");
// Return an receipt contract
return ReceiptContract(receiptAddress);
}

/// Checks that confiscateReceipt balances don't change or do change as expected
function checkConfiscateReceipt(
Expand Down Expand Up @@ -91,7 +66,9 @@ contract ConfiscateReceiptTest is OffchainAssetReceiptVaultTest {
// Start recording logs
vm.recordLogs();
OffchainAssetReceiptVault vault = createVault(alice, assetName, assetSymbol);
ReceiptContract receipt = getReceipt();
Vm.Log[] memory logs = vm.getRecordedLogs();
ReceiptContract receipt = getReceipt(logs);

// Prank as Alice to grant role
vm.startPrank(alice);

Expand All @@ -117,6 +94,7 @@ contract ConfiscateReceiptTest is OffchainAssetReceiptVaultTest {
// Ensure the fuzzed key is within the valid range for secp256k1
address alice = vm.addr((fuzzedKeyAlice % (SECP256K1_ORDER - 1)) + 1);
address bob = vm.addr((fuzzedKeyBob % (SECP256K1_ORDER - 1)) + 1);
vm.assume(alice != bob);

blockNumber = bound(blockNumber, 0, type(uint256).max);
vm.roll(blockNumber);
Expand All @@ -126,11 +104,11 @@ contract ConfiscateReceiptTest is OffchainAssetReceiptVaultTest {

// Assume that assets is less than uint256 max
assets = bound(assets, 1, type(uint256).max);

// Start recording logs
vm.recordLogs();
OffchainAssetReceiptVault vault = createVault(alice, assetName, assetName);
ReceiptContract receipt = getReceipt();
vm.assume(alice != bob);
Vm.Log[] memory logs = vm.getRecordedLogs();

// Prank as Alice to set roles
vm.startPrank(alice);
Expand All @@ -146,7 +124,7 @@ contract ConfiscateReceiptTest is OffchainAssetReceiptVaultTest {

vault.deposit(assets, alice, minShareRatio, data);

checkConfiscateReceipt(vault, receipt, alice, bob, 1, data);
checkConfiscateReceipt(vault, getReceipt(logs), alice, bob, 1, data);
vm.stopPrank();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import {Receipt as ReceiptContract} from "../../../../../contracts/concrete/rece

contract ConfiscateSharesTest is OffchainAssetReceiptVaultTest {
event ConfiscateShares(address sender, address confiscatee, uint256 confiscated, bytes justification);
event OffchainAssetReceiptVaultInitialized(address sender, OffchainAssetReceiptVaultConfig config);

/// Checks that confiscateShares balances don't change or do change as expected
function checkConfiscateShares(OffchainAssetReceiptVault vault, address alice, address bob, bytes memory data)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,208 @@
// SPDX-License-Identifier: CAL
pragma solidity =0.8.25;

import {OffchainAssetReceiptVault} from "../../../../../contracts/concrete/vault/OffchainAssetReceiptVault.sol";
import {OffchainAssetReceiptVaultTest, Vm} from "test/foundry/abstract/OffchainAssetReceiptVaultTest.sol";
import {LibOffchainAssetVaultCreator} from "test/foundry/lib/LibOffchainAssetVaultCreator.sol";
import {Receipt as ReceiptContract} from "../../../../../contracts/concrete/receipt/Receipt.sol";

contract OffchainAssetReceiptVaultHandlerTest is OffchainAssetReceiptVaultTest {
event SetERC20Tier(address sender, address tier, uint256 minimumTier, uint256[] context, bytes data);
event SetERC1155Tier(address sender, address tier, uint256 minimumTier, uint256[] context, bytes data);
event DepositWithReceipt(
address sender, address owner, uint256 assets, uint256 shares, uint256 id, bytes receiptInformation
);

function setUpAddressesAndBounds(
uint256 fuzzedKeyAlice,
uint256 fuzzedKeyBob,
uint256 fuzzedKeyJohn,
uint256 balance,
uint256 referenceBlockNumber,
uint256 certifyUntil
) internal view returns (address alice, address bob, address john, uint256, uint256, uint256) {
// Ensure the fuzzed key is within the valid range for secp256k
alice = vm.addr((fuzzedKeyAlice % (SECP256K1_ORDER - 1)) + 1);
bob = vm.addr((fuzzedKeyBob % (SECP256K1_ORDER - 1)) + 1);
john = vm.addr((fuzzedKeyJohn % (SECP256K1_ORDER - 1)) + 1);

balance = bound(balance, 1, type(uint256).max); // Bound from one to avoid ZeroAssets
referenceBlockNumber = bound(referenceBlockNumber, 1, block.number);
certifyUntil = bound(certifyUntil, 1, type(uint32).max - 1); // substruct 1 for next bound

return (alice, bob, john, balance, referenceBlockNumber, certifyUntil);
}

function setUpVault(address alice, string memory assetName, string memory assetSymbol)
internal
returns (OffchainAssetReceiptVault vault, ReceiptContract receipt)
{
vm.recordLogs();
vault = createVault(alice, assetName, assetSymbol);
Vm.Log[] memory logs = vm.getRecordedLogs();
receipt = getReceipt(logs);
return (vault, receipt);
}

/// Test testReceiptTransfer to self with handler role
function testReceiptTransferHandler(
uint256 fuzzedKeyAlice,
uint256 fuzzedKeyBob,
string memory assetName,
uint256 referenceBlockNumber,
uint256 certifyUntil,
uint256 futureTimeStamp,
bool forceUntil,
uint256 balance
) external {
address alice;
address bob;
(alice, bob,, balance, referenceBlockNumber, certifyUntil) =
setUpAddressesAndBounds(fuzzedKeyAlice, fuzzedKeyBob, 0, balance, referenceBlockNumber, certifyUntil);

// Need setting future timestamp so system gets unsertified but transfer is possible
// due to a handler role
futureTimeStamp = bound(futureTimeStamp, certifyUntil + 1, type(uint32).max);

vm.assume(alice != bob);

OffchainAssetReceiptVault vault;
ReceiptContract receipt;
(vault, receipt) = setUpVault(alice, assetName, assetName);

// Prank as Alice to grant roles
vm.startPrank(alice);

vault.grantRole(vault.CERTIFIER(), alice);
vault.grantRole(vault.HANDLER(), bob);
vault.grantRole(vault.DEPOSITOR(), alice);

// Call the certify function
vault.certify(certifyUntil, referenceBlockNumber, forceUntil, bytes(""));

vault.deposit(balance, bob, 1, bytes(""));

vm.stopPrank();
vm.warp(futureTimeStamp);

// Prank as Bob
vm.startPrank(bob);
vault.authorizeReceiptTransfer(bob, bob);
receipt.safeTransferFrom(bob, bob, 1, balance, bytes(""));
assertEq(receipt.balanceOf(bob, 1), balance);

vm.stopPrank();
}

/// Test testReceiptTransfer with Owner being a handler
function testReceiptTransferHandlerOwner(
uint256 fuzzedKeyAlice,
uint256 fuzzedKeyBob,
uint256 fuzzedKeyJohn,
string memory assetName,
uint256 referenceBlockNumber,
uint256 certifyUntil,
uint256 futureTimeStamp,
bool forceUntil,
uint256 balance
) external {
address alice;
address bob;
address john;
(alice, bob, john, balance, referenceBlockNumber, certifyUntil) = setUpAddressesAndBounds(
fuzzedKeyAlice, fuzzedKeyBob, fuzzedKeyJohn, balance, referenceBlockNumber, certifyUntil
);

// Need setting future timestamp so system gets uncertified but transfer is possible
// due to a handler role
futureTimeStamp = bound(futureTimeStamp, certifyUntil + 1, type(uint32).max);

vm.assume(alice != bob);
vm.assume(alice != john);
vm.assume(bob != john);

OffchainAssetReceiptVault vault;
ReceiptContract receipt;
(vault, receipt) = setUpVault(alice, assetName, assetName);

// Prank as Alice to grant roles
vm.startPrank(alice);

vault.grantRole(vault.CERTIFIER(), alice);
vault.grantRole(vault.HANDLER(), bob);
vault.grantRole(vault.DEPOSITOR(), alice);

// Call the certify function
vault.certify(certifyUntil, referenceBlockNumber, forceUntil, bytes(""));

// Cannot fuzz assets value due to variable limits
vault.deposit(balance, bob, 1, bytes(""));

vm.stopPrank();
vm.warp(futureTimeStamp);

// Prank as Bob
vm.startPrank(bob);
vault.authorizeReceiptTransfer(bob, john);
receipt.safeTransferFrom(bob, john, 1, balance, bytes(""));
assertEq(receipt.balanceOf(john, 1), balance);

vm.stopPrank();
}

/// Test testReceiptTransfer with Receiver being a handler
function testReceiptTransferHandlerReceiver(
uint256 fuzzedKeyAlice,
uint256 fuzzedKeyBob,
uint256 fuzzedKeyJohn,
string memory assetName,
uint256 referenceBlockNumber,
uint256 certifyUntil,
uint256 futureTimeStamp,
bool forceUntil,
uint256 balance
) external {
address alice;
address bob;
address john;
(alice, bob, john, balance, referenceBlockNumber, certifyUntil) = setUpAddressesAndBounds(
fuzzedKeyAlice, fuzzedKeyBob, fuzzedKeyJohn, balance, referenceBlockNumber, certifyUntil
);

// Need setting future timestamp so system gets uncertified but transfer is possible
// due to a handler role
futureTimeStamp = bound(futureTimeStamp, certifyUntil + 1, type(uint32).max);

vm.assume(alice != bob);
vm.assume(alice != john);
vm.assume(bob != john);

OffchainAssetReceiptVault vault;
ReceiptContract receipt;
(vault, receipt) = setUpVault(alice, assetName, assetName);

// Prank as Alice to grant roles
vm.startPrank(alice);

vault.grantRole(vault.CERTIFIER(), alice);
vault.grantRole(vault.HANDLER(), john);
vault.grantRole(vault.DEPOSITOR(), alice);

// Call the certify function
vault.certify(certifyUntil, referenceBlockNumber, forceUntil, bytes(""));

// Cannot fuzz assets value due to variable limits
vault.deposit(balance, bob, 1, bytes(""));

vm.stopPrank();
vm.warp(futureTimeStamp);

// Prank as Bob
vm.startPrank(bob);
vault.authorizeReceiptTransfer(bob, john);
receipt.safeTransferFrom(bob, john, 1, balance, bytes(""));
assertEq(receipt.balanceOf(john, 1), balance);

vm.stopPrank();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,36 +10,10 @@ import {OffchainAssetReceiptVaultTest, Vm} from "test/foundry/abstract/OffchainA
import {LibOffchainAssetVaultCreator} from "test/foundry/lib/LibOffchainAssetVaultCreator.sol";
import {ITierV2} from "rain.tier.interface/interface/ITierV2.sol";
import {Receipt as ReceiptContract} from "../../../../../contracts/concrete/receipt/Receipt.sol";
import "forge-std/console.sol";

contract TiersTest is OffchainAssetReceiptVaultTest {
event SetERC20Tier(address sender, address tier, uint256 minimumTier, uint256[] context, bytes data);
event SetERC1155Tier(address sender, address tier, uint256 minimumTier, uint256[] context, bytes data);
event OffchainAssetReceiptVaultInitialized(address sender, OffchainAssetReceiptVaultConfig config);

/// Get Receipt from event
function getReceipt() internal returns (ReceiptContract) {
Vm.Log[] memory logs = vm.getRecordedLogs();

// Find the OffchainAssetReceiptVaultInitialized event log
address receiptAddress = address(0);
bool eventFound = false; // Flag to indicate whether the event log was found
for (uint256 i = 0; i < logs.length; i++) {
if (logs[i].topics[0] == OffchainAssetReceiptVaultInitialized.selector) {
// Decode the event data
(, OffchainAssetReceiptVaultConfig memory config) =
abi.decode(logs[i].data, (address, OffchainAssetReceiptVaultConfig));
receiptAddress = config.receiptVaultConfig.receipt;
eventFound = true; // Set the flag to true since event log was found
break;
}
}

// Assert that the event log was found
assertTrue(eventFound, "OffchainAssetReceiptVaultInitialized event log not found");
// Return an receipt contract
return ReceiptContract(receiptAddress);
}

/// Test setERC20Tier event
function testSetERC20Tier(
Expand Down Expand Up @@ -391,7 +365,7 @@ contract TiersTest is OffchainAssetReceiptVaultTest {
// Start recording logs
vm.recordLogs();
OffchainAssetReceiptVault vault = createVault(alice, assetName, assetName);
ReceiptContract receipt = getReceipt();
Vm.Log[] memory logs = vm.getRecordedLogs();

// Prank as Alice to grant roles
vm.startPrank(alice);
Expand Down Expand Up @@ -423,6 +397,7 @@ contract TiersTest is OffchainAssetReceiptVaultTest {
);

vault.authorizeReceiptTransfer(bob, alice);
ReceiptContract receipt = getReceipt(logs);

receipt.safeTransferFrom(bob, alice, 1, 10, bytes(""));
assertEq(receipt.balanceOf(alice, 1), 10);
Expand Down
Loading