Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin' into fix-docs
Browse files Browse the repository at this point in the history
  • Loading branch information
dimpar committed May 8, 2024
2 parents 9ff0eb0 + 34015e9 commit 72bfcca
Show file tree
Hide file tree
Showing 6 changed files with 218 additions and 59 deletions.
5 changes: 3 additions & 2 deletions solidity/contracts/MezoAllocator.sol
Original file line number Diff line number Diff line change
Expand Up @@ -240,9 +240,10 @@ contract MezoAllocator is IDispatcher, Ownable2StepUpgradeable {
emit MaintainerRemoved(maintainerToRemove);
}

/// @notice Returns the total amount of tBTC allocated to MezoPortal.
/// @notice Returns the total amount of tBTC allocated to MezoPortal including
/// the amount that is currently hold by this contract.
function totalAssets() external view returns (uint256) {
return depositBalance;
return depositBalance + tbtc.balanceOf(address(this));
}

/// @notice Returns the list of maintainers.
Expand Down
7 changes: 7 additions & 0 deletions solidity/contracts/PausableOwnable.sol
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ abstract contract PausableOwnable is
/// mechanism.
error PausableUnauthorizedAccount(address account);

/// @notice Reverts when the new pause admin address is the same as the
/// current pause admin address.
error SamePauseAdmin();

