Skip to content

Instantly share code, notes, and snippets.

@Magicking
Last active December 12, 2020 11:17
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Magicking/fe63df8e8fce9a0710c53bc34fec7ac9 to your computer and use it in GitHub Desktop.
Save Magicking/fe63df8e8fce9a0710c53bc34fec7ac9 to your computer and use it in GitHub Desktop.
Multi deposit contract
pragma solidity <=0.8.0;
pragma experimental ABIEncoderV2;
// Author: Sylvain Laurent
// Use Scribble https://docs.scribble.codes/tool/cli-usage#emitting-a-flat-instrumented-file to generate guards / arm the contract
// This interface is designed to be compatible with the Vyper version.
/// @notice This is the Ethereum 2.0 deposit contract interface.
/// For more information see the Phase 0 specification under https://github.com/ethereum/eth2.0-specs
interface IDepositContract {
/// @notice A processed deposit event.
event DepositEvent(
bytes pubkey,
bytes withdrawal_credentials,
bytes amount,
bytes signature,
bytes index
);
/// @notice Submit a Phase 0 DepositData object.
/// @param pubkey A BLS12-381 public key.
/// @param withdrawal_credentials Commitment to a public key for withdrawals.
/// @param signature A BLS12-381 signature.
/// @param deposit_data_root The SHA-256 hash of the SSZ-encoded DepositData object.
/// Used as a protection against malformed input.
function deposit(
bytes calldata pubkey,
bytes calldata withdrawal_credentials,
bytes calldata signature,
bytes32 deposit_data_root
) external payable;
/// @notice Query the current deposit root hash.
/// @return The deposit root hash.
function get_deposit_root() external view returns (bytes32);
/// @notice Query the current deposit count.
/// @return The deposit count encoded as a little endian 64-bit number.
function get_deposit_count() external view returns (bytes memory);
}
contract BatchDeposit {
IDepositContract public deposit_contract;
// https://github.com/ethereum/eth2.0-specs/blob/dev/specs/phase0/beacon-chain.md#gwei-values
uint256 constant MAX_EFFECTIVE_DEPOSIT_AMOUNT = 32 ether;
// Prevent transaction creation with gas usage too close to block gas limit
uint256 constant MAX_VALIDATORS_VARIABLE = 100; // TODO Adjust to aims for 75% of block gas limit
uint256 constant MAX_VALIDATORS = 100; // TODO Adjust to aims for 75% of block gas limit
/// @notice Deploy a contract tied to selected deposit contract.
/// @param _deposit_contract A deposit contract address (see IDepositContract).
constructor(address _deposit_contract) {
// Network contract address
// Mainnet 0x00000000219ab540356cbb839cbe05303d7705fa @chain id:1
// Pyrmont 0x28aa7D30eb27b8955930beE3bC72255ab6a574D9 @chain id:5
deposit_contract = IDepositContract(_deposit_contract);
}
/// @notice Submit multiple Phase 0 DepositData object with variable amount per deposit.
/// @param pubkeys An array of BLS12-381 public key.
/// @param withdrawal_credentials An array of commitment to public keys for withdrawals.
/// @param signatures An array of BLS12-381 signature.
/// @param deposit_data_roots An array of SHA-256 hash of the SSZ-encoded DepositData object.
/// @param amounts An array of amount, must be above or equal 1 eth.
/// Used as a protection against malformed input.
/// if_succeeds {:msg "number of input elements too important"} old(pubkeys.length) <= MAX_VALIDATORS_VARIABLE;
/// if_succeeds {:msg "number of withdrawal_credentials mismatch the number of public keys"} old(pubkeys.length) <= old(withdrawal_credentials.length);
/// if_succeeds {:msg "number of signatures mismatch the number of public keys"} old(pubkeys.length) <= old(signatures.length);
/// if_succeeds {:msg "number of amounts mismatch the number of public keys"} old(pubkeys.length) <= old(amounts.length);
/// if_succeeds {:msg "number of deposit_data_roots mismatch the number of public keys"} old(pubkeys.length) <= old(deposit_data_roots.length);
/// if_succeeds {:msg "supplied ether value mismatch the total deposited sum"} deposited_amount == msg.value;
function batchDepositVariable(bytes[] calldata pubkeys, bytes[] calldata withdrawal_credentials, bytes[] calldata signatures, bytes32[] calldata deposit_data_roots, uint64[] calldata amounts) external payable returns (uint256 deposited_amount){
for (uint i = 0; i < pubkeys.length; i++) {
deposit_contract.deposit{value:amounts[i]}(pubkeys[i], withdrawal_credentials[i], signatures[i], deposit_data_roots[i]);
deposited_amount += uint256(amounts[i]);
}
}
/// @notice Submit multiple Phase 0 DepositData object with a fixed 32 eth amount.
/// @param pubkeys An array of BLS12-381 public key.
/// @param withdrawal_credentials An array of commitment to public keys for withdrawals.
/// @param signatures An array of BLS12-381 signature.
/// @param deposit_data_roots An array of SHA-256 hash of the SSZ-encoded DepositData object.
/// Used as a protection against malformed input.
/// if_succeeds {:msg "number of input elements too important"} old(pubkeys.length) <= MAX_VALIDATORS_VARIABLE;
/// if_succeeds {:msg "number of withdrawal_credentials mismatch the number of public keys"} old(pubkeys.length) <= old(withdrawal_credentials.length);
/// if_succeeds {:msg "number of signatures mismatch the number of public keys"} old(pubkeys.length) <= old(signatures.length);
/// if_succeeds {:msg "number of deposit_data_roots mismatch the number of public keys"} old(pubkeys.length) <= old(deposit_data_roots.length);
/// if_succeeds {:msg "supplied ether value mismatch the total deposited sum"} old(pubkeys.length)*MAX_EFFECTIVE_DEPOSIT_AMOUNT == msg.value;
function batchDeposit(bytes[] calldata pubkeys, bytes[] calldata withdrawal_credentials, bytes[] calldata signatures, bytes32[] calldata deposit_data_roots) external payable {
for (uint i = 0; i < pubkeys.length; i++) {
deposit_contract.deposit{value:MAX_EFFECTIVE_DEPOSIT_AMOUNT}(pubkeys[i], withdrawal_credentials[i], signatures[i], deposit_data_roots[i]);
}
}
}
pragma experimental ABIEncoderV2;
pragma solidity 0.7.5;
/// @notice This is the Ethereum 2.0 deposit contract interface.
/// For more information see the Phase 0 specification under https://github.com/ethereum/eth2.0-specs
interface IDepositContract {
/// @notice A processed deposit event.
event DepositEvent(bytes pubkey, bytes withdrawal_credentials, bytes amount, bytes signature, bytes index);
/// @notice Submit a Phase 0 DepositData object.
/// @param pubkey A BLS12-381 public key.
/// @param withdrawal_credentials Commitment to a public key for withdrawals.
/// @param signature A BLS12-381 signature.
/// @param deposit_data_root The SHA-256 hash of the SSZ-encoded DepositData object.
/// Used as a protection against malformed input.
function deposit(bytes calldata pubkey, bytes calldata withdrawal_credentials, bytes calldata signature, bytes32 deposit_data_root) external payable;
/// @notice Query the current deposit root hash.
/// @return The deposit root hash.
function get_deposit_root() external view returns (bytes32);
/// @notice Query the current deposit count.
/// @return The deposit count encoded as a little endian 64-bit number.
function get_deposit_count() external view returns (bytes memory);
}
contract BatchDeposit {
event AssertionFailed(string message);
struct vars0 {
uint256 old_0;
uint256 old_1;
uint256 old_2;
uint256 old_3;
uint256 old_4;
uint256 old_5;
uint256 old_6;
uint256 old_7;
uint256 old_8;
}
struct vars1 {
uint256 old_9;
uint256 old_10;
uint256 old_11;
uint256 old_12;
uint256 old_13;
uint256 old_14;
uint256 old_15;
uint256 old_16;
}
IDepositContract public deposit_contract;
uint256 internal constant MAX_EFFECTIVE_DEPOSIT_AMOUNT = 32 ether;
uint256 internal constant MAX_VALIDATORS_VARIABLE = 100;
uint256 internal constant MAX_VALIDATORS = 100;
/// @notice Deploy a contract tied to selected deposit contract.
/// @param _deposit_contract A deposit contract address (see IDepositContract).
constructor(address _deposit_contract) {
deposit_contract = IDepositContract(_deposit_contract);
}
function batchDepositVariable(bytes[] calldata pubkeys, bytes[] calldata withdrawal_credentials, bytes[] calldata signatures, bytes32[] calldata deposit_data_roots, uint64[] calldata amounts) external payable returns (uint256 deposited_amount) {
vars0 memory _v;
_v.old_0 = pubkeys.length;
_v.old_1 = pubkeys.length;
_v.old_2 = withdrawal_credentials.length;
_v.old_3 = pubkeys.length;
_v.old_4 = signatures.length;
_v.old_5 = pubkeys.length;
_v.old_6 = amounts.length;
_v.old_7 = pubkeys.length;
_v.old_8 = deposit_data_roots.length;
deposited_amount = _original_BatchDeposit_batchDepositVariable(pubkeys, withdrawal_credentials, signatures, deposit_data_roots, amounts);
if ((!((_v.old_0 <= MAX_VALIDATORS_VARIABLE)))) {
emit AssertionFailed("0: number of input elements too important");
assert(false);
}
if ((!((_v.old_1 <= _v.old_2)))) {
emit AssertionFailed("1: number of withdrawal_credentials mismatch the number of public keys");
assert(false);
}
if ((!((_v.old_3 <= _v.old_4)))) {
emit AssertionFailed("2: number of signatures mismatch the number of public keys");
assert(false);
}
if ((!((_v.old_5 <= _v.old_6)))) {
emit AssertionFailed("3: number of amounts mismatch the number of public keys");
assert(false);
}
if ((!((_v.old_7 <= _v.old_8)))) {
emit AssertionFailed("4: number of deposit_data_roots mismatch the number of public keys");
assert(false);
}
if ((!((deposited_amount == msg.value)))) {
emit AssertionFailed("5: supplied ether value mismatch the total deposited sum");
assert(false);
}
}
function _original_BatchDeposit_batchDepositVariable(bytes[] calldata pubkeys, bytes[] calldata withdrawal_credentials, bytes[] calldata signatures, bytes32[] calldata deposit_data_roots, uint64[] calldata amounts) private returns (uint256 deposited_amount) {
for (uint i = 0; (i < pubkeys.length); (i++)) {
deposit_contract.deposit{value: amounts[i]}(pubkeys[i], withdrawal_credentials[i], signatures[i], deposit_data_roots[i]);
deposited_amount += uint256(amounts[i]);
}
}
function batchDeposit(bytes[] calldata pubkeys, bytes[] calldata withdrawal_credentials, bytes[] calldata signatures, bytes32[] calldata deposit_data_roots) external payable {
vars1 memory _v;
_v.old_9 = pubkeys.length;
_v.old_10 = pubkeys.length;
_v.old_11 = withdrawal_credentials.length;
_v.old_12 = pubkeys.length;
_v.old_13 = signatures.length;
_v.old_14 = pubkeys.length;
_v.old_15 = deposit_data_roots.length;
_v.old_16 = pubkeys.length;
_original_BatchDeposit_batchDeposit(pubkeys, withdrawal_credentials, signatures, deposit_data_roots);
if ((!((_v.old_9 <= MAX_VALIDATORS_VARIABLE)))) {
emit AssertionFailed("6: number of input elements too important");
assert(false);
}
if ((!((_v.old_10 <= _v.old_11)))) {
emit AssertionFailed("7: number of withdrawal_credentials mismatch the number of public keys");
assert(false);
}
if ((!((_v.old_12 <= _v.old_13)))) {
emit AssertionFailed("8: number of signatures mismatch the number of public keys");
assert(false);
}
if ((!((_v.old_14 <= _v.old_15)))) {
emit AssertionFailed("9: number of deposit_data_roots mismatch the number of public keys");
assert(false);
}
if ((!(((_v.old_16 * MAX_EFFECTIVE_DEPOSIT_AMOUNT) == msg.value)))) {
emit AssertionFailed("10: supplied ether value mismatch the total deposited sum");
assert(false);
}
}
function _original_BatchDeposit_batchDeposit(bytes[] calldata pubkeys, bytes[] calldata withdrawal_credentials, bytes[] calldata signatures, bytes32[] calldata deposit_data_roots) private {
for (uint i = 0; (i < pubkeys.length); (i++)) {
deposit_contract.deposit{value: MAX_EFFECTIVE_DEPOSIT_AMOUNT}(pubkeys[i], withdrawal_credentials[i], signatures[i], deposit_data_roots[i]);
}
}
}
/// Utility contract holding a stack counter
contract __scribble_ReentrancyUtils {
bool __scribble_out_of_contract = true;
}
@Magicking
Copy link
Author

Scribble constraint need to be added to the constructor as well

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment