Skip to content

Commit

Permalink
Merge pull request #51 from gildlab/2023-02-12-sweep
Browse files Browse the repository at this point in the history
2023 02 12 sweep
  • Loading branch information
thedavidmeister committed Feb 12, 2023
2 parents aa50489 + e06d974 commit 6fba1dd
Show file tree
Hide file tree
Showing 9 changed files with 161 additions and 47 deletions.
2 changes: 1 addition & 1 deletion contracts/oracle/price/TwoPriceOracleFactory.sol
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ contract TwoPriceOracleFactory is Factory {
/// parameters are already encoded.
///
/// @param config_ Config for the oracle.
/// @return New `ChainlinkFeedPriceOracle` child contract address.
/// @return New `TwoPriceOracle` child contract address.
function createChildTyped(
TwoPriceOracleConfig memory config_
) external returns (TwoPriceOracle) {
Expand Down
10 changes: 8 additions & 2 deletions contracts/test/TestReceiptOwner.sol
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ contract TestReceiptOwner is IReceiptOwnerV1 {
uint256 amount_,
bytes memory data_
) external {
receipt_.ownerMint(account_, id_, amount_, data_);
receipt_.ownerMint(msg.sender, account_, id_, amount_, data_);
}

/// Exposes `IReceiptV1.ownerBurn` to anon.
Expand All @@ -74,7 +74,13 @@ contract TestReceiptOwner is IReceiptOwnerV1 {
uint256 amount_,
bytes memory receiptInformation_
) external {
receipt_.ownerBurn(account_, id_, amount_, receiptInformation_);
receipt_.ownerBurn(
msg.sender,
account_,
id_,
amount_,
receiptInformation_
);
}

/// Exposes `IReceiptV1.ownerTransferFrom` to anon.
Expand Down
66 changes: 36 additions & 30 deletions contracts/vault/offchainAsset/OffchainAssetReceiptVault.sol
Original file line number Diff line number Diff line change
Expand Up @@ -446,6 +446,7 @@ contract OffchainAssetReceiptVault is ReceiptVault, AccessControl {
/// mint new ERC20 shares and also increase the held receipt amount 1:1.
/// @param receiptInformation_ Forwarded to receipt mint and
/// `receiptInformation`.
/// @return shares_ As per IERC4626 `deposit`.
function redeposit(
uint256 assets_,
address receiver_,
Expand All @@ -456,18 +457,15 @@ contract OffchainAssetReceiptVault is ReceiptVault, AccessControl {
if (id_ > highwaterId) {
revert InvalidId(id_);
}
_deposit(

uint256 shares_ = _calculateDeposit(
assets_,
receiver_,
_calculateDeposit(
assets_,
_shareRatio(msg.sender, receiver_, id_, ShareAction.Mint),
0
),
id_,
receiptInformation_
_shareRatio(msg.sender, receiver_, id_, ShareAction.Mint),
0
);
return assets_;

_deposit(assets_, receiver_, shares_, id_, receiptInformation_);
return shares_;
}

/// Exposes `ERC20Snapshot` from Open Zeppelin behind a role restricted call.
Expand Down Expand Up @@ -637,11 +635,14 @@ contract OffchainAssetReceiptVault is ReceiptVault, AccessControl {
return;
}

// Minting and burning is always allowed as it is controlled via. RBAC
// separately to the tier contracts. Minting and burning is ALSO valid
// after the certification expires as it is likely the only way to
// Minting and burning is always allowed for the respective roles if they
// interact directly with the shares/receipt. Minting and burning is ALSO
// valid after the certification expires as it is likely the only way to
// repair the system and bring it back to a certifiable state.
if (from_ == address(0) || to_ == address(0)) {
if (
(from_ == address(0) && hasRole(DEPOSITOR, to_)) ||
(to_ == address(0) && hasRole(WITHDRAWER, from_))
) {
return;
}

Expand All @@ -665,23 +666,28 @@ contract OffchainAssetReceiptVault is ReceiptVault, AccessControl {

// If there is a tier contract we enforce it.
if (address(tier_) != address(0) && minimumTier_ > 0) {
// The sender must have a valid tier.
uint256 fromReportTime_ = tier_.reportTimeForTier(
from_,
minimumTier_,
tierContext_
);
if (block.timestamp < fromReportTime_) {
revert UnauthorizedSenderTier(from_, fromReportTime_);
if (from_ != address(0)) {
// The sender must have a valid tier.
uint256 fromReportTime_ = tier_.reportTimeForTier(
from_,
minimumTier_,
tierContext_
);
if (block.timestamp < fromReportTime_) {
revert UnauthorizedSenderTier(from_, fromReportTime_);
}
}
// The recipient must have a valid tier.
uint256 toReportTime_ = tier_.reportTimeForTier(
to_,
minimumTier_,
tierContext_
);
if (block.timestamp < toReportTime_) {
revert UnauthorizedRecipientTier(to_, toReportTime_);

if (to_ != address(0)) {
// The recipient must have a valid tier.
uint256 toReportTime_ = tier_.reportTimeForTier(
to_,
minimumTier_,
tierContext_
);
if (block.timestamp < toReportTime_) {
revert UnauthorizedRecipientTier(to_, toReportTime_);
}
}
}
}
Expand Down
10 changes: 8 additions & 2 deletions contracts/vault/receipt/IReceiptV1.sol
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,15 @@ interface IReceiptV1 is IERC1155 {
/// The owner MAY directly mint receipts for any account, ID and amount
/// without restriction. The data MUST be treated as both ERC1155 data and
/// receipt information. Overflow MUST revert as usual for ERC1155.
/// MUST REVERT if the `msg.sender` is NOT the owner.
/// MUST REVERT if the `msg.sender` is NOT the owner. Receipt information
/// MUST be emitted under the sender not the receiver account.
/// @param sender The sender to emit receipt information under.
/// @param account The account to mint a receipt for.
/// @param id The receipt ID to mint.
/// @param amount The amount to mint for the `id`.
/// @param data The ERC1155 data. MUST be emitted as receipt information.
function ownerMint(
address sender,
address account,
uint256 id,
uint256 amount,
Expand All @@ -54,12 +57,15 @@ interface IReceiptV1 is IERC1155 {

/// The owner MAY directly burn receipts for any account, ID and amount
/// without restriction. Underflow MUST revert as usual for ERC1155.
/// MUST REVERT if the `msg.sender` is NOT the owner.
/// MUST REVERT if the `msg.sender` is NOT the owner. Receipt information
/// MUST be emitted under the sender not the receipt owner account.
/// @param sender The sender to emit receipt information under.
/// @param account The account to burn a receipt for.
/// @param id The receipt ID to burn.
/// @param amount The amount to mint for the `id`.
/// @param data MUST be emitted as receipt information.
function ownerBurn(
address sender,
address account,
uint256 id,
uint256 amount,
Expand Down
6 changes: 4 additions & 2 deletions contracts/vault/receipt/Receipt.sol
Original file line number Diff line number Diff line change
Expand Up @@ -41,23 +41,25 @@ contract Receipt is IReceiptV1, Ownable, ERC1155 {

/// @inheritdoc IReceiptV1
function ownerMint(
address sender_,
address account_,
uint256 id_,
uint256 amount_,
bytes memory data_
) external virtual onlyOwner {
_receiptInformation(account_, id_, data_);
_receiptInformation(sender_, id_, data_);
_mint(account_, id_, amount_, data_);
}

/// @inheritdoc IReceiptV1
function ownerBurn(
address sender_,
address account_,
uint256 id_,
uint256 amount_,
bytes memory data_
) external virtual onlyOwner {
_receiptInformation(account_, id_, data_);
_receiptInformation(sender_, id_, data_);
_burn(account_, id_, amount_);
}

Expand Down
24 changes: 15 additions & 9 deletions contracts/vault/receipt/ReceiptVault.sol
Original file line number Diff line number Diff line change
Expand Up @@ -547,16 +547,10 @@ contract ReceiptVault is
bytes memory receiptInformation_
) public returns (uint256) {
uint256 id_ = _nextId();
uint256 shareRatio_ = _shareRatio(
msg.sender,
receiver_,
id_,
ShareAction.Mint
);

uint256 shares_ = _calculateDeposit(
assets_,
shareRatio_,
_shareRatio(msg.sender, receiver_, id_, ShareAction.Mint),
depositMinShareRatio_
);

Expand Down Expand Up @@ -615,7 +609,13 @@ contract ReceiptVault is

// erc1155 mint.
// Receiving contracts MUST implement `IERC1155Receiver`.
_receipt.ownerMint(receiver_, id_, shares_, receiptInformation_);
_receipt.ownerMint(
msg.sender,
receiver_,
id_,
shares_,
receiptInformation_
);
}

/// Hook for additional actions that MUST complete or revert before deposit
Expand Down Expand Up @@ -856,7 +856,13 @@ contract ReceiptVault is
_burn(owner_, shares_);

// ERC1155 burn.
_receipt.ownerBurn(owner_, id_, shares_, receiptInformation_);
_receipt.ownerBurn(
msg.sender,
owner_,
id_,
shares_,
receiptInformation_
);

// Hook to allow additional withdrawal checks.
_afterWithdraw(assets_, receiver_, owner_, shares_, id_);
Expand Down
2 changes: 1 addition & 1 deletion test/IPFSPull.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ describe("IPFS pull", async function () {
const resp = await fetch(
"https://ipfs.io/ipfs/bafkreih7cvpjocgrk7mgdel2hvjpquc26j4jo2jkez5y2qdaojfil7vley"
);
const ipfsData = await resp.json();
const ipfsData = await resp.json().catch(console.error);

assert(
ipfsData.name === erc1155Metadata.name,
Expand Down
77 changes: 77 additions & 0 deletions test/offchainAsset/OffChainAssetReceiptVault.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import {
deployOffchainAssetReceiptVaultFactory,
} from "./deployOffchainAssetReceiptVault";
import { DepositWithReceiptEvent } from "../../typechain-types/contracts/vault/receipt/ReceiptVault";
import { ReceiptInformationEvent } from "../../typechain-types/contracts/vault/receipt/Receipt";

const assert = require("assert");

Expand Down Expand Up @@ -201,6 +202,17 @@ describe("OffChainAssetReceiptVault", async function () {
.connect(alice)
.grantRole(await vault.connect(alice).DEPOSITOR(), alice.address);

const blockNum = await ethers.provider.getBlockNumber();
const block = await ethers.provider.getBlock(blockNum);
const _until = block.timestamp + 100;
const _referenceBlockNumber = block.number;

await vault
.connect(alice)
.grantRole(await vault.connect(alice).CERTIFIER(), bob.address);

await vault.connect(bob).certify(_until, _referenceBlockNumber, false, []);

await vault
.connect(alice)
["deposit(uint256,address,uint256,bytes)"](
Expand Down Expand Up @@ -1076,12 +1088,18 @@ describe("OffChainAssetReceiptVault", async function () {
`wrong confiscated expected ${shares} got ${confiscated}`
);
});

it("Checks confiscated is transferred", async function () {
const signers = await ethers.getSigners();
const alice = signers[0];
const bob = signers[1];
const [vault] = await deployOffChainAssetReceiptVault();

const blockNum = await ethers.provider.getBlockNumber();
const block = await ethers.provider.getBlock(blockNum);
const _certifiedUntil = block.timestamp + 100;
const _referenceBlockNumber = block.number;

const testErc20 = await ethers.getContractFactory("TestErc20");
const asset = (await testErc20.deploy()) as TestErc20;
await asset.deployed();
Expand All @@ -1101,6 +1119,13 @@ describe("OffChainAssetReceiptVault", async function () {
.connect(alice)
.increaseAllowance(vault.connect(alice).address, assets);

await vault
.connect(alice)
.grantRole(await vault.connect(alice).CERTIFIER(), alice.address);
await vault
.connect(alice)
.certify(_certifiedUntil, _referenceBlockNumber, false, []);

await vault
.connect(alice)
["deposit(uint256,address,uint256,bytes)"](assets, bob.address, ONE, []);
Expand All @@ -1122,6 +1147,7 @@ describe("OffChainAssetReceiptVault", async function () {
`Shares has not been confiscated`
);
});

it("Checks confiscated is same as receipt balance", async function () {
const signers = await ethers.getSigners();
const [vault, receipt] = await deployOffChainAssetReceiptVault();
Expand Down Expand Up @@ -1528,4 +1554,55 @@ describe("OffChainAssetReceiptVault", async function () {
"Failed to mint"
);
});
it("Check the receipt info sender when depositor mints for a different receiver", async () => {
const signers = await ethers.getSigners();
const alice = signers[0];
const bob = signers[1];

const [vault, receipt] = await deployOffChainAssetReceiptVault();

const testErc20 = await ethers.getContractFactory("TestErc20");
const asset = (await testErc20.deploy()) as TestErc20;
await asset.deployed();

const aliceAmount = ethers.BigNumber.from(5000);
await asset.transfer(alice.address, aliceAmount);
await asset.connect(alice).increaseAllowance(vault.address, aliceAmount);

const expectedId = 1;

const informationBytes = [125, 126];
await vault
.connect(alice)
.grantRole(await vault.connect(alice).DEPOSITOR(), alice.address);

const blockNum = await ethers.provider.getBlockNumber();
const block = await ethers.provider.getBlock(blockNum);
const _until = block.timestamp + 100;
const _referenceBlockNumber = block.number;

await vault
.connect(alice)
.grantRole(await vault.connect(alice).CERTIFIER(), bob.address);

await vault.connect(bob).certify(_until, _referenceBlockNumber, false, []);

const { sender } = (await getEventArgs(
await vault
.connect(alice)
["deposit(uint256,address,uint256,bytes)"](
aliceAmount,
bob.address,
expectedId,
informationBytes
),
"ReceiptInformation",
receipt
)) as ReceiptInformationEvent["args"];

assert(
sender === alice.address,
`wrong receipt information sender ${alice.address} got ${sender}`
);
});
});
11 changes: 11 additions & 0 deletions test/offchainAsset/Roles.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,17 @@ describe("OffChainAssetReceiptVault Roles", async function () {
.connect(alice)
.grantRole(await vault.connect(alice).DEPOSITOR(), alice.address);

const blockNum = await ethers.provider.getBlockNumber();
const block = await ethers.provider.getBlock(blockNum);
const _until = block.timestamp + 100;
const _referenceBlockNumber = block.number;

await vault
.connect(alice)
.grantRole(await vault.connect(alice).CERTIFIER(), bob.address);

await vault.connect(bob).certify(_until, _referenceBlockNumber, false, []);

await vault
.connect(alice)
["deposit(uint256,address,uint256,bytes)"](
Expand Down

0 comments on commit 6fba1dd

Please sign in to comment.