Giter Site home page Giter Site logo

youwallet / wallet Goto Github PK

View Code? Open in Web Editor NEW
118.0 14.0 55.0 27.32 MB

🚀 基于Flutter开发的跨终端数字货币交易所✨

Home Page: https://youwallet.github.io/

Kotlin 0.09% Ruby 0.29% Swift 0.09% Objective-C 0.01% Dart 86.21% CSS 6.20% HTML 7.12%
eth ethereum dapp token contracts

wallet's People

Contributors

ben7th avatar davidliu027 avatar georgeliuyu avatar zhaobinglong avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

wallet's Issues

APP内测流程

安卓手机点击安装apk:

https://github.com/youwallet/wallet/blob/zhaobinglong/application-init/you_wallet/app-release.apk

新建或者导入钱包

image

添加测试token

contract tokena address: 0x6C3118c39FAB22caF3f9910cd054F8ea435B5FFB
contract tokenb address: 0xe898663A2CbDf7a371bB4B6a5dd7aC93d4505C9a
contract tokenc address: 0xEAB3A69a992aeC845099717B148DC1995DD57685
contract tokend address: 0x2e01154391F7dcBf215c77DBd7fF3026Ea7514ce

获取测试以太币

https://faucet.metamask.io/

image

联系李飞获取测试用token

image

发起交易

钱包必须有以太币才发起交易才会成功
image

RPCError: got code -32000 with msg "invalid sender".

解决:

          credentials,
          Transaction(
              to: EthereumAddress.fromHex(token['address']),
              gasPrice: EtherAmount.inWei(BigInt.from(1000000000)),
              maxGas: 7000000,
              value: EtherAmount.fromUnitAndValue(EtherUnit.ether, 0),
              data: hexToBytes(postData)
          ),
          chainId: 3 // 没有这个参数会报RPCError: got code -32000 with msg "invalid sender".
      );

【接口】买入和卖出

SHT智能合约:https://etherscan.io/address/0x3d9c6c5a7b2b2744870166eac237bd6e366fa3ef
参考:https://github.com/youwallet/public/blob/yx/doc/interface.txt
参考:https://github.com/youwallet/wallet/wiki/%E6%B5%8B%E8%AF%95%E5%BC%80%E5%8F%91%E7%94%A8%E5%90%88%E7%BA%A6%E4%BF%A1%E6%81%AF

离线加密:https://github.com/youwallet/wallet/wiki/%E4%B8%80%E6%AE%B5-JS-%E8%B0%83%E7%94%A8%E5%90%88%E7%BA%A6%E7%9A%84%E7%A4%BA%E4%BE%8B%E4%BB%A3%E7%A0%81

contract YouWalletToken address: 0xC13D3E66BB3373596815070CA8f67a50cb0cF104
contract Proxy address: 0x6DAA5e785436eE200c66fA7500ae1925D6Cb727d
contract HybridExchange address: 0x9e23144B8bfC2A12187482708ccf19cC667135CC
contract TempMatch address: 0x7E999360d3327fDA8B0E339c8FC083d8AFe6A364

contract tokena address: 0x8F48de31810deaA8bF547587438970EBD2e4be16
contract tokenb address: 0x414b26708362B024A28C7Bc309D5C1a8Ac14647E

  • 1. 本地生成钱包地址
  • 2. 连接ropsten.infura.io网络
  • 3. 对选择的token进行授权
  • 4. 对交易签名
  • 5. 发起交易
/* 交易签名数据
 * config: 包含签名v和签名方法(各占以1个字节, 其它字节缺省)
 * r: 签名r
 * s: 签名s
 * */
struct OrderSignature {
    bytes32 config;
    bytes32 r;
    bytes32 s;
}

/* 订单参数
 * trader: taker 地址
 * baseTokenAmount: 交易token的数量
 * quoteTokenAmount: 报价token的数量
 * gasTokenAmount: 交易费用token的数量,一般默认0
 * data: 交易参数的设置, 包含hydro版本号、交易买卖标志等, 生成方式参见接口getConfigData
 * signature: 交易签名数据, 包含签名的vrs, 以及签名方法, 生成方式参见接口 getConfigSignature
 */
struct OrderParam {
    address trader;
    uint256 baseTokenAmount;
    uint256 quoteTokenAmount;
    uint256 gasTokenAmount;
    bytes32 data;
    OrderSignature signature;
}
/* 订单地址集合
 * baseToken: 交易token的合约地址
 * quoteToken: 报价token的合约地址
 * relayer: 交易费用接收账户地址
 * */
struct OrderAddressSet {
    address baseToken;
    address quoteToken;
    address relayer; // 千分之六的交易费会打入这个地址,随便一个
}
/* 发起订单
 * takerOrderParam: 订单参数
 * orderAddressSet: 订单地址集合
 * */
function takeOrder(OrderParam takerOrderParam, OrderAddressSet orderAddressSet);


