一个简单的以太坊合约让imtoken支持多签

熟悉比特币和以太坊的人应该都知道,在比特币中有2种类型的地址,1开头的是P2PKH,就是个人地址,3开头的是P2SH,一般是一个多签地址。所以在原生上比特币就支持多签。多签的一个优势就是可以多方对一笔付款达成共识,才能支付成功。比如3个人合伙开公司,他们的对外付款是比特币,为了防止管理财务的人作恶,于是他们可以创建2/3多签的地址,每个人持有一个私钥,对于每一笔付款,必须任意2个人都签名了才能支付出去。

比特币上的这个多签地址在以太坊上是没有原生支持的!以太坊最大的优点是支持图灵完备的智能合约,所以多签功能需要靠智能合约来实现。

为了简化代码,我们的需求是这样的:创建一个AB两个用户创建2/2的多签合约,该合约支持指定的ERC20 Token的支付。当某需要对外付款时,A用户调用合约,发起对C的转账n个Token,B用户也必须调用合约,发起对C的转账n个Token,只有A和B都调用了合约后,合约才会真的付款。其他用户发起转账无效。

根据以上需求,我改了一款极其简单的多签合约。代码如下:

pragma solidity ^0.4.24;

interface Token {
  function balanceOf(address _owner)  public view returns (uint256 );
  function transfer(address _to, uint256 _value) public ;
}

contract MultiSig {
    address private addrA;
    address private addrB;
    address private addrToken;

    struct Permit {
        bool addrAYes;
        bool addrBYes;
    }

    mapping (address => mapping (uint => Permit)) private permits;

    event Transfer(address indexed from, address indexed to, uint256 value);

    constructor(address a, address b, address tokenAddress) public{
        addrA = a;
        addrB = b;
        addrToken = tokenAddress;
    }
    function getAddrs() public view returns(address, address,address) {
      return (addrA, addrB,addrToken);
    }
    function transferTo(address to,  uint amount) public{
        Token token = Token(addrToken);
        require(token.balanceOf(this) >= amount);

        if (msg.sender == addrA) {
            permits[to][amount].addrAYes = true;
        } else if (msg.sender == addrB) {
            permits[to][amount].addrBYes = true;
        } else {
            require(false);
        }

        if (permits[to][amount].addrAYes == true && permits[to][amount].addrBYes == true) {
            token.transfer(to, amount);
            permits[to][amount].addrAYes = false;
            permits[to][amount].addrBYes = false;
        }
        emit Transfer(msg.sender, to, amount);
    }
}

以上代码十分简陋,功能十分有限,而且需要在etherscan或者remix上调用,对用户来说十分不友好,于是我想到了可以按ERC20标准接口对这个多签合约进行改造。改造后的合约看起来像是一个Token,但是本质上是一个多签地址。A B用户都可以使用imtoken或者KCash之类的支持ERC20的钱包APP进行多签,而不需要任何复杂的技能。所以我改写后的多签合约如下:

pragma solidity ^0.4.24;

interface IERC20 {
    function transfer(address to, uint256 value) external returns (bool);

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

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

    function totalSupply() external view returns (uint256);

    function balanceOf(address who) external view returns (uint256);

    function allowance(address owner, address spender) external view returns (uint256);

    event Transfer(address indexed from, address indexed to, uint256 value);

    event Approval(address indexed owner, address indexed spender, uint256 value);
}

contract MultiSig is IERC20 {
    address private addrA;
    address private addrB;
    address private addrToken;

    struct Permit {
        bool addrAYes;
        bool addrBYes;
    }

    mapping (address => mapping (uint => Permit)) private permits;

     event Transfer(address indexed from, address indexed to, uint256 value);

    event Approval(address indexed owner, address indexed spender, uint256 value);

    uint public totalSupply = 10*10**26;
    uint8 constant public decimals = 18;
    string constant public name = "MutiSigPTN";
    string constant public symbol = "MPTN";

 function approve(address spender, uint256 value) external returns (bool){
     return false;
 }

    function transferFrom(address from, address to, uint256 value) external returns (bool){
        return false;
    }

    function totalSupply() external view returns (uint256){
          IERC20 token = IERC20(addrToken);
          return token.totalSupply();
    }

    function allowance(address owner, address spender) external view returns (uint256){
        return 0;
    }

    constructor(address a, address b, address tokenAddress) public{
        addrA = a;
        addrB = b;
        addrToken = tokenAddress;
    }
    function getAddrs() public view returns(address, address,address) {
      return (addrA, addrB,addrToken);
    }
    function  transfer(address to,  uint amount)  public returns (bool){
        IERC20 token = IERC20(addrToken);
        require(token.balanceOf(this) >= amount);

        if (msg.sender == addrA) {
            permits[to][amount].addrAYes = true;
        } else if (msg.sender == addrB) {
            permits[to][amount].addrBYes = true;
        } else {
            require(false);
        }

        if (permits[to][amount].addrAYes == true && permits[to][amount].addrBYes == true) {
            token.transfer(to, amount);
            permits[to][amount].addrAYes = false;
            permits[to][amount].addrBYes = false;
        }
        emit Transfer(msg.sender, to, amount);
        return true;
    }
    function balanceOf(address _owner) public view returns (uint) {
        IERC20 token = IERC20(addrToken);
        if (_owner==addrA || _owner==addrB){
            return token.balanceOf(this);
        }
        return 0;
    }
}

这里我需要特别指出的是decimals这个属性必须与所支持的ERC20 Token一致,这样钱包才会算出正确的转账金额。另外imtoken的缓存刷新比较慢,并不是部署了合约后马上就能搜索到的。以上代码都实测没问题。

原文地址:https://www.cnblogs.com/studyzy/p/10739490.html

时间: 2024-07-31 04:14:32

一个简单的以太坊合约让imtoken支持多签的相关文章

通过一个案例精通以太坊智能合约和Solidity

作者介绍 Silver CEO 星际区块链信息发展有限公司 项目组件 ??这个项目是一个构建在以太坊上的游戏,感谢这个团队给我们提供的案例:https://cryptozombies.io ??从功能的角度看,有如下脚本: zombiefactory.sol:定义zombie和生成zombie. zombiefeeding.sol:定义小猫接口,给zombie吃小猫. zombieattack.sol:zombie打架的功能. erc721.sol:ERC721代币的接口. ownable.so

使用PHP和树莓派开发一个比特币和以太坊交易机器人

我最近得到了Raspberry Pi Zero Wifi,我告诉你这个东西是改变游戏规则的.我之前使用过RasPis,但由于该设备的占地面积小得多,耗电少,价格便宜且无线上网,因此非常适合低端或物联网项目. 注:目前我已经扩展了机器人以便能够交易以太坊! 我希望它能够在不必太多关注的情况下做事,而我想到的第一件事就是: 为什么不创建一个可以自动进行比特币和以太坊的简单交易机器人. 这个想法很简单:Raspberry Pi Zero使用Coinbase API定期检查价格,并在有意义的时候购买和销

装饰器的运用,编写一个简单的仿京东登录软件模拟支持微信和京东帐号登录

#__author__:"Jay guo" #__date__:2016/9/8 login_flag = False def login(flag): def func(f): def inner(): global login_flag if login_flag == False: nameuser = input("input your name:> ") print (nameuser) passwd = input ("input you

c#实战开发:用.net core开发一个简单的Web以太坊钱包 (六)

今天就来开发一个C# 版的简易钱包 先回顾以前的内容 c#实战开发:以太坊Geth 命令发布智能合约 (五) c#实战开发:以太坊Geth 常用命令 (四) c#实战开发:以太坊钱包快速同步区块和钱包卡死解决方案 (三) c#实战开发:以太坊钱包对接私链 (二) c#实战开发:以太坊私链搭建(一) 先看一下可视化钱包有哪些功能呢? 那这个钱包得有什么功能呢? 1.查看用户 2.查看交易记录 3.转账 4.发布智能合约 5.代币转账 6.代币查询 7.实时同步区块对比 8.智能填写手续费 首先新建

如何用python和flask以太坊智能合约开发

将数据存储在数据库中是任何软件应用程序不可或缺的一部分.无论如何控制该数据库都有一个该数据的主控.区块链技术将数据存储到区块链网络内的区块中.因此,只要某个节点与网络同步,它们就会获得区块中数据的副本.因此,该技术中没有特定的数据主控. 在本教程中,我们将编写一份智能合约(我将进一步解释),以便在区块链上保留用户数据.我们将使用python web3(web3的python库)来开发和部署智能合约.一旦我们在区块链上部署了智能合约.我们将使用flask API与智能合约进行交互以存储一些数据/信

以太坊智能合约项目-Token合约开发与部署

修订日期 姓名 邮箱 2019-09-05 brucefeng [email protected] 一. 钱包环境安装 以太坊钱包顾名思义,就是管理以太坊地址,存储以太坊Token的工具,再简单点说,任何区块链网络都需要我们有自己的账户,管理账户的软件可称之为钱包,无论是炒币的还是研究以太坊开发的,钱包都是必不可少的. 1.钱包分类 1.1 Mist 说到以太坊钱包,第一个要说的当然就是Ethereum官方钱包+浏览器 Mist.Mist是一个全节点钱包(全节点钱包通俗的来说就是同步了全部的以太

solidity编程开发语言——以太坊智能合约利器

这篇关于Solidity教程的博客展示了很多Solidity特性.本教程假定你对以太坊虚拟机和编程有一定的了解. 以太坊,"世界计算机"提供了一个非常强大的全球共享基础设施,使用名为Solidity的编程语言构建去中心化应用程序. 让我们开始我们的Solidity教程,介绍Solidity. 什么是Solidity? 以太坊Solidity是一种面向智能合约的高级语言,其语法与JavaScript类似.solidity是用于生成在EVM上执行的机器级代码的工具.solidity编译器获

区块链以太坊环境搭建(详细篇)

以太坊合约的配置(以在私有链上配置投票合约为例) 以太坊合约配置步骤大体如下: 一.安装Mist浏览器(已经集成以太坊钱包) 二.安装配置基于Go语言的geth命令 三.在本地搭建私有链 四.在私有链上完成挖矿工作 五.使用Mist在私有链上配置投票合约 具体步骤如下: 一.安装Mist浏览器(已经集成以太坊钱包) 1登陆https://github.com/ethereum/mist/releases/根据需求下载最新版本的客户端: 下载完成解压压缩文件后找到可运行文件运行安装即可 安装过程中

以太坊基础福运来平台制作

控制和责任像以太坊福运来平台制作请添加链接描述Q_1151880099这样的开放区块链是安全的,因为它们是去中心化的.这意味着以太坊的每个用户都应该控制自己的密钥,这些密钥可以控制对资金和合约的访问.一些用户选择通过使用第三方保管人(比如交易所钱包)放弃对密钥的控制权.在本书中,我们将教你如何控制和管理你自己的密钥. 这种控制带来了很大的责任.如果你丢失了你的钥匙,你将无法获得资金和合约.没有人可以帮助你重新获得访问权 - 你的资金将永远锁定.以下是一些帮助你管理这一责任的提示: 提示你选择密码