Diseño de contrato inteligente: contrato de fideicomiso/controlador

¿Cómo haría para crear el siguiente
contrato de depósito en garantía/controlador A que es capaz de aceptar tokens ERC20 del contrato B y ETH de la parte C y hacer un intercambio cuando se cumplen ciertas condiciones?

Este mismo contrato A también debería poder recibir tokens ERC20 del contrato D y ETH del contrato E y hacer un intercambio cuando se cumplan ciertas condiciones.

La captura/relevancia de la pregunta es , ¿cómo diseñar el contrato A para poder manejar entradas de token ERC20 de diferentes tipos, por ejemplo, tokens ERC20 de Walton (WTC) y FUSION (FSN)?

Respuestas (1)

Aquí es donde entran en juego las interfaces. Eso es genial, ¡porque ERC-20 es en realidad una interfaz! Te daré un ejemplo a continuación. Como puede ver, TokenSwapperni siquiera necesita saber acerca de TokenAand TokenB, solo que implementan la ERC20interfaz.

Ah, y antes de comenzar a desarrollar, primero debe familiarizarse con los conceptos básicos de la interfaz ERC20. lee este wiki

pragma solidity ^0.4.23;

/* Declaring the ERC20 interface. This tells
   other contracts how to handle ERC-20 tokens */
interface ERC20 {
    function allowance(address owner, address spender)
    external view returns (uint256);

    function transferFrom(address from, address to, uint256 value)
    external returns (bool);

    function approve(address spender, uint256 value) external returns (bool);

    function totalSupply() external view returns (uint256);
    function balanceOf(address who) external view returns (uint256);
    function transfer(address to, uint256 value) external returns (bool);
}


/* a simple base ERC token contract for testing */
/* DO NOT USE FOR PRODUCTION AS IT IS NOT SAFE */
contract ERC20Token is ERC20 {
    uint256 totalSupply_;

    mapping (address => mapping (address => uint256)) internal allowed;
    mapping(address => uint256) balances;

    function totalSupply() public view returns (uint256) {
        return totalSupply_;
    }

    function transfer(address _to, uint256 _value) external returns (bool) {
        require(_to != address(0));
        require(_value <= balances[msg.sender]);


        balances[msg.sender] -= _value;
        balances[_to] += _value;

        return true;
    }

    function balanceOf(address _owner) public view returns (uint256) {
        return balances[_owner];
    }

      function transferFrom(
        address _from,
        address _to,
        uint256 _value
    )
        public
        returns (bool)
    {
        require(_to != address(0));
        require(_value <= balances[_from]);
        require(_value <= allowed[_from][msg.sender]);

        balances[_from] -= _value;
        balances[_to] += _value;
        allowed[_from][msg.sender] -= _value;

        return true;
    }

    function approve(address _spender, uint256 _value) public returns (bool) {
        allowed[msg.sender][_spender] = _value;
        return true;
    }

    function allowance(
        address _owner,
        address _spender
    )
    public
    view
    returns (uint256)
    {
        return allowed[_owner][_spender];
    }
}

/* The tokens inherit their functionality from ERC20Token */
contract TokenA is ERC20Token {
}

contract TokenB is ERC20Token {
}

contract TokenC is ERC20Token {
}
contract TokenD is ERC20Token {
}

/* DO NOT USE IN PRODUCTION AS IT DOESN'T CHECK FOR UNDERFLOW/OVERFLOW */
contract TokenSwapper {
    // Keeps track of the tokens users have
    mapping(address => mapping(address => uint256)) tokenBalances_;

    function tokenBalances(address _owner, ERC20 _token) public view returns (uint256 balance) {
        return balance = tokenBalances_[_owner][_token];
    }

    function deposit(ERC20 _token, uint256 _amount) public {
        _token.transferFrom(msg.sender, address(this), _amount);
        tokenBalances_[msg.sender][_token] += _amount;
    }

    function swap(ERC20 _fromToken, ERC20 _toToken, uint256 _amount) public {
        tokenBalances_[msg.sender][_fromToken] -= _amount;
        tokenBalances_[msg.sender][_toToken] += _amount;
    }

    function withdraw(ERC20 _token, uint256 _amount) public {
        require(tokenBalances_[msg.sender][_token] >= _amount);

        _token.transfer(msg.sender, _amount);
    }
}
Henk, ¿entonces 'TokenSwapper' puede contener cualquier tipo de erc20token en tokenBalances, junto con la dirección especificada? ¿No hay necesidad de generar un objeto desde la interfaz inicialmente como en las ventas colectivas? por ejemplo, token público ERC20; gracias por responder, las interfaces me han estado molestando por un tiempo... ¿no es posible transferir ERC20 en lugar de transferFrom?
Si eso es correcto. El uso transferno es seguro, ya que el contrato inteligente no puede detectar cuándo recibió tokens
tal vez esta sea una pregunta estúpida, pero ¿qué pasa si la interfaz se llama 'Token' o algo más, aún podría usar ERC20 como el tipo de argumento de entrada para _token? en el contrato TokenSwapper?
Sí, el nombre no importa. Los nombres de las funciones, como sea que se declaren en la interfaz, sí importan.
¿Cómo sabe TokenSwapper que tiene que usar una interfaz si no es heredada por el contrato o especificada dentro del contrato? muchas gracias por despejar mis cuellos de botella!