Skip to content

Commit

Permalink
πŸ› Refactor & add SSBalance tests
Browse files Browse the repository at this point in the history
  • Loading branch information
KimlikDAO-bot committed May 1, 2024
1 parent 6b30c59 commit 946115d
Show file tree
Hide file tree
Showing 15 changed files with 456 additions and 239 deletions.
9 changes: 9 additions & 0 deletions common/IBridgeReceiver.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import {amountAddr} from "interfaces/types/amountAddr.sol";

interface IBridgeReceiver {
function acceptBridgeFromEthereum(amountAddr aaddr) external;
}
119 changes: 59 additions & 60 deletions contracts/KDAOMainnet.sol β†’ ethereum/KDAO.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,18 @@

pragma solidity ^0.8.0;

import {IBridgeReceiver} from "common/IBridgeReceiver.sol";
import {IERC20, IERC20Permit} from "interfaces/erc/IERC20Permit.sol";
import {PROTOCOL_FUND, ProtocolFund, RedeemInfoFrom} from "interfaces/kimlikdao/IProtocolFund.sol";
import {KDAO_ZKSYNC} from "interfaces/kimlikdao/addresses.sol";
import {amountAddr, amountAddrFrom} from "interfaces/types/amountAddr.sol";
import {uint128x2} from "interfaces/types/uint128x2.sol";
import {uint48x2, uint48x2From} from "interfaces/types/uint48x2.sol";
import {L1_MESSENGER} from "interfaces/zksync/IL1Messenger.sol";
import {TxStatus, ZkSync, applyL1ToL2Alias} from "interfaces/zksync/IZkSync.sol";
import {L2Log, L2LogLocator} from "interfaces/zksync/L2Log.sol";

