pragma solidity ^0.4.24;
contract SecuredTokenTransfer {
/// @dev Transfers a token and returns if it was a success
/// @param token Token that should be transferred
/// @param receiver Receiver to whom the token should be transferred
/// @param amount The amount of tokens that should be transferred
function transferToken (
address token,
address receiver,
uint256 amount
)
internal
returns (bool transferred)
{
bytes memory data = abi.encodeWithSignature("transfer(address,uint256)", receiver, amount);
// solium-disable-next-line security/no-inline-assembly
assembly {
let success := call(sub(gas, 10000), token, 0, add(data, 0x20), mload(data), 0, 0)
let ptr := mload(0x40)
returndatacopy(ptr, 0, returndatasize)
switch returndatasize
case 0 { transferred := success }
case 0x20 { transferred := iszero(or(iszero(success), iszero(mload(ptr)))) }
default { transferred := 0 }
}
}
}
contract Proxy {
// masterCopy always needs to be first declared variable, to ensure that it is at the same location in the contracts to which calls are delegated.
address masterCopy;
/// @dev Constructor function sets address of master copy contract.
/// @param _masterCopy Master copy address.
constructor(address _masterCopy)
public
{
require(_masterCopy != 0, "Invalid master copy address provided");
masterCopy = _masterCopy;
}
/// @dev Fallback function forwards all transactions and returns all received return data.
function ()
external
payable
{
// solium-disable-next-line security/no-inline-assembly
assembly {
let masterCopy := and(sload(0), 0xffffffffffffffffffffffffffffffffffffffff)
calldatacopy(0, 0, calldatasize())
let success := delegatecall(gas, masterCopy, 0, calldatasize(), 0, 0)
returndatacopy(0, 0, returndatasize())
if eq(success, 0) { revert(0, returndatasize()) }
return(0, returndatasize())
}
}
function implementation()
public
view
returns (address)
{
return masterCopy;
}
function proxyType()
public
pure
returns (uint256)
{
return 2;
}
}
contract DelegateConstructorProxy is Proxy {
/// @dev Constructor function sets address of master copy contract.
/// @param _masterCopy Master copy address.
/// @param initializer Data used for a delegate call to initialize the contract.
constructor(address _masterCopy, bytes initializer) Proxy(_masterCopy)
public
{
if (initializer.length > 0) {
// solium-disable-next-line security/no-inline-assembly
assembly {
let masterCopy := and(sload(0), 0xffffffffffffffffffffffffffffffffffffffff)
let success := delegatecall(sub(gas, 10000), masterCopy, add(initializer, 0x20), mload(initializer), 0, 0)
let ptr := mload(0x40)
returndatacopy(ptr, 0, returndatasize)
if eq(success, 0) { revert(ptr, returndatasize) }
}
}
}
}
contract PayingProxy is DelegateConstructorProxy, SecuredTokenTransfer {
/// @dev Constructor function sets address of master copy contract.
/// @param _masterCopy Master copy address.
/// @param initializer Data used for a delegate call to initialize the contract.
/// @param funder Address that should be paid for the execution of this call
/// @param paymentToken Token that should be used for the payment (0 is ETH)
/// @param payment Value that should be paid
constructor(address _masterCopy, bytes initializer, address funder, address paymentToken, uint256 payment)
DelegateConstructorProxy(_masterCopy, initializer)
public
{
if (payment > 0) {
if (paymentToken == address(0)) {
// solium-disable-next-line security/no-send
require(funder.send(payment), "Could not pay safe creation with ether");
} else {
require(transferToken(paymentToken, funder, payment), "Could not pay safe creation with token");
}
}
}
}
{
"compilationTarget": {
"PayingProxy.sol": "PayingProxy"
},
"evmVersion": "byzantium",
"libraries": {},
"optimizer": {
"enabled": false,
"runs": 200
},
"remappings": []
}
[{"constant":true,"inputs":[],"name":"proxyType","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[],"name":"implementation","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"inputs":[{"name":"_masterCopy","type":"address"},{"name":"initializer","type":"bytes"},{"name":"funder","type":"address"},{"name":"paymentToken","type":"address"},{"name":"payment","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"payable":true,"stateMutability":"payable","type":"fallback"}]