自分：A  
ERC20トークン：Coin  
ERC20トークン：Fund  
両トークンのDeployerは同じアカウント：Z  
相手：B

AがFundをBurnする際に、同量のCoinをZからBに移動したい  
AからBに「ありがとう」を送ると、ZからBにCoinが支払われるような使い方です

開発はRemixのVMでしています

CoinのSolidty

```

    // SPDX-License-Identifier: GPL-2.0
    pragma solidity ^0.6.0;
    
    import "https://github.com/OpenZeppelin/openzeppelin-contracts/contracts/token/ERC20/ERC20.sol";
    import "https://github.com/OpenZeppelin/openzeppelin-contracts/contracts/token/ERC20/SafeERC20.sol";
    
    contract Coin is ERC20 {
        address private _MakerAddress;
        string private _Message = "";
        string public version;
    
        constructor(
            string memory name,
            string memory symbol,
            uint256 initial_supply,
            string memory version_
        ) public ERC20(name, symbol) {
            _MakerAddress = msg.sender;
            _mint(msg.sender, initial_supply);
            version = version_;
        }
    
        function addCoin(uint256 ammount) public returns (uint256){
            _mint(msg.sender, ammount);
        }
    
        function transferWithMessage(address recipient, uint256 amount, string memory message) public payable returns (bool){
            _Message = message;
            _transfer(_msgSender(), recipient, amount);
            return true;
        }
    
        function getMakerAddress() public view returns (address) {
            return _MakerAddress;
        }
    }
    
```

FundのSolidty

```

    // SPDX-License-Identifier: GPL-2.0
    pragma solidity ^0.6.0;
    
    import "https://github.com/OpenZeppelin/openzeppelin-contracts/contracts/token/ERC20/ERC20.sol";
    import "https://github.com/OpenZeppelin/openzeppelin-contracts/contracts/token/ERC20/SafeERC20.sol";
    import "https://github.com/OpenZeppelin/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol";
    
    contract FundManager is ERC20 {
        address private _MakerAddress;
        string private _Message = "";
        string private _version = "";
        address payable private _coinTokenOwner;
        IERC20 private _coinToken;
    
        event Realize(uint256 amount, address receiver, string message);
    
        constructor(
            string memory name,
            string memory symbol,
            uint256 initial_supply,
            string memory version,
            address payable coinTokenOwner,
            IERC20 coinToken
        ) public ERC20(name, symbol) {
            _MakerAddress = msg.sender;
            _mint(msg.sender, initial_supply);
            _version = version;
            _coinTokenOwner = coinTokenOwner;
            _coinToken = coinToken;
        }
    
        function addFund(uint256 ammount) public returns (uint256) {
            _mint(msg.sender, ammount);
        }
    
        function getVersion() public view returns (string memory) {
            return _version;
        }
    
        function getMakerAddress() public view returns (address) {
            return _MakerAddress;
        }
    
        function realize(uint256 _amount, address _receiver, string memory _message) public {
            emit Realize(_amount, _receiver, _message);
            super._burn(msg.sender, _amount);
            _coinToken.approve(_coinTokenOwner, _amount);
            _coinToken.transferFrom(_coinTokenOwner, _receiver, _amount);
        }
    }
    
```

`realize`がFundをBurnして、送金したい関数です

FundをZからAに送るところまでは動作するのですが、Aが`realize`を実行すると下記のエラーになりました

```

    transact to FundManager.realize errored: VM error: revert. revert The transaction has been reverted to the initial state. Reason provided by the contract: "ERC20: transfer amount exceeds allowance". Debug the transaction to get more information.
    
```

`transferFrom`は第三者間の送金に使用できるとあったのですが、使い方間違っていますでしょうか?

自分で作っていながら、自分のリクエストで他人のトークンを移動するのは技術的に不可能ではないかと思い始めています  
その場合のアイデアもいただけると助かります

追加情報です  
記載方法に指摘があったのでまとめになります

FundManagerを考えなおしました  
(テストで何度も実行できるようにBurnの部分削除しています)

```

    // SPDX-License-Identifier: GPL-2.0
    pragma solidity ^0.6.0;
    
    import "https://github.com/OpenZeppelin/openzeppelin-contracts/contracts/token/ERC20/ERC20.sol";
    import "https://github.com/OpenZeppelin/openzeppelin-contracts/contracts/token/ERC20/SafeERC20.sol";
    
    import "https://github.com/OpenZeppelin/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol";
    
    contract FundManager is ERC20 {
        address private _MakerAddress;
        string private _Message = "";
        string private _version = "";
        address private _coinTokenOwner;
        IERC20 private _coinToken;
    
        event Realize(uint256 amount, address receiver, string message);
    
        constructor(
            string memory name,
            string memory symbol,
            uint256 initial_supply,
            string memory version,
            address coinTokenOwner,
            IERC20 coinToken
        ) public ERC20(name, symbol) {
            _MakerAddress = msg.sender;
            _mint(msg.sender, initial_supply);
            _version = version;
            _coinTokenOwner = coinTokenOwner;
            _coinToken = coinToken;
        }
    
        function realizeAllowance(uint256 _amount, address _receiver, string memory _message) public returns (bool) {
            require(_amount > 0);
            require(_receiver != address(0));
    
            emit Realize(_amount, _receiver, _message);
    
            _coinToken.allowance(_coinTokenOwner, _receiver);
    
            return true;
        }
    
        function realizeApproval(address _receiver, uint256 _amount) public returns (bool) {
            require(_amount > 0);
            require(msg.sender != address(0));
    
            _coinToken.approve(_receiver, _amount);
            return true;
        }
    
        function realizeTransferFrom(address _receiver, uint256 _amount) public returns (bool) {
            require(_amount > 0);
            require(msg.sender != address(0));
            require(_receiver != address(0));
    
            _coinToken.transferFrom(_coinTokenOwner, _receiver, _amount);
    
            return true;
        }
    }
    
```

`realizeAllowance` 自分(A)として実行  
`realizeApproval` Owner(Z)として実行  
`realizeTransferFrom` 自分(A)として実行

`realizeApproval` Owner(Z)として実行しているつもりでしたが、Fundから実行しているため、Fundのアドレスになっていました  
owner : Fundのアドレス  
spender : B  
で実行すると値が取れました  
Fundからapproveすることは間違っているのでしょうか

役にたつと幸いです
CC BY-SA 4.0
2020-12-24T04:35:10.633
72853
2020-12-24T09:15:40.117
2020-12-24T08:09:10.800
27721
27721
question
ethereum solidity
Solidity ERC20トークンを第三者間で移動したいがエラーになる
いろいろ見直し以下の内容で一応動作しました  
Burnの部分まだいれていないですが

```

    // SPDX-License-Identifier: GPL-2.0
    pragma solidity ^0.6.0;
    
    import "https://github.com/OpenZeppelin/openzeppelin-contracts/contracts/token/ERC20/ERC20.sol";
    import "https://github.com/OpenZeppelin/openzeppelin-contracts/contracts/token/ERC20/SafeERC20.sol";
    
    import "https://github.com/OpenZeppelin/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol";
    
    contract FundManager is ERC20 {
        address private _MakerAddress;
        string private _Message = "";
        string private _version = "";
        address private _coinTokenOwner;
        IERC20 private _coinToken;
    
        event Realize(uint256 amount, address receiver, string message);
    
        constructor(
            string memory name,
            string memory symbol,
            uint256 initial_supply,
            string memory version,
            address coinTokenOwner,
            IERC20 coinToken
        ) public ERC20(name, symbol) {
            _MakerAddress = msg.sender;
            _mint(msg.sender, initial_supply);
            _version = version;
            _coinTokenOwner = coinTokenOwner;
            _coinToken = coinToken;
        }
    
        function addFund(uint256 ammount) public returns (uint256) {
            _mint(msg.sender, ammount);
        }
    
        function getVersion() public view returns (string memory) {
            return _version;
        }
    
        function getMakerAddress() public view returns (address) {
            return _MakerAddress;
        }
    
        function realize(uint256 _amount, address _receiver, string memory _message) public returns (bool) {
            require(msg.sender != address(0));
            require(_amount > 0);
            require(_receiver != address(0));
    
            emit Realize(_amount, _receiver, _message);
    
            _coinToken.allowance(address(this), _receiver);
            _coinToken.approve(_receiver, _amount);
            _coinToken.transfer(_receiver, _amount);
    
            return true;
        }
        
        function getCoinBalance() public view returns (uint256) {
            return _coinToken.balanceOf(address(this));
        }
    }
    
```

スマートコントラクトからスマートコントラクトにアクセスする場合のアドレスが実行時のアドレスではなく「スマートコントラクトのアドレスになる」ということが分かっていなかったのが問題の発端のようです

セキュリティ的にとか問題があれば指摘いただけると助かります

ありがとうございました
CC BY-SA 4.0
2020-12-24T09:15:40.117
72861
2020-12-24T09:15:40.117
27721
72853
answer