/// @notice Reverts if called by any account other than the pause admin
/// or the contract owner.
modifier onlyPauseAdminOrOwner() {
Expand Down Expand Up @@ -95,6 +99,9 @@ abstract contract PausableOwnable is
if (newPauseAdmin == address(0)) {
revert ZeroAddress();
}
if (newPauseAdmin == pauseAdmin) {
revert SamePauseAdmin();
}

emit PauseAdminUpdated(newPauseAdmin, pauseAdmin);

Expand Down
12 changes: 12 additions & 0 deletions solidity/contracts/stBTC.sol
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,12 @@ contract stBTC is ERC4626Fees, PausableOwnable {
/// Reverts if the address is disallowed.
error DisallowedAddress();

/// Reverts if the treasury address is the same.
error SameTreasury();

/// Reverts if the dispatcher address is the same.
error SameDispatcher();

/// @custom:oz-upgrades-unsafe-allow constructor
constructor() {
_disableInitializers();
Expand Down Expand Up @@ -104,6 +110,9 @@ contract stBTC is ERC4626Fees, PausableOwnable {
if (newTreasury == address(this)) {
revert DisallowedAddress();
}
if (newTreasury == treasury) {
revert SameTreasury();
}

emit TreasuryUpdated(treasury, newTreasury);

Expand All @@ -128,6 +137,9 @@ contract stBTC is ERC4626Fees, PausableOwnable {
if (address(newDispatcher) == address(0)) {
revert ZeroAddress();
}
if (address(newDispatcher) == address(dispatcher)) {
revert SameDispatcher();
}

address oldDispatcher = address(dispatcher);

Expand Down
5 changes: 3 additions & 2 deletions solidity/contracts/test/upgrades/MezoAllocatorV2.sol
Original file line number Diff line number Diff line change
Expand Up @@ -238,9 +238,10 @@ contract MezoAllocatorV2 is IDispatcher, Ownable2StepUpgradeable {
emit MaintainerRemoved(maintainerToRemove);
}

/// @notice Returns the total amount of tBTC allocated to MezoPortal.
/// @notice Returns the total amount of tBTC allocated to MezoPortal including
/// the amount that is currently hold by this contract.
function totalAssets() external view returns (uint256) {
return depositBalance;
return depositBalance + tbtc.balanceOf(address(this));
}

/// @notice Returns the list of maintainers.
Expand Down
222 changes: 167 additions & 55 deletions solidity/test/MezoAllocator.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,13 @@ const { getNamedSigners, getUnnamedSigners } = helpers.signers
async function fixture() {
const { tbtc, stbtc, mezoAllocator, mezoPortal } = await deployment()
const { governance, maintainer } = await getNamedSigners()
const [depositor, thirdParty] = await getUnnamedSigners()
const [depositor, depositor2, thirdParty] = await getUnnamedSigners()

return {
governance,
thirdParty,
depositor,
depositor2,
maintainer,
tbtc,
stbtc,
Expand All @@ -42,13 +43,15 @@ describe("MezoAllocator", () => {

let thirdParty: HardhatEthersSigner
let depositor: HardhatEthersSigner
let depositor2: HardhatEthersSigner
let maintainer: HardhatEthersSigner
let governance: HardhatEthersSigner

before(async () => {
;({
thirdParty,
depositor,
depositor2,
maintainer,
governance,
tbtc,
Expand All @@ -70,84 +73,175 @@ describe("MezoAllocator", () => {
})

context("when the caller is maintainer", () => {
context("when a first deposit is made", () => {
let tx: ContractTransactionResponse
context("when two consecutive deposits are made", () => {
beforeAfterSnapshotWrapper()

before(async () => {
await tbtc.mint(await stbtc.getAddress(), to1e18(6))
tx = await mezoAllocator.connect(maintainer).allocate()
})
context("when a first deposit is made", () => {
let tx: ContractTransactionResponse

it("should deposit and transfer tBTC to Mezo Portal", async () => {
await expect(tx).to.changeTokenBalances(
tbtc,
[await mezoPortal.getAddress()],
[to1e18(6)],
)
})
before(async () => {
await tbtc.mint(await stbtc.getAddress(), to1e18(6))
tx = await mezoAllocator.connect(maintainer).allocate()
})

it("should not store any tBTC in Mezo Allocator", async () => {
expect(
await tbtc.balanceOf(await mezoAllocator.getAddress()),
).to.equal(0)
})
it("should deposit and transfer tBTC to Mezo Portal", async () => {
await expect(tx).to.changeTokenBalances(
tbtc,
[await mezoPortal.getAddress()],
[to1e18(6)],
)
})

it("should increment the deposit id", async () => {
const actualDepositId = await mezoAllocator.depositId()
expect(actualDepositId).to.equal(1)
})
it("should not store any tBTC in Mezo Allocator", async () => {
expect(
await tbtc.balanceOf(await mezoAllocator.getAddress()),
).to.equal(0)
})

it("should increase tracked deposit balance amount", async () => {
const depositBalance = await mezoAllocator.depositBalance()
expect(depositBalance).to.equal(to1e18(6))
it("should increment the deposit id", async () => {
const actualDepositId = await mezoAllocator.depositId()
expect(actualDepositId).to.equal(1)
})

it("should increase tracked deposit balance amount", async () => {
const depositBalance = await mezoAllocator.depositBalance()
expect(depositBalance).to.equal(to1e18(6))
})

it("should emit DepositAllocated event", async () => {
await expect(tx)
.to.emit(mezoAllocator, "DepositAllocated")
.withArgs(0, 1, to1e18(6), to1e18(6))
})
})

it("should emit DepositAllocated event", async () => {
await expect(tx)
.to.emit(mezoAllocator, "DepositAllocated")
.withArgs(0, 1, to1e18(6), to1e18(6))
context("when a second deposit is made", () => {
let tx: ContractTransactionResponse

before(async () => {
await tbtc.mint(await stbtc.getAddress(), to1e18(5))

tx = await mezoAllocator.connect(maintainer).allocate()
})

it("should increment the deposit id", async () => {
const actualDepositId = await mezoAllocator.depositId()
expect(actualDepositId).to.equal(2)
})

it("should emit DepositAllocated event", async () => {
await expect(tx)
.to.emit(mezoAllocator, "DepositAllocated")
.withArgs(1, 2, to1e18(5), to1e18(11))
})

it("should deposit and transfer tBTC to Mezo Portal", async () => {
expect(
await tbtc.balanceOf(await mezoPortal.getAddress()),
).to.equal(to1e18(11))
})

it("should increase tracked deposit balance amount", async () => {
const depositBalance = await mezoAllocator.depositBalance()
expect(depositBalance).to.equal(to1e18(11))
})

it("should not store any tBTC in Mezo Allocator", async () => {
expect(
await tbtc.balanceOf(await mezoAllocator.getAddress()),
).to.equal(0)
})

it("should not store any tBTC in stBTC", async () => {
expect(await tbtc.balanceOf(await stbtc.getAddress())).to.equal(0)
})
})
})

context("when a second deposit is made", () => {
let tx: ContractTransactionResponse
context("when accounting for tBTC 'donation' to Mezo Allocator", () => {
let depositorDepositTx: ContractTransactionResponse
let depositorRedeemTx: ContractTransactionResponse
let depositor2DepositTx: ContractTransactionResponse
let depositor2RedeemTx: ContractTransactionResponse

beforeAfterSnapshotWrapper()

before(async () => {
await tbtc.mint(await stbtc.getAddress(), to1e18(5))
await tbtc.mint(depositor, to1e18(1))
await tbtc
.connect(depositor)
.approve(await stbtc.getAddress(), to1e18(1))
// Deposit by the first depositor
depositorDepositTx = await stbtc
.connect(depositor)
.deposit(to1e18(1), depositor)

// Mezo Portal first allocation
await mezoAllocator.connect(maintainer).allocate()

tx = await mezoAllocator.connect(maintainer).allocate()
})
// Donation / rewards
await tbtc.mint(await mezoAllocator.getAddress(), to1e18(1))

await tbtc.mint(depositor2, to1e18(1))
await tbtc
.connect(depositor2)
.approve(await stbtc.getAddress(), to1e18(1))
// Deposit by the second depositor
depositor2DepositTx = await stbtc
.connect(depositor2)
.deposit(to1e18(1), depositor2)
// Mezo Portal second allocation
await mezoAllocator.connect(maintainer).allocate()

it("should increment the deposit id", async () => {
const actualDepositId = await mezoAllocator.depositId()
expect(actualDepositId).to.equal(2)
})
// Redeeming shares by the first depositor
const stBTCdepositorBalance = await stbtc.balanceOf(depositor)
depositorRedeemTx = await stbtc
.connect(depositor)
.redeem(stBTCdepositorBalance, depositor, depositor)

it("should emit DepositAllocated event", async () => {
await expect(tx)
.to.emit(mezoAllocator, "DepositAllocated")
.withArgs(1, 2, to1e18(5), to1e18(11))
// Redeeming shares by the second depositor
const stBTCdepositor2Balance = await stbtc.balanceOf(depositor2)
depositor2RedeemTx = await stbtc
.connect(depositor2)
.redeem(stBTCdepositor2Balance, depositor2, depositor2)
})

it("should deposit and transfer tBTC to Mezo Portal", async () => {
expect(await tbtc.balanceOf(await mezoPortal.getAddress())).to.equal(
to1e18(11),
it("should mint correct amount of shares for the first depositor", async () => {
await expect(depositorDepositTx).to.changeTokenBalances(
stbtc,
[depositor.address],
[to1e18(1)],
)
})

it("should increase tracked deposit balance amount", async () => {
const depositBalance = await mezoAllocator.depositBalance()
expect(depositBalance).to.equal(to1e18(11))
it("should mint correct amount of shares for the second depositor", async () => {
// expected shares = (assets * total supply of shares) / total assets
// expected shares = (1 * 1 stBTC) / 2 tBTC = 0.5
await expect(depositor2DepositTx).to.changeTokenBalances(
stbtc,
[depositor2.address],
[500000000000000000n], // 0.5 stBTC
)
})

it("should not store any tBTC in Mezo Allocator", async () => {
expect(
await tbtc.balanceOf(await mezoAllocator.getAddress()),
).to.equal(0)
it("should redeem shares with accounting for 'donation' for the first depositor", async () => {
// expected tBTC = shares * total assets / total supply of shares
// expected tBTC = (1 * 3) / 1.5 = 2
await expect(depositorRedeemTx).to.changeTokenBalances(
tbtc,
[depositor.address],
[to1e18(2) - 1n], // adjusted for rounding
)
})

it("should not store any tBTC in stBTC", async () => {
expect(await tbtc.balanceOf(await stbtc.getAddress())).to.equal(0)
it("should redeem shares without accounting for 'donation' for the second depositor", async () => {
// expected tBTC = shares * total assets / total supply of shares
// expected tBTC = (0.5 * 3) / 1.5 = 2
await expect(depositor2RedeemTx).to.changeTokenBalances(
tbtc,
[depositor2.address],
[to1e18(1)],
)
})
})
})
Expand Down Expand Up @@ -263,6 +357,8 @@ describe("MezoAllocator", () => {
})

context("when there is a deposit", () => {
beforeAfterSnapshotWrapper()

before(async () => {
await tbtc.mint(await stbtc.getAddress(), to1e18(5))
await mezoAllocator.connect(maintainer).allocate()
Expand All @@ -278,6 +374,22 @@ describe("MezoAllocator", () => {
expect(await mezoAllocator.totalAssets()).to.equal(depositBalance)
})
})

context("when there is a deposit plus 'donation' made", () => {
beforeAfterSnapshotWrapper()

before(async () => {
await tbtc.mint(await stbtc.getAddress(), to1e18(5))
await mezoAllocator.connect(maintainer).allocate()
// donation
await tbtc.mint(await mezoAllocator.getAddress(), to1e18(1))
})

it("should return the total assets value", async () => {
const totalAssets = await mezoAllocator.totalAssets()
expect(totalAssets).to.equal(to1e18(6))
})
})
})

describe("addMaintainer", () => {
Expand Down
Loading

0 comments on commit 72bfcca

Please sign in to comment.