/* 获取交易签名数据
 * v: 签名v值
 * r: 签名r值
 * s: 签名s值
 * signMethod: 签名方法, 0为eth.sign, 1为EIP712
 *
 * 返回值:
 * OrderSignature 结构体
 * */
function getConfigSignature(bytes1 v,  bytes32 r, bytes32 s, uint8 signMethod);

[讨论]app前端开发计划

时间节点 内容 备注
10.1 / 11.15 前端所有页面开发完毕,达到每个页面可以查看,所有按钮点击,路由跳转正确,发布一个静态的app不带后端服务
11.15 / 11.30 后端接口对接完毕,前端所有的页面均可以显示正常的数据
11.30 / 12.15 前后端协同测试,在15号之前尽可能解决所有发现的问题
12.15 / 12.30 预发布,app先上一个版本,邀请种子用户和开发者进行内测,解决内测发现的问题
2020.01.01 app 1.0正式上线,普通用户可以进行下载安装

【调试】实现测试用 UI

目的:

  • 封装前端使用的业务逻辑相关函数
  • 通过一个界面上的按钮来测试所有函数
  • 输出函数执行结果

20190902周任务协调

本地权限,相机/相册/指纹本地调试跑通 @赵冰龙
前端代码结构搭建 @hnuyx 宋亮可以建个单独的issue预估dealine与size,一个size先按一个理想人于预估。
分配前端页面组件任务 @hnuyx @zhaobinglong 你们如果分好的话每个组件可以单独建个issue。

内测问题汇总

问题汇总如下,H高优先级,M中优先 级,L低优先级

  • H 首页-下拉刷新;
  • M 首页-钱包名称旁加二维码,点击进入收款页面;
  • H 钱包-导出私钥;
  • M 转帐-先隐藏转帐模式手续费的选择,慢中快速,手续费改成“矿工费用”
  • Q gaslimit计算资源,gasprice单价,矿工费=花费gas数量Xgasprice,@用心;
  • H 兑换-TOKEN资产根据钱包/网络切换刷新;
  • H 兑换-切换TOKEN组合,刷新交易历史和深度;
  • H 兑换-交易深度没有显示;
  • M 兑换-切换买入卖出时页面字体和背景都需要变化;
  • H 兑换-买单卖单没有自动撮合;
  • H 兑换-页面;
  • 兑换历史记录是否可以从链上获取,@用心;

image
image

Warning: Podfile is out of date

安卓studio一个警告错误:

This can cause a mismatched version of Flutter to be embedded in your app,
 which may result in App Store submission rejection or crashes.
 If you have local Podfile edits you would like to keep, 
see https://github.com/flutter/flutter/issues/24641 for instructions.
To regenerate the Podfile, run:
  rm ios/Podfile

【文档】SHT智能合约

/**
 *Submitted for verification at Etherscan.io on 2018-11-17
*/

pragma solidity ^0.4.24;
// produced by the Solididy File Flattener (c) David Appleton 2018
// contact : [email protected]
// released under Apache 2.0 licence
// input  /home/henry/learning/git/smartContract/truffle/022-sht/contracts-bak/SibbayHealthToken.sol
// flattened :  Saturday, 17-Nov-18 06:24:45 UTC
contract Ownable {
  address public owner;


  event OwnershipRenounced(address indexed previousOwner);
  event OwnershipTransferred(
    address indexed previousOwner,
    address indexed newOwner
  );


  /**
   * @dev The Ownable constructor sets the original `owner` of the contract to the sender
   * account.
   */
  constructor() public {
    owner = msg.sender;
  }

  /**
   * @dev Throws if called by any account other than the owner.
   */
  modifier onlyOwner() {
    require(msg.sender == owner);
    _;
  }

  /**
   * @dev Allows the current owner to transfer control of the contract to a newOwner.
   * @param newOwner The address to transfer ownership to.
   */
  function transferOwnership(address newOwner) public onlyOwner {
    require(newOwner != address(0));
    emit OwnershipTransferred(owner, newOwner);
    owner = newOwner;
  }

  /**
   * @dev Allows the current owner to relinquish control of the contract.
   */
  function renounceOwnership() public onlyOwner {
    emit OwnershipRenounced(owner);
    owner = address(0);
  }
}

contract ERC20Basic {
  function totalSupply() public view returns (uint256);
  function balanceOf(address who) public view returns (uint256);
  function transfer(address to, uint256 value) public returns (bool);
  event Transfer(address indexed from, address indexed to, uint256 value);
}