contract KDAO is IERC20Permit {
event BridgeToZkSync(bytes32 indexed l2TxHash, address indexed addr, uint256 amount);
event ClaimFailedZkSyncBridge(bytes32 indexed l2TxHash, address indexed addr, uint256 amount);
event AcceptBridgeFromZkSync(
L2LogLocator indexed logLocator, address indexed addr, uint256 amount
);

function name() external pure override returns (string memory) {
return "KimlikDAO";
}
Expand All @@ -30,6 +26,14 @@ contract KDAO is IERC20Permit {
return 6;
}

///////////////////////////////////////////////////////////////////////////
//
// IERC20 balance fields and methods + additional supply methods
//
///////////////////////////////////////////////////////////////////////////

mapping(address => uint256) public override balanceOf;

uint48x2 internal totals = uint48x2From(100_000_000e6, 0);

/// @notice `maxSupply()` starts out as 100M and can only be decremented thereafter
Expand All @@ -50,8 +54,11 @@ contract KDAO is IERC20Permit {
return totals.lo();
}

mapping(address => uint256) public override balanceOf;
mapping(address => mapping(address => uint256)) public override allowance;
///////////////////////////////////////////////////////////////////////////
//
// IERC20 transfer methods
//
///////////////////////////////////////////////////////////////////////////

function transfer(address to, uint256 amount) external override returns (bool) {
if (to == PROTOCOL_FUND) {
Expand All @@ -67,11 +74,7 @@ contract KDAO is IERC20Permit {
return true;
}

function transferFrom(address from, address to, uint256 amount)
external
override
returns (bool)
{
function transferFrom(address from, address to, uint256 amount) external override returns (bool) {
require(to != address(this) && to != PROTOCOL_FUND);
uint256 allowed = allowance[from][msg.sender];
if (allowed != type(uint256).max) allowance[from][msg.sender] = allowed - amount; // Checked substraction
Expand All @@ -83,6 +86,14 @@ contract KDAO is IERC20Permit {
return true;
}

///////////////////////////////////////////////////////////////////////////
//
// IERC20 allowance fields and methods + recommended update methods
//
///////////////////////////////////////////////////////////////////////////

mapping(address => mapping(address => uint256)) public override allowance;

function approve(address spender, uint256 amount) external override returns (bool) {
allowance[msg.sender][spender] = amount;
emit Approval(msg.sender, spender, amount);
Expand Down Expand Up @@ -117,50 +128,38 @@ contract KDAO is IERC20Permit {
// keccak256(bytes("KDAO")),
// keccak256(bytes("1")),
// 0x1,
// KDAO_MAINNET
// KDAO_ETHEREUM
// )
// );
bytes32 public constant override DOMAIN_SEPARATOR =
0x6faf94999332059363533545c34fe71ffc0642c13cd1fa816c361b545eb33d9b;

// keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)");
bytes32 private constant PERMIT_TYPEHASH =
0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9;
bytes32 private constant PERMIT_TYPEHASH = 0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9;

mapping(address => uint256) public override nonces;

function permit(
address owner,
address spender,
uint256 amount,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external {
function permit(address owner, address spender, uint256 amount, uint256 deadline, uint8 v, bytes32 r, bytes32 s)
external
{
require(deadline >= block.timestamp);
unchecked {
bytes32 digest = keccak256(
abi.encodePacked(
"\x19\x01",
DOMAIN_SEPARATOR,
keccak256(
abi.encode(
PERMIT_TYPEHASH, owner, spender, amount, nonces[owner]++, deadline
)
)
keccak256(abi.encode(PERMIT_TYPEHASH, owner, spender, amount, nonces[owner]++, deadline))
)
);
address recovered = ecrecover(digest, v, r, s);
require(recovered != address(0) && recovered == owner);
allowance[owner][spender] = amount;
emit Approval(owner, spender, amount);
}
allowance[owner][spender] = amount;
emit Approval(owner, spender, amount);
}

///////////////////////////////////////////////////////////////////////////
//
// KimlikDAO protocol specific methods
// KimlikDAO protocol specific fields and methods
//
///////////////////////////////////////////////////////////////////////////

Expand All @@ -184,39 +183,46 @@ contract KDAO is IERC20Permit {

///////////////////////////////////////////////////////////////////////////
//
// Mainnet <-> zkSync Era bridge methods
// Mainnet <-> zkSync Era bridge fields and methods
//
///////////////////////////////////////////////////////////////////////////

mapping(bytes32 => amountAddr) public bridgedAmountAddr;
event BridgeToZkSync(bytes32 indexed l2TxHash, address indexed from, address indexed to, uint256 amount);
event ClaimFailedZkSyncBridge(bytes32 indexed l2TxHash, address indexed addr, uint256 amount);
event AcceptBridgeFromZkSync(L2LogLocator indexed logLocator, address indexed addr, uint256 amount);

mapping(bytes32 => amountAddr) private bridgedAmountAddr;
mapping(L2LogLocator => bool) private isLogProcessed;

function bridgeToZkSync(uint256 amount, uint128x2 l2TxGasLimitAndPerPubdata)
function bridgeToZkSync(amountAddr aaddr, uint128x2 l2TxGasLimitAndPerPubdata)
public
payable
returns (bytes32 l2TxHash)
{
(uint256 amount, address addr) = aaddr.unpack();
if (addr == address(0)) {
addr = msg.sender;
aaddr = aaddr.addAddr(msg.sender);
}
balanceOf[msg.sender] -= amount; // Checked substraction
amountAddr aaddr = amountAddrFrom(amount, msg.sender);
l2TxHash = ZkSync.requestL2Transaction{value: msg.value}(
KDAO_ZKSYNC,
0,
abi.encodeWithSelector(0x12341234, aaddr),
abi.encodeCall(IBridgeReceiver.acceptBridgeFromEthereum, aaddr),
l2TxGasLimitAndPerPubdata.hi(),
l2TxGasLimitAndPerPubdata.lo(),
new bytes[](0),
msg.sender == tx.origin ? msg.sender : applyL1ToL2Alias(msg.sender)
);
totals = totals.decLo(amount);
bridgedAmountAddr[l2TxHash] = aaddr;
emit BridgeToZkSync(l2TxHash, msg.sender, amount);
bridgedAmountAddr[l2TxHash] = aaddr.setAddr(msg.sender);

emit BridgeToZkSync(l2TxHash, msg.sender, addr, amount);
}

function claimFailedZkSyncBridge(
bytes32 l2TxHash,
L2LogLocator logLocator,
bytes32[] calldata merkleProof
) public {
function claimFailedZkSyncBridge(bytes32 l2TxHash, L2LogLocator logLocator, bytes32[] calldata merkleProof)
public
{
require(
ZkSync.proveL1ToL2TransactionStatus(
l2TxHash,
Expand All @@ -228,7 +234,7 @@ contract KDAO is IERC20Permit {
)
);
amountAddr aaddr = bridgedAmountAddr[l2TxHash];
require(aaddr != amountAddr.wrap(0));
require(!aaddr.isZero());
bridgedAmountAddr[l2TxHash] = amountAddr.wrap(0);

(uint256 amount, address addr) = aaddr.unpack();
Expand All @@ -239,25 +245,17 @@ contract KDAO is IERC20Permit {
emit ClaimFailedZkSyncBridge(l2TxHash, addr, amount);
}

function acceptBridgeFromZkSync(
amountAddr aaddr,
L2LogLocator logLocator,
bytes32[] calldata merkleProof
) public {
function acceptBridgeFromZkSync(amountAddr aaddr, L2LogLocator logLocator, bytes32[] calldata merkleProof) public {
L2Log memory l2Log = L2Log({
l2ShardId: 0,
isService: false,
isService: true,
txNumberInBatch: uint16(logLocator.txNumber()),
sender: KDAO_ZKSYNC,
sender: L1_MESSENGER,
key: bytes32(uint256(uint160(KDAO_ZKSYNC))),
value: bytes32(amountAddr.unwrap(aaddr))
value: keccak256(abi.encode(aaddr))
});
require(!isLogProcessed[logLocator]);
require(
ZkSync.proveL2LogInclusion(
logLocator.batchNumber(), logLocator.messageIndex(), l2Log, merkleProof
)
);
require(ZkSync.proveL2LogInclusion(logLocator.batchNumber(), logLocator.messageIndex(), l2Log, merkleProof));

(uint256 amount, address addr) = aaddr.unpack();
uint48x2 total = totals.incLo(amount);
Expand All @@ -267,6 +265,7 @@ contract KDAO is IERC20Permit {
balanceOf[addr] += amount;
}
isLogProcessed[logLocator] = true;

emit AcceptBridgeFromZkSync(logLocator, addr, amount);
}
}
4 changes: 3 additions & 1 deletion foundry.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,16 @@ single_line_statement_blocks = "single"
sort_imports = true

[profile.default]
src = 'contracts'
test = 'test'
optimizer = true
optimizer_runs = 100_000
remappings = ["forge-std/=lib/forge-std/src/", "interfaces/=lib/interfaces/"]

[profile.ethereum]
solc_version = "0.8.25"
evm_version = "cancun"
src = "ethereum"

[profile.zksync]
solc_version = "0.8.24"
src = "zksync"
2 changes: 1 addition & 1 deletion lib/forge-std
13 changes: 7 additions & 6 deletions test/KDAOMainnet.t.sol β†’ test/ethereum/KDAO.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@

pragma solidity ^0.8.0;

import {KDAO} from "contracts/KDAOMainnet.sol";
import {KDAO} from "ethereum/KDAO.sol";
import {Test} from "forge-std/Test.sol";
import {KDAO_MAINNET, KDAO_MAINNET_DEPLOYER} from "interfaces/kimlikdao/addresses.sol";
import {console2} from "forge-std/console2.sol";
import {KDAO_ETHEREUM, KDAO_ETHEREUM_DEPLOYER} from "interfaces/kimlikdao/addresses.sol";
import {uint48x2From} from "interfaces/types/uint48x2.sol";

contract KDAOPremined is KDAO {
Expand All @@ -14,15 +15,15 @@ contract KDAOPremined is KDAO {
balanceOf[address(0x1339)] = 100e6;
balanceOf[address(0x1310)] = 100e6;

totals = uint48x2From(100_000_000e6, 400e6);
totals = uint48x2From(100_000_000e6, 4 * 100e6);
}
}

contract KDAOMainnetTest is Test {
contract KDAOTest is Test {
KDAO private kdao;

function setUp() public {
vm.prank(KDAO_MAINNET_DEPLOYER);
vm.prank(KDAO_ETHEREUM_DEPLOYER);
kdao = new KDAOPremined();
}

Expand All @@ -37,7 +38,7 @@ contract KDAOMainnetTest is Test {
keccak256(bytes("KDAO")),
keccak256(bytes("1")),
0x1,
KDAO_MAINNET
KDAO_ETHEREUM
)
)
);
Expand Down
4 changes: 2 additions & 2 deletions test/KDAOZkSync.t.sol β†’ test/zksync/KDAO.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@

pragma solidity ^0.8.0;

import {KDAO} from "contracts/KDAOZkSync.sol";
import {Test} from "forge-std/Test.sol";
import {KDAO_ZKSYNC, KDAO_ZKSYNC_DEPLOYER} from "interfaces/kimlikdao/addresses.sol";
import {uint48x2From} from "interfaces/types/uint48x2.sol";
import {KDAO} from "zksync/KDAO.sol";

contract KDAOZkSyncTest is Test {
contract KDAOTest is Test {
KDAO private kdao;

function setUp() public {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@

pragma solidity ^0.8.0;

import {KDAO_PRESALE_V1, KDAO_PRESALE_V2} from "contracts/KDAOPresale.sol";
import {Test} from "forge-std/Test.sol";
import {KDAO_PRESALE, KDAO_PRESALE_DEPLOYER} from "interfaces/kimlikdao/addresses.sol";
import {computeCreateAddress as computeZkSyncCreateAddress} from "interfaces/zksync/IZkSync.sol";
import {KDAO_PRESALE_V1, KDAO_PRESALE_V2} from "zksync/KDAOPresale.sol";

contract addressesTest is Test {
function testDeployerConsistency() public pure {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@

pragma solidity ^0.8.0;

import {KDAOPresaleV1} from "contracts/KDAOPresaleV1.sol";
import {Test} from "forge-std/Test.sol";
import {IUpgradable} from "interfaces/kimlikdao/IUpgradable.sol";
import {KDAO_PRESALE_DEPLOYER} from "interfaces/kimlikdao/addresses.sol";
import {KDAOPresaleV1} from "zksync/KDAOPresaleV1.sol";

contract MockKDAOPresaleV2 is IUpgradable {
function versionHash() external pure override returns (bytes32) {
Expand Down
Loading

0 comments on commit 946115d

Please sign in to comment.