Skip to content

Commit

Permalink
Use EIP1167 for urn (#8)
Browse files Browse the repository at this point in the history
* Support multicall for LockstakeEngine

* Sketch use of converter inside LockstakeEngine

* Send out ngt from converter, separate events

* Add index parameter to open()

* Approve tokens to mkrNgt in the constructor

* gov => mkr, stkGov => stkMkr

* Use EIP1167 for urn

* Fix rebase conflict

* Minor formatting

* Small _initCode reformatting

* Remove unnecessary create2 success check

* Add LockstakeUrn init and ctor tests

* FIx vat.can interface

---------

Co-authored-by: oldchili <130549691+oldchili@users.noreply.github.com>
Co-authored-by: sunbreak <sunbreak1211@proton.me>
Co-authored-by: telome <>
  • Loading branch information
3 people authored Jan 9, 2024
1 parent 917420f commit 5f6051b
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 5 deletions.
21 changes: 18 additions & 3 deletions src/LockstakeEngine.sol
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ contract LockstakeEngine is Multicall {
MkrNgtLike immutable public mkrNgt;
GemLike immutable public ngt;
uint256 immutable public mkrNgtRate;
address immutable public urnImplementation;

// --- events ---

Expand Down Expand Up @@ -149,6 +150,7 @@ contract LockstakeEngine is Multicall {
ngt.approve(address(mkrNgt), type(uint256).max);
mkr.approve(address(mkrNgt), type(uint256).max);
mkrNgtRate = mkrNgt.rate();
urnImplementation = address(new LockstakeUrn(address(vat), stkMkr_));

wards[msg.sender] = 1;
emit Rely(msg.sender);
Expand All @@ -166,6 +168,17 @@ contract LockstakeEngine is Multicall {
ok = urnOwners[urn] == usr || urnCan[urn][usr] == 1;
}

// See the reference implementation in https://eips.ethereum.org/EIPS/eip-1167
function _initCode() internal view returns (bytes memory code) {
code = new bytes(0x37);
bytes20 impl = bytes20(urnImplementation);
assembly {
mstore(add(code, 0x20), 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000)
mstore(add(code, add(0x20, 0x14)), impl)
mstore(add(code, add(0x20, 0x28)), 0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000)
}
}

// --- administration ---

function rely(address usr) external auth {
Expand Down Expand Up @@ -199,7 +212,7 @@ contract LockstakeEngine is Multicall {

function getUrn(address owner, uint256 index) external view returns (address urn) {
uint256 salt = uint256(keccak256(abi.encode(owner, index)));
bytes32 codeHash = keccak256(abi.encodePacked(type(LockstakeUrn).creationCode, abi.encode(vat, stkMkr)));
bytes32 codeHash = keccak256(abi.encodePacked(_initCode()));
urn = address(uint160(uint256(
keccak256(
abi.encodePacked(bytes1(0xff), address(this), salt, codeHash)
Expand All @@ -215,8 +228,10 @@ contract LockstakeEngine is Multicall {

function open(uint256 index) external returns (address urn) {
require(index == usrAmts[msg.sender]++, "LockstakeEngine/wrong-urn-index");
bytes32 salt = keccak256(abi.encode(msg.sender, index));
urn = address(new LockstakeUrn{salt: salt}(address(vat), address(stkMkr)));
uint256 salt = uint256(keccak256(abi.encode(msg.sender, index)));
bytes memory initCode = _initCode();
assembly { urn := create2(0, add(initCode, 0x20), 0x37, salt) }
LockstakeUrn(urn).init(); // would revert if create2 had failed
urnOwners[urn] = msg.sender;
emit Open(msg.sender, urn);
}
Expand Down
9 changes: 7 additions & 2 deletions src/LockstakeUrn.sol
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ contract LockstakeUrn {

address immutable public engine;
GemLike immutable public stkMkr;
VatLike immutable public vat;

// --- modifiers ---

Expand All @@ -46,12 +47,16 @@ contract LockstakeUrn {
_;
}

// --- constructor ---
// --- constructor & init ---

constructor(address vat_, address stkMkr_) {
engine = msg.sender;
vat = VatLike(vat_);
stkMkr = GemLike(stkMkr_);
VatLike(vat_).hope(msg.sender);
}

function init() external isEngine {
vat.hope(msg.sender);
stkMkr.approve(msg.sender, type(uint256).max);
}

Expand Down
14 changes: 14 additions & 0 deletions test/LockstakeEngine.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ pragma solidity ^0.8.16;
import "dss-test/DssTest.sol";
import { LockstakeEngine } from "src/LockstakeEngine.sol";
import { LockstakeClipper } from "src/LockstakeClipper.sol";
import { LockstakeUrn } from "src/LockstakeUrn.sol";
import { PipMock } from "test/mocks/PipMock.sol";
import { DelegateFactoryMock, DelegateMock } from "test/mocks/DelegateMock.sol";
import { GemMock } from "test/mocks/GemMock.sol";
Expand All @@ -18,6 +19,7 @@ interface ChainlogLike {
}

interface VatLike {
function can(address, address) external view returns (uint256);
function dai(address) external view returns (uint256);
function gem(bytes32, address) external view returns (uint256);
function ilks(bytes32) external view returns (uint256, uint256, uint256, uint256, uint256);
Expand Down Expand Up @@ -214,12 +216,24 @@ contract LockstakeEngineTest is DssTest {
address urn = engine.getUrn(address(this), 0);
vm.expectRevert("LockstakeEngine/wrong-urn-index");
engine.open(1);

assertEq(VatLike(vat).can(urn, address(engine)), 0);
assertEq(stkMkr.allowance(urn, address(engine)), 0);
vm.expectEmit(true, true, true, true);
emit Open(address(this), urn);
assertEq(engine.open(0), urn);
assertEq(engine.usrAmts(address(this)), 1);
assertEq(VatLike(vat).can(urn, address(engine)), 1);
assertEq(stkMkr.allowance(urn, address(engine)), type(uint256).max);
assertEq(LockstakeUrn(urn).engine(), address(engine));
assertEq(address(LockstakeUrn(urn).stkMkr()), address(stkMkr));
assertEq(address(LockstakeUrn(urn).vat()), vat);
vm.expectRevert("LockstakeUrn/not-engine");
LockstakeUrn(urn).init();

vm.expectRevert("LockstakeEngine/wrong-urn-index");
engine.open(2);

assertEq(engine.getUrn(address(this), 1), engine.open(1));
assertEq(engine.usrAmts(address(this)), 2);
assertEq(engine.getUrn(address(this), 2), engine.open(2));
Expand Down

0 comments on commit 5f6051b

Please sign in to comment.