library SafeMath {

  /**
  * @dev Multiplies two numbers, throws on overflow.
  */
  function mul(uint256 a, uint256 b) internal pure returns (uint256 c) {
    if (a == 0) {
      return 0;
    }
    c = a * b;
    assert(c / a == b);
    return c;
  }

  /**
  * @dev Integer division of two numbers, truncating the quotient.
  */
  function div(uint256 a, uint256 b) internal pure returns (uint256) {
    // assert(b > 0); // Solidity automatically throws when dividing by 0
    // uint256 c = a / b;
    // assert(a == b * c + a % b); // There is no case in which this doesn't hold
    return a / b;
  }

  /**
  * @dev Subtracts two numbers, throws on overflow (i.e. if subtrahend is greater than minuend).
  */
  function sub(uint256 a, uint256 b) internal pure returns (uint256) {
    assert(b <= a);
    return a - b;
  }

  /**
  * @dev Adds two numbers, throws on overflow.
  */
  function add(uint256 a, uint256 b) internal pure returns (uint256 c) {
    c = a + b;
    assert(c >= a);
    return c;
  }
}

contract Management is Ownable {

  /**
   * 暂停和取消暂停事件
   * */
  event Pause();
  event Unpause();

  /**
   * 打开锁定期自动释放事件
   * 关闭锁定期自动释放事件
   * 打开强制锁定期自动释放事件
   * */
  event OpenAutoFree(address indexed admin, address indexed who);
  event CloseAutoFree(address indexed admin, address indexed who);
  event OpenForceAutoFree(address indexed admin, address indexed who);

  /**
   * 增加和删除管理员事件
   * */
  event AddAdministrator(address indexed admin);
  event DelAdministrator(address indexed admin);

  /**
   * 合约暂停标志, True 暂停,false 未暂停
   * 锁定余额自动释放开关
   * 强制锁定余额自动释放开关
   * 合约管理员
   * */
  bool public paused = false;
  mapping(address => bool) public autoFreeLockBalance;          // false(default) for auto frce, true for not free
  mapping(address => bool) public forceAutoFreeLockBalance;     // false(default) for not force free, true for froce free
  mapping(address => bool) public adminList;

  /**
   * 构造函数
   * */
  constructor() public {
  }

  /**
   * modifier 要求合约正在运行状态
   */
  modifier whenNotPaused() {
    require(!paused);
    _;
  }

  /**
   * modifier 要求合约暂停状态
   */
  modifier whenPaused() {
    require(paused);
    _;
  }

  /**
   * 要求是管理员
   * */
  modifier whenAdministrator(address who) {
    require(adminList[who]);
    _;
  }

  /**
   * 要求不是管理员
   * */
  modifier whenNotAdministrator(address who) {
    require(!adminList[who]);
    _;
  }

  /**
   * * 暂停合约
   */
  function pause() onlyOwner whenNotPaused public {
    paused = true;
    emit Pause();
  }

  /**
   * 取消暂停合约
   */
  function unpause() onlyOwner whenPaused public {
    paused = false;
    emit Unpause();
  }

  /**
   * 打开锁定期自动释放开关
   * */
  function openAutoFree(address who) whenAdministrator(msg.sender) public {
    delete autoFreeLockBalance[who];
    emit OpenAutoFree(msg.sender, who);
  }

  /**
   * 关闭锁定期自动释放开关
   * */
  function closeAutoFree(address who) whenAdministrator(msg.sender) public {
    autoFreeLockBalance[who] = true;
    emit CloseAutoFree(msg.sender, who);
  }

  /**
   * 打开强制锁定期自动释放开关
   * 该开关只能打开,不能关闭
   * */
  function openForceAutoFree(address who) onlyOwner public {
    forceAutoFreeLockBalance[who] = true;
    emit OpenForceAutoFree(msg.sender, who);
  }

  /**
   * 添加管理员
   * */
  function addAdministrator(address who) onlyOwner public {
    adminList[who] = true;
    emit AddAdministrator(who);
  }

  /**
   * 删除管理员
   * */
  function delAdministrator(address who) onlyOwner public {
    delete adminList[who];
    emit DelAdministrator(who);
  }
}

contract BasicToken is ERC20Basic {
  using SafeMath for uint256;

  /**
   * 账户总余额
   * */
  mapping(address => uint256) balances;

  /**
   * 总供应量
   * */
  uint256 totalSupply_;

  /**
   * 获取总供应量
   * */
  function totalSupply() public view returns (uint256) {
    return totalSupply_;
  }

}

contract ERC20 is ERC20Basic {
  function allowance(address owner, address spender)
    public view returns (uint256);

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

  function approve(address spender, uint256 value) public returns (bool);
  event Approval(
    address indexed owner,
    address indexed spender,
    uint256 value
  );
}

contract StandardToken is ERC20, BasicToken {

  // 记录代理账户
  // 第一个address是token的所有者,即被代理账户
  // 第二个address是token的使用者,即代理账户
  mapping (address => mapping (address => uint256)) internal allowed;

  // 代理转账事件
  // spender: 代理
  // from: token所有者
  // to: token接收账户
  // value: token的转账数量
  event TransferFrom(address indexed spender,
                     address indexed from,
                     address indexed to,
                     uint256 value);


  /**
   * 设置代理
   * _spender 代理账户
   * _value 代理额度
   */
  function approve(address _spender, uint256 _value) public returns (bool) {
    allowed[msg.sender][_spender] = _value;
    emit Approval(msg.sender, _spender, _value);
    return true;
  }

  /**
   * 查询代理额度
   * _owner token拥有者账户
   * _spender 代理账户
   */
  function allowance(
    address _owner,
    address _spender
   )
    public
    view
    returns (uint256)
  {
    return allowed[_owner][_spender];
  }

  /**
   * 提高代理额度
   * _spender 代理账户
   * _addValue 需要提高的代理额度
   */
  function increaseApproval(
    address _spender,
    uint _addedValue
  )
    public
    returns (bool)
  {
    allowed[msg.sender][_spender] = (
      allowed[msg.sender][_spender].add(_addedValue));
    emit Approval(msg.sender, _spender, allowed[msg.sender][_spender]);
    return true;
  }

  /**
   * 降低代理额度
   * _spender 代理账户
   * _subtractedValue 降低的代理额度
   */
  function decreaseApproval(
    address _spender,
    uint _subtractedValue
  )
    public
    returns (bool)
  {
    uint oldValue = allowed[msg.sender][_spender];
    if (_subtractedValue > oldValue) {
      allowed[msg.sender][_spender] = 0;
    } else {
      allowed[msg.sender][_spender] = oldValue.sub(_subtractedValue);
    }
    emit Approval(msg.sender, _spender, allowed[msg.sender][_spender]);
    return true;
  }

}

contract SibbayHealthToken is StandardToken, Management {

  string public constant name = "Sibbay Health Token"; // solium-disable-line uppercase
  string public constant symbol = "SHT"; // solium-disable-line uppercase
  uint8 public constant decimals = 18; // solium-disable-line uppercase

  /**
   * 常量
   * 单位量, 即1个token有多少wei(假定token的最小单位为wei)
   * */
  uint256 constant internal MAGNITUDE = 10 ** uint256(decimals);

  uint256 public constant INITIAL_SUPPLY = 1000000000 * MAGNITUDE;

  // 设置赎回价格事件
  event SetSellPrice(address indexed admin, uint256 price);
  // 锁定期转账事件
  event TransferByDate(address indexed from, address indexed to, uint256[] values, uint256[] dates);
  event TransferFromByDate(address indexed spender, address indexed from, address indexed to, uint256[] values, uint256[] dates);
  // 关闭赎回事件
  event CloseSell(address indexed who);
  // 赎回事件
  event Sell(address indexed from, address indexed to, uint256 tokenValue, uint256 etherValue);
  // withdraw 事件
  event Withdraw(address indexed who, uint256 etherValue);
  // 添加token到fundAccount账户
  event AddTokenToFund(address indexed who, address indexed from, uint256 value);
  // refresh 事件
  event Refresh(address indexed from, address indexed who);

  /**
   * 将锁定期的map做成一个list
   * value 锁定的余额
   * _next 下个锁定期的到期时间
   * */
  struct Element {
    uint256 value;
    uint256 next;
  }

  /**
   * 账户
   * lockedBalances 锁定余额
   * lockedElement 锁定期余额
   * start_date 锁定期最早到期时间
   * end_date 锁定期最晚到期时间
   * */
  struct Account {
    uint256 lockedBalances;
    mapping(uint256 => Element) lockedElement;
    uint256 start_date;
    uint256 end_date;
  }

  /**
   * 所有账户
   * */
  mapping(address => Account) public accounts;

  /**
   * sellPrice: token 赎回价格, 即1 token的赎回价格是多少wei(wei为以太币最小单位)
   * fundAccount: 特殊资金账户,赎回token,接收购买token资金
   * sellFlag: 赎回标记
   * */
  uint256 public sellPrice;
  address public fundAccount;
  bool public sellFlag;

  /**
   * 需求:owner 每年释放的金额不得超过年初余额的10%
   * curYear:  当前年初时间
   * YEAR:  一年365天的时间
   * vault: owner限制额度
   * VAULT_FLOOR_VALUE: vault 最低限值
   * */
  uint256 public curYear;
  uint256 constant internal YEAR = 365 * 24 * 3600;
  uint256 public vault;
  uint256 constant internal VAULT_FLOOR_VALUE = 10000000 * MAGNITUDE;

  /**
   * 合约构造函数
   * 初始化合约的总供应量
   */
  constructor(address _owner, address _fund) public {
    // 要求_owner, _fund不为0
    require(_owner != address(0));
    require(_fund != address(0));

    // 设置owner, fund
    owner = _owner;
    fundAccount = _fund;

    // 初始化owner是管理员
    adminList[owner] = true;

    // 初始化发行量
    totalSupply_ = INITIAL_SUPPLY;
    balances[owner] = INITIAL_SUPPLY;
    emit Transfer(0x0, owner, INITIAL_SUPPLY);

    /**
     * 初始化合约属性
     * 赎回价格
     * 赎回标记为false
     * */
    sellPrice = 0;
    sellFlag = true;

    /**
     * 初始化owner限制额度
     * 2018/01/01 00:00:00
     * */
    vault = totalSupply_.mul(10).div(100);
    curYear = 1514736000;
  }

  /**
   * fallback函数
   * */
  function () external payable {
  }

  /**
   * modifier 要求开启赎回token
   * */
  modifier whenOpenSell()
  {
    require(sellFlag);
    _;
  }

  /**
   * modifier 要求关闭赎回token
   * */
  modifier whenCloseSell()
  {
    require(!sellFlag);
    _;
  }

  /**
   * 刷新owner限制余额vault
   * */
  function refreshVault(address _who, uint256 _value) internal
  {
    uint256 balance;

    // 只对owner操作
    if (_who != owner)
      return ;
    // 记录balance of owner
    balance = balances[owner];
    // 如果是新的一年, 则计算vault为当前余额的10%
    if (now >= (curYear + YEAR))
    {
      if (balance <= VAULT_FLOOR_VALUE)
        vault = balance;
      else
        vault = balance.mul(10).div(100);
      curYear = curYear.add(YEAR);
    }

    // vault 必须大于等于 _value
    require(vault >= _value);
    vault = vault.sub(_value);
    return ;
  }

  /**
   * 重新计算到期的锁定期余额, 内部接口
   * _who: 账户地址
   * */
  function refreshlockedBalances(address _who, bool _update) internal returns (uint256)
  {
    uint256 tmp_date = accounts[_who].start_date;
    uint256 tmp_value = accounts[_who].lockedElement[tmp_date].value;
    uint256 tmp_balances = 0;
    uint256 tmp_var;

    // 强制自动释放打开则跳过判断,直接释放锁定期余额
    if (!forceAutoFreeLockBalance[_who])
    {
      // 强制自动释放未打开,则判断自动释放开关
      if(autoFreeLockBalance[_who])
      {
        // 自动释放开关未打开(true), 直接返回0
        return 0;
      }
    }

    // 锁定期到期
    while(tmp_date != 0 &&
          tmp_date <= now)
    {
      // 记录到期余额
      tmp_balances = tmp_balances.add(tmp_value);

      // 记录 tmp_date
      tmp_var = tmp_date;

      // 跳到下一个锁定期
      tmp_date = accounts[_who].lockedElement[tmp_date].next;
      tmp_value = accounts[_who].lockedElement[tmp_date].value;

      // delete 锁定期余额
      if (_update)
        delete accounts[_who].lockedElement[tmp_var];
    }

    // return expired balance
    if(!_update)
      return tmp_balances;

    // 修改锁定期数据
    accounts[_who].start_date = tmp_date;
    accounts[_who].lockedBalances = accounts[_who].lockedBalances.sub(tmp_balances);
    balances[_who] = balances[_who].add(tmp_balances);

    // 将最早和最晚时间的标志,都置0,即最初状态
    if (accounts[_who].start_date == 0)
        accounts[_who].end_date = 0;

    return tmp_balances;
  }

  /**
   * 可用余额转账,内部接口
   * _from token的拥有者
   * _to token的接收者
   * _value token的数量
   * */
  function transferAvailableBalances(
    address _from,
    address _to,
    uint256 _value
  )
    internal
  {
    // 检查可用余额
    require(_value <= balances[_from]);

    // 修改可用余额
    balances[_from] = balances[_from].sub(_value);
    balances[_to] = balances[_to].add(_value);

    // 触发转账事件
    if(_from == msg.sender)
      emit Transfer(_from, _to, _value);
    else
      emit TransferFrom(msg.sender, _from, _to, _value);
  }

  /**
   * 锁定余额转账,内部接口
   * _from token的拥有者
   * _to token的接收者
   * _value token的数量
   * */
  function transferLockedBalances(
    address _from,
    address _to,
    uint256 _value
  )
    internal
  {
    // 检查可用余额
    require(_value <= balances[_from]);

    // 修改可用余额和锁定余额
    balances[_from] = balances[_from].sub(_value);
    accounts[_to].lockedBalances = accounts[_to].lockedBalances.add(_value);
  }

  /**
   * 回传以太币, 内部接口
   * _from token来源账户
   * _to token目标账户
   * _value 为token数目
   * */
  function transferEther(
    address _from,
    address _to,
    uint256 _value
  )
    internal
  {
    /**
     * 要求 _to 账户接收地址为特殊账户地址
     * 这里只能为return,不能为revert
     * 普通转账在这里返回, 不赎回ether
     * */
    if (_to != fundAccount)
        return ;

    /**
     * 没有打开赎回功能,不能向fundAccount转账
     * */
    require(sellFlag);

    /**
     * 赎回价格必须大于0
     * 赎回的token必须大于0
     * */
    require(_value > 0);

    // 赎回的以太币必须小于账户余额, evalue 单位是wei,即以太币的最小单位
    uint256 evalue = _value.mul(sellPrice).div(MAGNITUDE);
    require(evalue <= address(this).balance);

    // 回传以太币
    if (evalue > 0)
    {
      _from.transfer(evalue);
      emit Sell(_from, _to, _value, evalue);
    }
  }

  /**
   * 取回合约上所有的以太币
   * 只有owner才能取回
   * */
  function withdraw() public onlyOwner {
    uint256 value = address(this).balance;
    owner.transfer(value);
    emit Withdraw(msg.sender, value);
  }

  /**
   * 从from账户向fundAccount添加token
   * */
  function addTokenToFund(address _from, uint256 _value) 
    whenNotPaused
    public
  {
    if (_from != msg.sender)
    {
      // 检查代理额度
      require(_value <= allowed[_from][msg.sender]);

      // 修改代理额度
      allowed[_from][msg.sender] = allowed[_from][msg.sender].sub(_value);
    }

    // 刷新vault余额
    refreshVault(_from, _value);

    // 修改可用账户余额
    transferAvailableBalances(_from, fundAccount, _value);
    emit AddTokenToFund(msg.sender, _from, _value);
  }

  /**
   * 转账
   * */
  function transfer(
    address _to,
    uint256 _value
  )
    public
    whenNotPaused
    returns (bool)
  {
    // 不能给地址0转账
    require(_to != address(0));

    /**
     * 获取到期的锁定期余额
     * */
    refreshlockedBalances(msg.sender, true);
    refreshlockedBalances(_to, true);

    // 刷新vault余额
    refreshVault(msg.sender, _value);

    // 修改可用账户余额
    transferAvailableBalances(msg.sender, _to, _value);

    // 回传以太币
    transferEther(msg.sender, _to, _value);

    return true;
  }

  /**
   * 代理转账
   * 代理从 _from 转账 _value 到 _to
   * */
  function transferFrom(
    address _from,
    address _to,
    uint256 _value
  )
    public
    whenNotPaused
    returns (bool)
  {
    // 不能向赎回地址发送token
    require(_to != fundAccount);

    // 不能向0地址转账
    require(_to != address(0));

    /**
     * 获取到期的锁定期余额
     * */
    refreshlockedBalances(_from, true);
    refreshlockedBalances(_to, true);

    // 检查代理额度
    require(_value <= allowed[_from][msg.sender]);

    // 修改代理额度
    allowed[_from][msg.sender] = allowed[_from][msg.sender].sub(_value);

    // 刷新vault余额
    refreshVault(_from, _value);

    // 修改可用账户余额
    transferAvailableBalances(_from, _to, _value);

    return true;
  }

  /**
   * 设定代理和代理额度
   * 设定代理为 _spender 额度为 _value
   * */
  function approve(
    address _spender,
    uint256 _value
  )
    public
    whenNotPaused
    returns (bool)
  {
    return super.approve(_spender, _value);
  }

  /**
   * 提高代理的代理额度
   * 提高代理 _spender 的代理额度 _addedValue
   * */
  function increaseApproval(
    address _spender,
    uint _addedValue
  )
    public
    whenNotPaused
    returns (bool success)
  {
    return super.increaseApproval(_spender, _addedValue);
  }

  /**
   * 降低代理的代理额度
   * 降低代理 _spender 的代理额度 _subtractedValue
   * */
  function decreaseApproval(
    address _spender,
    uint _subtractedValue
  )
    public
    whenNotPaused
    returns (bool success)
  {
    return super.decreaseApproval(_spender, _subtractedValue);
  }

  /**
   * 批量转账 token
   * 批量用户 _receivers
   * 对应的转账数量 _values
   * */
  function batchTransfer(
    address[] _receivers,
    uint256[] _values
  )
    public
    whenNotPaused
  {
    // 判断接收账号和token数量为一一对应
    require(_receivers.length > 0 && _receivers.length == _values.length);

    /**
     * 获取到期的锁定期余额
     * */
    refreshlockedBalances(msg.sender, true);

    // 判断可用余额足够
    uint32 i = 0;
    uint256 total = 0;
    for (i = 0; i < _values.length; i ++)
    {
      total = total.add(_values[i]);
    }
    require(total <= balances[msg.sender]);

    // 刷新vault余额
    refreshVault(msg.sender, total);

    // 一一 转账
    for (i = 0; i < _receivers.length; i ++)
    {
      // 不能向赎回地址发送token
      require(_receivers[i] != fundAccount);

      // 不能向0地址转账
      require(_receivers[i] != address(0));

      refreshlockedBalances(_receivers[i], true);
      // 修改可用账户余额
      transferAvailableBalances(msg.sender, _receivers[i], _values[i]);
    }
  }

  /**
   * 代理批量转账 token
   * 被代理人 _from
   * 批量用户 _receivers
   * 对应的转账数量 _values
   * */
  function batchTransferFrom(
    address _from,
    address[] _receivers,
    uint256[] _values
  )
    public
    whenNotPaused
  {
    // 判断接收账号和token数量为一一对应
    require(_receivers.length > 0 && _receivers.length == _values.length);

    /**
     * 获取到期的锁定期余额
     * */
    refreshlockedBalances(_from, true);

    // 判断可用余额足够
    uint32 i = 0;
    uint256 total = 0;
    for (i = 0; i < _values.length; i ++)
    {
      total = total.add(_values[i]);
    }
    require(total <= balances[_from]);

    // 判断代理额度足够
    require(total <= allowed[_from][msg.sender]);

    // 修改代理额度
    allowed[_from][msg.sender] = allowed[_from][msg.sender].sub(total);

    // 刷新vault余额
    refreshVault(_from, total);

    // 一一 转账
    for (i = 0; i < _receivers.length; i ++)
    {
      // 不能向赎回地址发送token
      require(_receivers[i] != fundAccount);

      // 不能向0地址转账
      require(_receivers[i] != address(0));

      refreshlockedBalances(_receivers[i], true);
      // 修改可用账户余额
      transferAvailableBalances(_from, _receivers[i], _values[i]);
    }
  }

  /**
   * 带有锁定期的转账, 当锁定期到期之后,锁定token数量将转入可用余额
   * _receiver 转账接收账户
   * _values 转账数量
   * _dates 锁定期,即到期时间
   *        格式:UTC时间,单位秒,即从1970年1月1日开始到指定时间所经历的秒
   * */
  function transferByDate(
    address _receiver,
    uint256[] _values,
    uint256[] _dates
  )
    public
    whenNotPaused
  {
    // 判断接收账号和token数量为一一对应
    require(_values.length > 0 &&
        _values.length == _dates.length);

    // 不能向赎回地址发送token
    require(_receiver != fundAccount);

    // 不能向0地址转账
    require(_receiver != address(0));

    /**
     * 获取到期的锁定期余额
     * */
    refreshlockedBalances(msg.sender, true);
    refreshlockedBalances(_receiver, true);

    // 判断可用余额足够
    uint32 i = 0;
    uint256 total = 0;
    for (i = 0; i < _values.length; i ++)
    {
      total = total.add(_values[i]);
    }
    require(total <= balances[msg.sender]);

    // 刷新vault余额
    refreshVault(msg.sender, total);

    // 转账
    for(i = 0; i < _values.length; i ++)
    {
      transferByDateSingle(msg.sender, _receiver, _values[i], _dates[i]);
    }

    emit TransferByDate(msg.sender, _receiver, _values, _dates);
  }

  /**
   * 代理带有锁定期的转账, 当锁定期到期之后,锁定token数量将转入可用余额
   * _from 被代理账户
   * _receiver 转账接收账户
   * _values 转账数量
   * _dates 锁定期,即到期时间
   *        格式:UTC时间,单位秒,即从1970年1月1日开始到指定时间所经历的秒
   * */
  function transferFromByDate(
    address _from,
    address _receiver,
    uint256[] _values,
    uint256[] _dates
  )
    public
    whenNotPaused
  {
    // 判断接收账号和token数量为一一对应
    require(_values.length > 0 &&
        _values.length == _dates.length);

    // 不能向赎回地址发送token
    require(_receiver != fundAccount);

    // 不能向0地址转账
    require(_receiver != address(0));

    /**
     * 获取到期的锁定期余额
     * */
    refreshlockedBalances(_from, true);
    refreshlockedBalances(_receiver, true);

    // 判断可用余额足够
    uint32 i = 0;
    uint256 total = 0;
    for (i = 0; i < _values.length; i ++)
    {
      total = total.add(_values[i]);
    }
    require(total <= balances[_from]);

    // 判断代理额度足够
    require(total <= allowed[_from][msg.sender]);

    // 修改代理额度
    allowed[_from][msg.sender] = allowed[_from][msg.sender].sub(total);

    // 刷新vault余额
    refreshVault(_from, total);

    // 转账
    for(i = 0; i < _values.length; i ++)
    {
      transferByDateSingle(_from, _receiver, _values[i], _dates[i]);
    }

    emit TransferFromByDate(msg.sender, _from, _receiver, _values, _dates);
  }

  /**
   * _from token拥有者
   * _to 转账接收账户
   * _value 转账数量
   * _date 锁定期,即到期时间
   *       格式:UTC时间,单位秒,即从1970年1月1日开始到指定时间所经历的秒
   * */
  function transferByDateSingle(
    address _from,
    address _to,
    uint256 _value,
    uint256 _date
  )
    internal
  {
    uint256 start_date = accounts[_to].start_date;
    uint256 end_date = accounts[_to].end_date;
    uint256 tmp_var = accounts[_to].lockedElement[_date].value;
    uint256 tmp_date;

    if (_value == 0)
    {
        // 不做任何处理
        return ;
    }

    if (_date <= now)
    {
      // 到期时间比当前早,直接转入可用余额
      // 修改可用账户余额
      transferAvailableBalances(_from, _to, _value);

      return ;
    }

    if (start_date == 0)
    {
      // 还没有收到过锁定期转账
      // 最早时间和最晚时间一样
      accounts[_to].start_date = _date;
      accounts[_to].end_date = _date;
      accounts[_to].lockedElement[_date].value = _value;
    }
    else if (tmp_var > 0)
    {
      // 收到过相同的锁定期
      accounts[_to].lockedElement[_date].value = tmp_var.add(_value);
    }
    else if (_date < start_date)
    {
      // 锁定期比最早到期的还早
      // 添加锁定期,并加入到锁定期列表
      accounts[_to].lockedElement[_date].value = _value;
      accounts[_to].lockedElement[_date].next = start_date;
      accounts[_to].start_date = _date;
    }
    else if (_date > end_date)
    {
      // 锁定期比最晚到期还晚
      // 添加锁定期,并加入到锁定期列表
      accounts[_to].lockedElement[_date].value = _value;
      accounts[_to].lockedElement[end_date].next = _date;
      accounts[_to].end_date = _date;
    }
    else
    {
      /**
       * 锁定期在 最早和最晚之间
       * 首先找到插入的位置
       * 然后在插入的位置插入数据
       * tmp_var 即 tmp_next
       * */
      tmp_date = start_date;
      tmp_var = accounts[_to].lockedElement[tmp_date].next;
      while(tmp_var < _date)
      {
        tmp_date = tmp_var;
        tmp_var = accounts[_to].lockedElement[tmp_date].next;
      }

      // 记录锁定期并加入列表
      accounts[_to].lockedElement[_date].value = _value;
      accounts[_to].lockedElement[_date].next = tmp_var;
      accounts[_to].lockedElement[tmp_date].next = _date;
    }

    // 锁定期转账
    transferLockedBalances(_from, _to, _value);

    return ;
  }

  /**
   * sell tokens
   * */
  function sell(uint256 _value) public whenOpenSell whenNotPaused {
    transfer(fundAccount, _value);
  }

  /**
   * 设置token赎回价格
   * */
  function setSellPrice(uint256 price) public whenAdministrator(msg.sender) {
    require(price > 0);
    sellPrice = price;

    emit SetSellPrice(msg.sender, price);
  }

  /**
   * 关闭购买赎回token
   * */
  function closeSell() public whenOpenSell onlyOwner {
    sellFlag = false;
    emit CloseSell(msg.sender);
  }

  /**
   * 重新计算账号的lockbalance
   * */
  function refresh(address _who) public whenNotPaused {
    refreshlockedBalances(_who, true);
    emit Refresh(msg.sender, _who);
  }

  /**
   * 查询账户可用余额
   * */
  function availableBalanceOf(address _owner) public view returns (uint256) {
    return (balances[_owner] + refreshlockedBalances(_owner, false));
  }

  /**
   * 查询账户总余额
   * */
  function balanceOf(address _owner) public view returns (uint256) {
    return balances[_owner] + accounts[_owner].lockedBalances;
  }

  /**
   * 获取锁定余额
   * */
  function lockedBalanceOf(address _who) public view returns (uint256) {
    return (accounts[_who].lockedBalances - refreshlockedBalances(_who, false));
  }

  /**
   * 根据日期获取锁定余额
   * 返回:锁定余额,下一个锁定期
   * */
  function lockedBalanceOfByDate(address _who, uint256 date) public view returns (uint256, uint256) {
    return (accounts[_who].lockedElement[date].value, accounts[_who].lockedElement[date].next);
  }

}

【接口】生成钱包

  • 通过助记词生成钱包,缓存到本地,显示到首页
  • 钱包列表
  • 助记词导入钱包
  • 私钥导入钱包
  • 切换钱包
  • 删除指定钱包

生成助记词:

import 'package:bip39/bip39.dart' as bip39;
import 'package:ed25519_hd_key/ed25519_hd_key.dart';
import "package:hex/hex.dart";

计算钱包地址

import 'package:web3dart/credentials.dart';

    final private = EthPrivateKey.fromHex(privateKey);
    final address = await private.extractAddress();
    print("address: $address");

[讨论]后端核心逻辑代码是否开源

关于后端核心逻辑是否不开源或阶段性不开源,大家可以讨论发表意见
不开源原因
开源导致可能被迅速抄袭
开源导致容易被封杀

开源的原因
社区力量更强大,利于社区发展
有效规避法律风险

@youwallet/wallet

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.