0 ETH
USD
BTC
0x6EdB89D09D4f2eE6422EEf4088E459167Aec582A
In order to save any account details you will need to provide a signed message of that account for verification. Currently we support only signatures generated by the MyCrypto Tool.
The signature text MUST CONTAIN the the string " etherchain.org ".
Hash | Block | Type | From | To | Value | Fee | Time |
---|
pragma solidity ^0.4.14;
/**
* Contract that exposes the needed erc20 token functions
*/
contract ERC20Interface {
// Send _value amount of tokens to address _to
function transfer(address _to, uint256 _value) returns (bool success);
// Get the account balance of another account with address _owner
function balanceOf(address _owner) constant returns (uint256 balance);
}
/**
* Contract that will forward any incoming Ether to its creator
*/
contract Forwarder {
// Address to which any funds sent to this contract will be forwarded
address public parentAddress;
event ForwarderDeposited(address from, uint value, bytes data);
event TokensFlushed(
address tokenContractAddress, // The contract address of the token
uint value // Amount of token sent
);
/**
* Create the contract, and set the destination address to that of the creator
*/
function Forwarder() {
parentAddress = msg.sender;
}
/**
* Modifier that will execute internal code block only if the sender is a parent of the forwarder contract
*/
modifier onlyParent {
if (msg.sender != parentAddress) {
throw;
}
_;
}
/**
* Default function; Gets called when Ether is deposited, and forwards it to the destination address
*/
function() payable {
if (!parentAddress.call.value(msg.value)(msg.data))
throw;
// Fire off the deposited event if we can forward it
ForwarderDeposited(msg.sender, msg.value, msg.data);
}
/**
* Execute a token transfer of the full balance from the forwarder token to the main wallet contract
* @param tokenContractAddress the address of the erc20 token contract
*/
function flushTokens(address tokenContractAddress) onlyParent {
ERC20Interface instance = ERC20Interface(tokenContractAddress);
var forwarderAddress = address(this);
var forwarderBalance = instance.balanceOf(forwarderAddress);
if (forwarderBalance == 0) {
return;
}
if (!instance.transfer(parentAddress, forwarderBalance)) {
throw;
}
TokensFlushed(tokenContractAddress, forwarderBalance);
}
/**
* It is possible that funds were sent to this address before the contract was deployed.
* We can flush those funds to the destination address.
*/
function flush() {
if (!parentAddress.call.value(this.balance)())
throw;
}
}
/**
* Basic multi-signer wallet designed for use in a co-signing environment where 2 signatures are required to move funds.
* Typically used in a 2-of-3 signing configuration. Uses ecrecover to allow for 2 signatures in a single transaction.
*/
contract WalletSimple {
// Events
event Deposited(address from, uint value, bytes data);
event SafeModeActivated(address msgSender);
event Transacted(
address msgSender, // Address of the sender of the message initiating the transaction
address otherSigner, // Address of the signer (second signature) used to initiate the transaction
bytes32 operation, // Operation hash (sha3 of toAddress, value, data, expireTime, sequenceId)
address toAddress, // The address the transaction was sent to
uint value, // Amount of Wei sent to the address
bytes data // Data sent when invoking the transaction
);
event TokenTransacted(
address msgSender, // Address of the sender of the message initiating the transaction
address otherSigner, // Address of the signer (second signature) used to initiate the transaction
bytes32 operation, // Operation hash (sha3 of toAddress, value, tokenContractAddress, expireTime, sequenceId)
address toAddress, // The address the transaction was sent to
uint value, // Amount of token sent
address tokenContractAddress // The contract address of the token
);
// Public fields
address[] public signers; // The addresses that can co-sign transactions on the wallet
bool public safeMode = false; // When active, wallet may only send to signer addresses
// Internal fields
uint constant SEQUENCE_ID_WINDOW_SIZE = 10;
uint[10] recentSequenceIds;
/**
* Modifier that will execute internal code block only if the sender is an authorized signer on this wallet
*/
modifier onlysigner {
if (!isSigner(msg.sender)) {
throw;
}
_;
}
/**
* Set up a simple multi-sig wallet by specifying the signers allowed to be used on this wallet.
* 2 signers will be required to send a transaction from this wallet.
* Note: The sender is NOT automatically added to the list of signers.
* Signers CANNOT be changed once they are set
*
* @param allowedSigners An array of signers on the wallet
*/
function WalletSimple(address[] allowedSigners) {
if (allowedSigners.length != 3) {
// Invalid number of signers
throw;
}
signers = allowedSigners;
}
/**
* Gets called when a transaction is received without calling a method
*/
function() payable {
if (msg.value > 0) {
// Fire deposited event if we are receiving funds
Deposited(msg.sender, msg.value, msg.data);
}
}
/**
* Create a new contract (and also address) that forwards funds to this contract
* returns address of newly created forwarder address
*/
function createForwarder() onlysigner returns (address) {
return new Forwarder();
}
/**
* Execute a multi-signature transaction from this wallet using 2 signers: one from msg.sender and the other from ecrecover.
* The signature is a signed form (using eth.sign) of tightly packed toAddress, value, data, expireTime and sequenceId
* Sequence IDs are numbers starting from 1. They are used to prevent replay attacks and may not be repeated.
*
* @param toAddress the destination address to send an outgoing transaction
* @param value the amount in Wei to be sent
* @param data the data to send to the toAddress when invoking the transaction
* @param expireTime the number of seconds since 1970 for which this transaction is valid
* @param sequenceId the unique sequence id obtainable from getNextSequenceId
* @param signature the result of eth.sign on the operationHash sha3(toAddress, value, data, expireTime, sequenceId)
*/
function sendMultiSig(address toAddress, uint value, bytes data, uint expireTime, uint sequenceId, bytes signature) onlysigner {
// Verify the other signer
var operationHash = sha3("ETHER", toAddress, value, data, expireTime, sequenceId);
var otherSigner = verifyMultiSig(toAddress, operationHash, signature, expireTime, sequenceId);
// Success, send the transaction
if (!(toAddress.call.value(value)(data))) {
// Failed executing transaction
throw;
}
Transacted(msg.sender, otherSigner, operationHash, toAddress, value, data);
}
/**
* Execute a multi-signature token transfer from this wallet using 2 signers: one from msg.sender and the other from ecrecover.
* The signature is a signed form (using eth.sign) of tightly packed toAddress, value, tokenContractAddress, expireTime and sequenceId
* Sequence IDs are numbers starting from 1. They are used to prevent replay attacks and may not be repeated.
*
* @param toAddress the destination address to send an outgoing transaction
* @param value the amount in tokens to be sent
* @param tokenContractAddress the address of the erc20 token contract
* @param expireTime the number of seconds since 1970 for which this transaction is valid
* @param sequenceId the unique sequence id obtainable from getNextSequenceId
* @param signature the result of eth.sign on the operationHash sha3(toAddress, value, tokenContractAddress, expireTime, sequenceId)
*/
function sendMultiSigToken(address toAddress, uint value, address tokenContractAddress, uint expireTime, uint sequenceId, bytes signature) onlysigner {
// Verify the other signer
var operationHash = sha3("ERC20", toAddress, value, tokenContractAddress, expireTime, sequenceId);
var otherSigner = verifyMultiSig(toAddress, operationHash, signature, expireTime, sequenceId);
ERC20Interface instance = ERC20Interface(tokenContractAddress);
if (!instance.transfer(toAddress, value)) {
throw;
}
TokenTransacted(msg.sender, otherSigner, operationHash, toAddress, value, tokenContractAddress);
}
/**
* Execute a token flush from one of the forwarder addresses. This transfer needs only a single signature and can be done by any signer
*
* @param forwarderAddress the address of the forwarder address to flush the tokens from
* @param tokenContractAddress the address of the erc20 token contract
*/
function flushForwarderTokens(address forwarderAddress, address tokenContractAddress) onlysigner {
Forwarder forwarder = Forwarder(forwarderAddress);
forwarder.flushTokens(tokenContractAddress);
}
/**
* Do common multisig verification for both eth sends and erc20token transfers
*
* @param toAddress the destination address to send an outgoing transaction
* @param operationHash the sha3 of the toAddress, value, data/tokenContractAddress and expireTime
* @param signature the tightly packed signature of r, s, and v as an array of 65 bytes (returned by eth.sign)
* @param expireTime the number of seconds since 1970 for which this transaction is valid
* @param sequenceId the unique sequence id obtainable from getNextSequenceId
* returns address of the address to send tokens or eth to
*/
function verifyMultiSig(address toAddress, bytes32 operationHash, bytes signature, uint expireTime, uint sequenceId) private returns (address) {
var otherSigner = recoverAddressFromSignature(operationHash, signature);
// Verify if we are in safe mode. In safe mode, the wallet can only send to signers
if (safeMode && !isSigner(toAddress)) {
// We are in safe mode and the toAddress is not a signer. Disallow!
throw;
}
// Verify that the transaction has not expired
if (expireTime < block.timestamp) {
// Transaction expired
throw;
}
// Try to insert the sequence ID. Will throw if the sequence id was invalid
tryInsertSequenceId(sequenceId);
if (!isSigner(otherSigner)) {
// Other signer not on this wallet or operation does not match arguments
throw;
}
if (otherSigner == msg.sender) {
// Cannot approve own transaction
throw;
}
return otherSigner;
}
/**
* Irrevocably puts contract into safe mode. When in this mode, transactions may only be sent to signing addresses.
*/
function activateSafeMode() onlysigner {
safeMode = true;
SafeModeActivated(msg.sender);
}
/**
* Determine if an address is a signer on this wallet
* @param signer address to check
* returns boolean indicating whether address is signer or not
*/
function isSigner(address signer) returns (bool) {
// Iterate through all signers on the wallet and
for (uint i = 0; i < signers.length; i++) {
if (signers[i] == signer) {
return true;
}
}
return false;
}
/**
* Gets the second signer's address using ecrecover
* @param operationHash the sha3 of the toAddress, value, data/tokenContractAddress and expireTime
* @param signature the tightly packed signature of r, s, and v as an array of 65 bytes (returned by eth.sign)
* returns address recovered from the signature
*/
function recoverAddressFromSignature(bytes32 operationHash, bytes signature) private returns (address) {
if (signature.length != 65) {
throw;
}
// We need to unpack the signature, which is given as an array of 65 bytes (from eth.sign)
bytes32 r;
bytes32 s;
uint8 v;
assembly {
r := mload(add(signature, 32))
s := mload(add(signature, 64))
v := and(mload(add(signature, 65)), 255)
}
if (v < 27) {
v += 27; // Ethereum versions are 27 or 28 as opposed to 0 or 1 which is submitted by some signing libs
}
return ecrecover(operationHash, v, r, s);
}
/**
* Verify that the sequence id has not been used before and inserts it. Throws if the sequence ID was not accepted.
* We collect a window of up to 10 recent sequence ids, and allow any sequence id that is not in the window and
* greater than the minimum element in the window.
* @param sequenceId to insert into array of stored ids
*/
function tryInsertSequenceId(uint sequenceId) onlysigner private {
// Keep a pointer to the lowest value element in the window
uint lowestValueIndex = 0;
for (uint i = 0; i < SEQUENCE_ID_WINDOW_SIZE; i++) {
if (recentSequenceIds[i] == sequenceId) {
// This sequence ID has been used before. Disallow!
throw;
}
if (recentSequenceIds[i] < recentSequenceIds[lowestValueIndex]) {
lowestValueIndex = i;
}
}
if (sequenceId < recentSequenceIds[lowestValueIndex]) {
// The sequence ID being used is lower than the lowest value in the window
// so we cannot accept it as it may have been used before
throw;
}
if (sequenceId > (recentSequenceIds[lowestValueIndex] + 10000)) {
// Block sequence IDs which are much higher than the lowest value
// This prevents people blocking the contract by using very large sequence IDs quickly
throw;
}
recentSequenceIds[lowestValueIndex] = sequenceId;
}
/**
* Gets the next available sequence ID for signing when using executeAndConfirm
* returns the sequenceId one higher than the highest currently stored
*/
function getNextSequenceId() returns (uint) {
uint highestSequenceId = 0;
for (uint i = 0; i < SEQUENCE_ID_WINDOW_SIZE; i++) {
if (recentSequenceIds[i] > highestSequenceId) {
highestSequenceId = recentSequenceIds[i];
}
}
return highestSequenceId + 1;
}
}
Type | Name | Constant | Signature |
---|---|---|---|
function | parentAddress() => ( address) | true | 0x00821de3 |
function | flushTokens(tokenContractAddress address) | false | 0x3ef13367 |
function | flush() | false | 0x6b9f96ea |
constructor | () | ||
fallback | |||
event | ForwarderDeposited(from address, value uint256, data bytes) | 0x69b31548dea9b3b707b4dff357d326e3e9348b24e7a6080a218a6edeeec48f9b | |
event | TokensFlushed(tokenContractAddress address, value uint256) | 0x9401e4e79c19cbe2bd774cb70a94ba660e6718be1bac1298ab3b07f454a60821 |
[
{
"constant": true,
"inputs": [],
"name": "parentAddress",
"outputs": [
{
"name": "",
"type": "address"
}
],
"payable": false,
"type": "function",
"signature": "0x00821de3"
},
{
"constant": false,
"inputs": [
{
"name": "tokenContractAddress",
"type": "address"
}
],
"name": "flushTokens",
"outputs": [],
"payable": false,
"type": "function",
"signature": "0x3ef13367"
},
{
"constant": false,
"inputs": [],
"name": "flush",
"outputs": [],
"payable": false,
"type": "function",
"signature": "0x6b9f96ea"
},
{
"inputs": [],
"payable": false,
"type": "constructor"
},
{
"payable": true,
"type": "fallback"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"name": "from",
"type": "address"
},
{
"indexed": false,
"name": "value",
"type": "uint256"
},
{
"indexed": false,
"name": "data",
"type": "bytes"
}
],
"name": "ForwarderDeposited",
"type": "event",
"signature": "0x69b31548dea9b3b707b4dff357d326e3e9348b24e7a6080a218a6edeeec48f9b"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"name": "tokenContractAddress",
"type": "address"
},
{
"indexed": false,
"name": "value",
"type": "uint256"
}
],
"name": "TokensFlushed",
"type": "event",
"signature": "0x9401e4e79c19cbe2bd774cb70a94ba660e6718be1bac1298ab3b07f454a60821"
}
]
bzz://d0f8838ba17108a895d34ae8ef3bff4e0dc9d639c3c51921fee1d17eaa803721
6060604052361561003a5763ffffffff60e060020a600035041662821de381146100eb5780633ef133671461011a5780636b9f96ea1461013b575b5b60008054600160a060020a0316903490366040518083838082843782019150509250505060006040518083038185876187965a03f192505050151561007f57600080fd5b7f69b31548dea9b3b707b4dff357d326e3e9348b24e7a6080a218a6edeeec48f9b3334600036604051600160a060020a0385168152602081018490526060604082018181529082018390526080820184848082843782019150509550505050505060405180910390a15b005b34156100f657600080fd5b6100fe610150565b604051600160a060020a03909116815260200160405180910390f35b341561012557600080fd5b6100e9600160a060020a036004351661015f565b005b341561014657600080fd5b6100e96102dc565b005b600054600160a060020a031681565b600080548190819033600160a060020a0390811691161461017f57600080fd5b83925030915082600160a060020a03166370a082318360006040516020015260405160e060020a63ffffffff8416028152600160a060020a039091166004820152602401602060405180830381600087803b15156101dc57600080fd5b6102c65a03f115156101ed57600080fd5b5050506040518051915050801515610204576102d5565b60008054600160a060020a038086169263a9059cbb929091169084906040516020015260405160e060020a63ffffffff8516028152600160a060020a0390921660048301526024820152604401602060405180830381600087803b151561026a57600080fd5b6102c65a03f1151561027b57600080fd5b50505060405180519050151561029057600080fd5b7f9401e4e79c19cbe2bd774cb70a94ba660e6718be1bac1298ab3b07f454a608218482604051600160a060020a03909216825260208201526040908101905180910390a15b5b50505050565b600054600160a060020a039081169030163160405160006040518083038185876187965a03f192505050151561031157600080fd5b5b5600a165627a7a72305820d0f8838ba17108a895d34ae8ef3bff4e0dc9d639c3c51921fee1d17eaa8037210029
Transaction 0x7fedbc2701fbbc45d476689a62bc9c79cbfc53fd1b474190f0e6653221216055 on the 2019-06-12T08:57:14+00:00 (6 months ago).