Erc-20

從多個地址收集 ERC20 餘額?

  • December 28, 2018

我正在建構一個 dApp,其中涉及為 ERC20 存款的個人使用者創建唯一帳戶

$$ I keep the addresses and private keys in a centralized database $$,對於流行的 ERC20 代幣,如 BNB、0x 等。但是,為了發揮作用,我的 dApp 需要將所有這些餘額收集到一個中央錢包中。由於這些是 ERC20 存款而不是 ETH 存款,因此使用者錢包中沒有存放 ETH,因此無法支付用於將其 ERC20 餘額發送到中央錢包的 gas。 有誰知道這個問題的有效解決方案?我幼稚的解決方案是,每次我檢測到一個 ERC20 存入該錢包時,就將 ETH 發送到使用者的錢包中,這樣該錢包就可以支付傳輸的 gas,但這很醜陋,而且看起來像很多 gas 成本。

謝謝!

今天有兩種方法可以做到:

1.普通賬戶

生成您的使用者轉移到的錢包密鑰/地址,並且您必須向這些地址發送氣體才能轉移資金。

缺點:

  • 收集資金需要您將氣體發送到這些地址,這最終會導致灰塵堆積在這些地址中
  • 儲存和管理帳戶私鑰可能會成為一項挑戰
  1. 智能合約賬戶 =========

部署一個智能合約工廠,生成一個主“賬戶可以控制”的“接收地址”。

本質上,您有一個智能合約,可以創建儲存收到資金的新地址,並且您有一個“所有者”地址,可以呼叫一種方法來轉移資金。

工廠智能合約

有多種方法可以實現這一點:

Factory 合約可以實現所有權驗證並控制接收者,或者每個接收者可以自己進行驗證。

我能想到的最佳實施、安全性和性能方面如下:

工廠契約:

  • 有一個所有者(所有者可以更改)
  • 所有者可以創建新的“接收者”
  • 工廠索引映射中的接收器( uint => address )
  • 所有者可以從接收者契約中收取或返還資金
  • 接受批量呼叫以便從多個接收方收取/退款

如果您想降低 gas 使用量並實施硬體簽名,批處理很重要

考慮使用單獨的伺服器進行簽名,您甚至可以將外部硬體錢包插入其中,或者 HSM(硬體簽名模組)。

這裡最棒的部分是你甚至可以通過這樣的方式來實現它,你可以從任何基於乙太坊的智能合約/令牌跟踪器(BNB / DAI / 等)或使用自定義呼叫者介面的任何令牌標準收集令牌(你可以呼叫您想要的任何地址的任意方法)。

無需向這些接收者發送 gas,因為所有者是“發送交易”的一方,而“接收者合約是代幣的所有者”

用於部署和與接收器互動的廉價 gas,因為您可以在網路不擁塞時執行此操作,並且能夠與 GasToken ( gastoken.io ) 集成以進一步降低您的價格。

希望這可以幫助。

範例起始程式碼

pragma solidity ^0.4.25;

/*
   Just the interface so solidity can compile properly
   We could skip this if we use generic call creation or abi.encodeWithSelector
*/
contract ERC20 {
   function totalSupply() public constant returns (uint);
   function balanceOf(address tokenOwner) public constant returns (uint balance);
   function allowance(address tokenOwner, address spender) public constant returns (uint remaining);
   function transfer(address to, uint tokens) public returns (bool success);
   function approve(address spender, uint tokens) public returns (bool success);
   function transferFrom(address from, address to, uint tokens) public returns (bool success);
   event Transfer(address indexed from, address indexed to, uint tokens);
   event Approval(address indexed tokenOwner, address indexed spender, uint tokens);
}

/*
   Generic Receiver Contract
*/
contract Receiver {
   
   address public owner;

   constructor() public {
       /* 
           Deployer's address ( Factory in our case )
           do not pass this as a constructor argument because 
           etherscan will have issues displaying our validated source code
       */
       owner = msg.sender;
   }
   
   /*
       @notice Send funds owned by this contract to another address
       @param tracker  - ERC20 token tracker ( DAI / MKR / etc. )
       @param amount   - Amount of tokens to send
       @param receiver - Address we're sending these tokens to
       @return true if transfer succeeded, false otherwise 
   */
   function sendFundsTo( address tracker, uint256 amount, address receiver) public returns ( bool ) {
       // callable only by the owner, not using modifiers to improve readability
       require(msg.sender == owner);
       
       // Transfer tokens from this address to the receiver
       return ERC20(tracker).transfer(receiver, amount);
   }
   
   // depending on your system,  you probably want to suicide this at some
   // point in the future, or reuse it for other clients
}

/*
   Factory Contract
*/

contract Factory {
   
   address public owner;
   mapping ( uint256 => address ) public receiversMap;
   uint256 receiverCount = 0;
   
   constructor() public {
       /* 
           Deployer's address ( Factory in our case )
           do not pass this as a constructor argument because 
           etherscan will have issues displaying our validated source code
       */
       owner = msg.sender;
   }
   
   /*
       @notice Create a number of receiver contracts
       @param number  - 0-255 
   */
   function createReceivers( uint8 number ) public {
       require(msg.sender == owner);

       for(uint8 i = 0; i < number; i++) {
           // Create and index our new receiver
           receiversMap[++receiverCount] = new Receiver();
       }
       // add event here if you need it
   }
   
   /*
       @notice Send funds in a receiver to another address
       @param ID       - Receiver indexed ID
       @param tracker  - ERC20 token tracker ( DAI / MKR / etc. )
       @param amount   - Amount of tokens to send
       @param receiver - Address we're sending tokens to
       @return true if transfer succeeded, false otherwise 
   */
   function sendFundsFromReceiverTo( uint256 ID, address tracker, uint256 amount, address receiver ) public returns (bool) {
       require(msg.sender == owner);
       return Receiver( receiversMap[ID] ).sendFundsTo( tracker, amount, receiver);
   }
   
   /*
       Batch Collection - Should support a few hundred transansfers
       
       @param tracker           - ERC20 token tracker ( DAI / MKR / etc. )
       @param receiver          - Address we're sending tokens to
       @param contractAddresses - we send an array of addresses instead of ids, so we don't need to read them ( lower gas cost )
       @param amounts           - array of amounts 

   */
   function batchCollect( address tracker, address receiver, address[] contractAddresses, uint256[] amounts ) public {
       require(msg.sender == owner);
       
       for(uint256 i = 0; i < contractAddresses.length; i++) {
           
           // add exception handling
           Receiver( contractAddresses[i] ).sendFundsTo( tracker, amounts[i], receiver);
       }
   }
   
}

全部

  • 添加所有權變更
  • 添加視圖以讀取指定跟踪器的接收器餘額
  • 在需要的地方添加事件
  • 在 batchCollect 中添加異常處理

流動:

  • 1.部署工廠合約
  • 2.呼叫Factory合約上的createReceivers
  • 3.將一些測試令牌發送到receiversMap中映射的接收器
  • 4.呼叫 Factory 上的 sendFundsFromReceiverTo將所述代幣移動到新地址

引用自:https://ethereum.stackexchange.com/questions/64686