前言:
首先了解下为什么会出现智能合约,打个比方现在有两个人A和B打赌明天会不会下雨,每个人赌注100元,如果第二天下雨则A拿走200元,否则B拿走200元,这样就有一个问题,赌注要到第二天才能见效,如果两个人是知根知底的熟人还是君子,那么可以定一个君子协定,但是这个并不适用于陌生人或者信誉不好的人,那么应该怎么办,只能找个中间人,类似于裁判,需要对赌注结果进行判断而且保管赌金,这就带来了第二个问题,这个中间人可靠不可靠,信任如何解决,这里就出现了智能合约,通过计算机代码来控制合约内容,并保管金额,只要代码经过双方审核没有问题合约生效,就不会有人为因素来干扰,解决了信任问题。
所以智能合约(Smart contracts)是一种基于区块链技术的自动化合约。它们是一组以编程形式定义的计算机代码,旨在执行、验证或执行合同中的特定条件或条款。
智能合约运行在区块链上,通过区块链的去中心化和分布式特性,实现了在没有中间人的情况下进行可靠的交易和合约执行。智能合约的代码和执行结果被记录在区块链的区块中,具有透明性、不可篡改性和可验证性。
智能合约可以用于各种场景,例如数字货币交易、资产转让、投票、供应链管理、保险索赔等。合约的条件和逻辑由编程语言来定义,常见的智能合约平台使用的编程语言包括 Solidity(用于以太坊)、Vyper(用于以太坊)、Corda(用于 Corda 区块链平台)等。
智能合约的执行通常基于预先设定的条件和触发事件。一旦满足了合约的条件,智能合约将自动执行相应的操作,例如转移资金、更新状态或触发其他合约。这种自动化的执行消除了中介机构的需求,减少了交易成本并提高了执行的效率。
搭建以太坊合约:
这里我们以以太坊为例,讲讲底层是如何实现智能合约,首先我们需要知道以以太坊有C和go两个版本,但是其智能合约可以使用如下四种语言:
- Solidity ,受JavaScript 启发
- Serpent ,受Python启发
- Mutan,受Go 启发
- LLL 受Lisp 启发
其中Solidity到目前为止是最流行的智能合约编程语言,当然每个不同的区块链会有自己对应的支持的智能合约语言,这里以Solidity进行讲解
首先下载以太坊协议的官方 Go 实现,地址如下:
https://github.com/ethereum/go-ethereum
注意下载版本不要大于v1.12.0,因为该版本的不能再在基于 PoW 的私有链上使用,详情请查看地址:
https://github.com/ethereum/go-ethereum/releases/tag/v1.12.0
下载完成后,可能需要科学上网,搭建好代理端口后执行如下:
export http_proxy=http://127.0.0.1:7890
export https_proxy=http://127.0.0.1:7890
进入下载的go-ethereum目录执行,如果没有安装go,首先安装go环境:
apt update
apt install golang
make geth
mv geth /usr/local/bin/geth-1.11.6
geth-1.11.6 version
然后安装solidity,首先在如下地址下载对应的二进制文件:
https://github.com/ethereum/solidity/releases
然后执行如下命令讲文件放入bin目录:
mv solc-static-linux /usr/local/bin
solc --version
完成后我们就要搭建自己的私有节点,如果我们去公有链除了数据库庞大外执行合约还要花费一定的费用,测试的话就在本地进行测试就好:
首先创建文件genesis.json:,其中部分参数解释如下:
mixhash 与nonce配合用于挖矿,由上一个区块的一部分生成的hash nonce nonce就是一个64位随机数,用于挖矿 difficulty 设置当前区块的难度,如果难度过大,cpu挖矿就很难,这里设置较小难度 alloc 用来预置账号以及账号的以太币数量 coinbase 矿工的账号,随便填 timestamp 设置创世块的时间戳 parentHash 上一个区块的hash值,因为是创世块,所以这个值是0 extraData 附加信息,随便填,可以填你的个性信息 gasLimit 该值设置对GAS的消耗总量限制,用来限制区块能包含的交易信息总和
{
"config": {
"chainId": 111,
"homesteadBlock": 0,
"eip150Block": 0,
"eip150Hash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"eip155Block": 0,
"eip158Block": 0,
"byzantiumBlock": 0,
"constantinopleBlock": 0,
"petersburgBlock": 0,
"istanbulBlock": 0,
"ethash": {}
},
"nonce": "0x0",
"timestamp": "0x5ddf8f3e",
"extraData": "0x0000000000000000000000000000000000000000000000000000000000000000",
"gasLimit": "0x47b760",
"difficulty": "0x00002",
"mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"coinbase": "0x0000000000000000000000000000000000000000",
"alloc": { },
"number": "0x0",
"gasUsed": "0x0",
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000"
}
然后执行命令进行节点初始化:
其中参数解释:
init 指定创世块文件的位置,并创建初始块 datadir 设置当前区块链网络数据存放的位置
geth-1.11.6 --datadir data1 init genesis.json
出现如下successfully 证明初始化成功:
因为我们需要在一台主机上创建多个节点方便操作,,然后执行如下命令,其中--http.addr为本机IP,其中需要注意personal这个namespace高版本已经不用了,如果再想用的话,需要添加--rpc.enabledeprecatedpersonal
这个参数:
geth-1.11.6 --datadir /home/yitai/privatechain/data1 --http --http.api "eth,web3,miner,admin,personal,net" --http.corsdomain "*" --nodiscover --networkid 111 --http.addr 192.168.5.106 --http.port 9049 --port 3366 --allow-insecure-unlock --rpc.enabledeprecatedpersonal
然后会data1文件夹中创建出geth.ipc文件:
然后执行如下命令,此时是
geth-1.11.6 attach ipc:geth.ipc
这里首先我们要Geth JavaScript console熟悉命令,如下地址为官方说明:
https://geth.ethereum.org/docs/interacting-with-geth/javascript-console
Geth JavaScript console 常用对象如下,在console输入前面的对象按tab可以看到对应的方法:
eth:主要包含对区块链进行访问和交互相关的方法 net:包含以下查看p2p网络状态的方法 admin:包含一些与管理节点相关的方法 miner:包含启动&停止挖矿的一些方法 personal:主要包含一些管理账户的方法 txpool:包含一些查看交易内存池的方法 web3:包含了以上对象,还包含一些单位换算的方法
常用方法如下:
创建账户
personal.newAccount()
解锁账户
personal.unlockAccount()
解锁账户,指定解锁具体账户
personal.unlockAccount(eth.accounts[0])
列出系统中的账户
eth.accounts
1、查看账户余额,返回值的单位是 Wei (“ ”里面是自己管理的账户地址)
eth.getBalance()
2、查看账户余额,返回值的单位是 Wei (“ ”里面是自己管理的账户地址)
eth.getBalance("写上账户地址")
3、转换为单位ether,便于阅读
web3.fromWei(eth.getBalance("写上账户地址"),'ether')
4、如果是在里面创建的账户可以调用内部函数拿到地址,不用每次都复制地址。
eth.getBalance(eth.accounts[0])
web3.fromWei(eth.getBalance(eth.accounts[0]),'ether')
发起交易(发起方需要是自己管理的账户,其次需要先解锁账户),from:发起交易的地址;to:接受交易的地址
eth.sendTransaction({from:eth.accounts[0],to:"接受交易的地址",value:100000})
列出当前区块高度
eth.blockNumber
获取交易信息
eth.getTransaction()
获取区块信息
eth.getBlock()
开始挖矿
miner.start()
表示一直挖矿
miner.start(1)
查看
eth.coinbase
停止挖矿
miner.stop()
开始挖矿,当挖到一个块时就停止,
miner.start(1);admin.sleepBlocks(1);miner.stop()
Wei 换算成以太币
web3.fromWei()
以太币换算成 Wei
web3.toWei()
交易油中的状态
bxpool.status
查看我们创建的节点:
查看当前连接节点为0:
然后我们在Geth JavaScript console下添加两个新账号:
可以看到创建了如下两个账号:
0x20cabfdcc5db00741f71a889085d39ae4c9bd990 0x6e466264f57e3d618284b3162409883599ebf138
下面我们设置其中一个为Coinbase ,挖到一个区块会奖励5个以太币,挖矿所得的奖励会进入矿工的账户,这个账户叫做coinbase,默认情况下coinbase是本地账户中的第一个账户,通过miner.setEtherbase()可将其他账户设置成coinbase。Coinbase 地址指的是在以太坊网络上进行挖矿活动时,挖矿奖励被发送到的地址。这个地址通常是挖矿节点的钱包地址,并且此时查看余额为0:
下面就开始挖矿,由于我们的是私有链,而且难度系数低,所以很容易就挖到:
需要注意getBalance()返回值的单位是wei,wei是以太币的最小单位,1个以太币=10的18次方个wei。要查看有多少个以太币,可以用web3.fromWei()将返回值换算成以太币:
这个时候我们看看当前区块总数为17,并且在miner中可以看到对应的账号地址:
下面我们尝试进行一次转账,讲第一个账户的钱转一部分到第二个账户,转移前需要进行解锁账户:
解锁完成后进行转账操作,可以看到转账成功后会有一个账单地址,追踪这个地址可以看到交易的详细信息:
转账虽然成功,但是这个时候查看该地址余额还是显示为0:
这是因为虽然此时交易已经提交到区块链,返回了交易的hash,但还未被处理,这可以通过查看txpool来验证:
其中有一条pending的交易,pending表示已提交但还未被处理的交易,要使交易被处理,必须要挖矿。这里我们启动挖矿,然后等待挖到一个区块之后就停止挖矿,执行后可以看到已经成功转账,至于为什么,这个要说以太坊的Proof-of-Work工作量机制,不过后续以太坊使用Proof-of-Stake(PoS)是一种区块链共识机制,与传统的Proof-of-Work(PoW)机制不同。在PoS中,区块链的验证和记账权不是通过解决复杂的数学难题来获得,而是基于参与者在系统中持有的加密货币(通常是同一区块链的本地代币)的数量。
此时我们再查刚才的转账记录地址,可以看到其被记录到了18区块,查看对应的18区块可以看到对应的交易账单:
下面我们开始自己编写一个合约,具体的Solidity语法请参考如下地址,我们的测试代码也取自官方案例:
https://docs.soliditylang.org/zh/v0.8.17/introduction-to-smart-contracts.html
测试代码如下,其主要功能是mint,send两个方法,mint方法是向指定的地址发送代币, send为从调用者处发送代币到指定地址:
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.4;
contract Coin {
// 关键字 "public" 使变量可以从其他合约中访问。
address public minter;
mapping (address => uint) public balances;
// 事件允许客户端对您声明的特定合约变化做出反应
event Sent(address from, address to, uint amount);
// 构造函数代码只有在合约创建时运行
constructor() {
minter = msg.sender;
}
// 向一个地址发送一定数量的新创建的代币
// 但只能由合约创建者调用
function mint(address receiver, uint amount) public {
require(msg.sender == minter);
balances[receiver] += amount;
}
// 错误类型变量允许您提供关于操作失败原因的信息。
// 它们会返回给函数的调用者。
error InsufficientBalance(uint requested, uint available);
// 从任何调用者那里发送一定数量的代币到一个地址
function send(address receiver, uint amount) public {
if (amount > balances[msg.sender])
revert InsufficientBalance({
requested: amount,
available: balances[msg.sender]
});
balances[msg.sender] -= amount;
balances[receiver] += amount;
emit Sent(msg.sender, receiver, amount);
}
}
我们可以通过如下地址进行在线测试:
https://remix.ethereum.org/#lang=en&optimize=false&runs=200&evmVersion=null
首先我们新建一个文件后讲上述代码粘贴到新建文本中,然后点击编译:
首先需要部署合约,选择好地址点击部署就可以看到部署的合约:
首先选择要接收的地址,然后设置好金额,执行后可以看到debug中有参数数据,这样就会执行mint中的代码,向指定的地址转入50代币,然后查询可以看到成功转入50代币:
然后执行第二个转账send方法, 执行这个方法会将调用者的代币转入指定地址中,可以看到调用地址的金额减少了20,被转入了指定的地址:
下面我们把合约部署再我们自己的私链中,首先查看编译详情,其中有ABI和字节码数据:
然后进入如下网址对ABI的json数据进行转移:
https://www.bejson.com/
ABI转义前数据如下:
[
{
"inputs": [],
"stateMutability": "nonpayable",
"type": "constructor"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "requested",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "available",
"type": "uint256"
}
],
"name": "InsufficientBalance",
"type": "error"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "address",
"name": "from",
"type": "address"
},
{
"indexed": false,
"internalType": "address",
"name": "to",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "amount",
"type": "uint256"
}
],
"name": "Sent",
"type": "event"
},
{
"inputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"name": "balances",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "receiver",
"type": "address"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
}
],
"name": "mint",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "minter",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "receiver",
"type": "address"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
}
],
"name": "send",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
}
]
然后执行如下命令,将json字符串转义成字符串,并在geth控制台中将其赋值给新变量:
abi = JSON.parse('[{\"inputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"requested\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"available\",\"type\":\"uint256\"}],\"name\":\"InsufficientBalance\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"Sent\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"balances\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"mint\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"minter\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"send\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]')
myContract = web3.eth.contract(abi)
下面执行如下命令,预估手续费:
bytecode = "0x608060405234801561001057600080fd5b50336000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506105fc806100606000396000f3fe608060405234801561001057600080fd5b506004361061004c5760003560e01c8063075461721461005157806327e235e31461006f57806340c10f191461009f578063d0679d34146100bb575b600080fd5b6100596100d7565b60405161006691906103b6565b60405180910390f35b61008960048036038101906100849190610402565b6100fb565b6040516100969190610448565b60405180910390f35b6100b960048036038101906100b4919061048f565b610113565b005b6100d560048036038101906100d0919061048f565b6101c5565b005b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60016020528060005260406000206000915090505481565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461016b57600080fd5b80600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282546101ba91906104fe565b925050819055505050565b600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205481111561028a5780600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020546040517fcf479181000000000000000000000000000000000000000000000000000000008152600401610281929190610532565b60405180910390fd5b80600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282546102d9919061055b565b9250508190555080600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825461032f91906104fe565b925050819055507f3990db2d31862302a685e8086b5755072a6e2b5b780af1ee81ece35ee3cd33453383836040516103699392919061058f565b60405180910390a15050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006103a082610375565b9050919050565b6103b081610395565b82525050565b60006020820190506103cb60008301846103a7565b92915050565b600080fd5b6103df81610395565b81146103ea57600080fd5b50565b6000813590506103fc816103d6565b92915050565b600060208284031215610418576104176103d1565b5b6000610426848285016103ed565b91505092915050565b6000819050919050565b6104428161042f565b82525050565b600060208201905061045d6000830184610439565b92915050565b61046c8161042f565b811461047757600080fd5b50565b60008135905061048981610463565b92915050565b600080604083850312156104a6576104a56103d1565b5b60006104b4858286016103ed565b92505060206104c58582860161047a565b9150509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60006105098261042f565b91506105148361042f565b925082820190508082111561052c5761052b6104cf565b5b92915050565b60006040820190506105476000830185610439565b6105546020830184610439565b9392505050565b60006105668261042f565b91506105718361042f565b9250828203905081811115610589576105886104cf565b5b92915050565b60006060820190506105a460008301866103a7565b6105b160208301856103a7565b6105be6040830184610439565b94935050505056fea2646970667358221220b7068a932ac927292afefef1993fb5fbdd8d9f62b10b9c5559a47313126c03b964736f6c63430008110033"
web3.eth.estimateGas({data: bytecode})
其中需要注意字节码前面要加上0x,并且要注意编译版本,如果过高会报错:
下面解锁账户:
personal.unlockAccount(eth.coinbase)
开始部署合约:
contractInstance =myContract.new({from:"0x20cabfdcc5db00741f71a889085d39ae4c9bd990",data:bytecode,gas:1000000})
执行看到如下为成功:
输入contractInstance检查合约是否正确:
这里需要注意address为未定义是因为合约还没有被放到链上,所以我们需要挖一下矿把合约写入链上:
miner.start(1);admin.sleepBlocks(1);miner.stop();
写入成功后可以看到具体的合约方法和地址:
下面我们先查询下新创建账号0xdd2b86ed99b469fe81063257f65b07b45047f73c的金额,调用call类型函数的方法:
contractInstance.balances.call("0xdd2b86ed99b469fe81063257f65b07b45047f73c",{from:"0x20cabfdcc5db00741f71a889085d39ae4c9bd990"})
下面我们尝试执行mint向指定地址添加金额,其中需要注意写入区块的因为是POW共识,所以一定要挖矿:
contractInstance.mint("0xdd2b86ed99b469fe81063257f65b07b45047f73c","10",{from:"0x20cabfdcc5db00741f71a889085d39ae4c9bd990"})
下面我们尝试转账,将地址 0x20cabfdcc5db00741f71a889085d39ae4c9bd990的转到0xdd2b86ed99b469fe81063257f65b07b45047f73c:
contractInstance.send("0xdd2b86ed99b469fe81063257f65b07b45047f73c","11",{from:"0x20cabfdcc5db00741f71a889085d39ae4c9bd990"})
并且通过交易hash可以查看交易信息:
eth.getTransactionReceipt("0x77538ee9b7b75c4235f81786be6ddd08f1087e91129defabbe417dbfb8e5d66c")
以上就一个创建私链并且添加自己的智能合约过程
区别:
这里有人可能就有疑问了,比特链是不是和以太链一样可以创建自己的智能合约,但是很遗憾,比特币作为第一个区块链和加密货币,并没有原生支持智能合约功能。比特币的设计目标主要是作为一种去中心化的数字货币,用于安全地进行价值转移。然而,虽然比特币本身不支持智能合约,但有一些项目和层次协议试图在比特币上实现智能合约功能。但是都是通过构建在比特币之上的侧链或层次协议来实现智能合约功能,并不是比特币本身的原生功能。相比之下,以太坊是专门设计用于支持智能合约的区块链平台,具有原生的智能合约功能,并提供了丰富的开发工具和编程语言来编写和部署智能合约。
比特币链(Bitcoin blockchain)和以太坊链(Ethereum blockchain)是两个不同的区块链网络,它们在设计目标、功能和特点上有一些显著的区别。
-
设计目标:
- 比特币链:比特币链的主要设计目标是实现去中心化的数字货币系统,即比特币(BTC)。它旨在提供安全、可靠的价值转移和存储,使用户可以进行去中心化的交易,而不依赖于中心化的机构。
- 以太坊链:以太坊链的设计目标是提供一个通用的区块链平台,支持智能合约和去中心化应用(DApps)的创建和执行。以太坊旨在实现一个可编程的区块链,使开发人员能够构建和部署各种去中心化应用和智能合约。
-
智能合约功能:
- 比特币链:比特币链本身没有原生支持智能合约功能。虽然比特币脚本语言(Script)提供了一些简单的脚本操作,如多重签名和时间锁定,但它的功能相对有限。
- 以太坊链:以太坊链是一个专为智能合约而设计的平台。它提供了一个完整的智能合约执行环境,使用 Solidity 等编程语言编写智能合约。以太坊的智能合约能够运行复杂的逻辑、与其他合约进行交互,并支持创建去中心化应用程序(DApps)和发行自定义代币。
-
编程语言和开发生态系统:
- 比特币链:比特币链的脚本语言相对简单,不太适合复杂的应用程序开发。因此,比特币上的开发生态系统相对较小,主要集中在与比特币交易和钱包相关的工具和库上。
- 以太坊链:以太坊提供了更丰富的编程语言和开发工具,主要使用 Solidity 进行智能合约开发。以太坊拥有庞大的开发者社区和丰富的开发生态系统,涵盖了各种开发框架、库和工具,以支持以太坊智能合约和DApps的开发。
-
扩展性和性能:
- 比特币链:比特币链的设计注重安全性和去中心化,因此其扩展性相对较低。比特币链的区块确认时间较长(约10分钟),交易吞吐量有限。
- 以太坊链:以太坊链在追求扩展性方面做出了一些努力,但仍面临着性能和可扩展性挑战。以太坊的区块确认时间较短(约15秒),但随着交易增加,网络拥堵和交易费用也可能增加。
总结起来,比特币链和以太坊链是两个不同的区块链网络,各自有不同的设计目标和功能。比特币链专注于去中心化的数字货币交易,而以太坊链则提供了更丰富的智能合约平台和去中心化应用开发能力。所以目前有很多基于以太坊创建的智能合约,但是比特币只能采用其他方法来创建智能合约,具体的方法后续会进行讲解。
永续合约:
在币圈经常会听到永续合约,很多新手对这个概念可能比较模糊,这里对永续合约进行讲解,要理解永续合约首先要理解什么叫期货,永续合约的全称为永续期货合约。
首先了解下什么是期货,正常我们购买东西都是一手交钱一手交货,这个就是现货交易,那么期货交易就是双方约定好在将来某个时间以某个价格交易某商品,约定的这个合约就是期货合约,比如我们和经销商约定好六个月后以十元一斤价格购买一百斤土豆,等到半年后的这天交割日经销商必须按照十元一斤给我一百斤土豆,而我也要支付响应的价格,这个就是期货交割合约,在这半年中如何保证双方不会违约,这就双方要交的保证金到对应的监管方,如果半年后土豆价格暴涨,我们就赚了,反之就要承担响应的损失。
理解了什么是期货合约,我们就知道合约就是双方进行一个约定,到约定日期生效就是我们的期货合约,但是如果我们不约定时间,或者说不受时间限制双方约定的就属于永续合约,双方均可以随时进行平仓结束合约或开始合约,这就是永续合约。
永续合约是一种衍生品合约,其特点如下:
-
无到期日:与传统期货合约不同,永续合约没有固定的到期日。交易者可以持有合约的头寸,直到决定平仓或被强制平仓。
-
资金费率机制:为了保持永续合约价格与标的资产价格的接近程度,永续合约引入了资金费率机制。资金费率是交易者之间的利息交换。如果合约价格与标的资产价格之间存在差异,资金费率将根据差异情况进行调整,以鼓励合约价格向标的资产价格靠近。
-
杠杆交易:永续合约通常支持杠杆交易,允许交易者使用较少的自有资金来控制更大数量的标的资产。交易者可以通过选择适当的杠杆倍数来放大头寸规模,以增加潜在盈利机会。然而,杠杆交易也带来了增加的风险,可能导致损失扩大。
-
强平机制:由于没有到期日,永续合约引入了强平机制,以防止交易者因持有不可持续的头寸而遭受巨大损失。交易所会设定一定的保证金要求,并根据市场价格波动情况对持仓进行标记和强制平仓。
简单说当我们购买永续合约的时候会根据当前行情对未来进行一个判断,比如我预计以后BTC价格会下降,那么我只要买看空的永续合约,当然也可以加杠杆进行操作,这样如果后续BTC真的和我预计的一样下跌,那么和我购买时候的价格相比,跌的金额乘杠杆就是我们的盈利,但是如果预测错了,价格上涨,则涨的价格就是我们损失的,如果杠杆加的太高,可能会因为保证金不足被强行平仓。
永续合约分为两种正向合约和反向合约,正向合约一张合约面值按BTC数量(价值多少个BTC),而反向合约是按USDT数量(价值多少USDT),下面我们用两个合约进行解释:
合约类型 | 合约面值 |
一张正向BTC合约面值 | 0.1 BTC |
一张反向BTC合约面值 | 100 USDT |
正向合约:
正向合约,即稳定币合约,指用USDT或者法币对比特币做合约交易。目前国内一些永续合约交易所已经开放多币种交易,也就是说你只要持有足够USDT,就可以直接做多个主流币种的合约交易。比如我们交易的是BTC,以USDT计价,保证金也是USDT。
假设当前BTC价格为2W美金,我们想以两倍杠杆买入5张BTC正向合约,那么我们需要支出多少保证金,并且可以操作的仓位价值又是多少,下面进行计算:
正向合约仓位价格=合约面值*合约张数*当前价格 正向合约仓位价格=杠杆倍数*保证金
所以很好理解:
合约面值*合约张数*当前价格=杠杆倍数*保证金
也就是说:
保证金=(合约面值*合约张数*当前价格)/杠杆倍数
套用金额分析:
(0.1*5*2W)/2=5000USDT
所以我们需要支付5000USDT来控制10000USDT的仓位价格,也就是5张价值0.1BTC价值10000USDT的合约。
然后算下我们的盈利,这里以看涨为例,看空则相反:
盈利=(平仓价-开仓价)*合约面值*合约张数
也就是说如果我买的时候是2w美金,现在我想平仓了,当前价格是3w美金,则结果如下:
(30000-20000)*0.1*5=5000usdt
就是我用5000usdt使用两倍杠杆正向合约赚了5000usdt
那什么情况下会爆仓,当亏损=保证金的情况下就会亏损,对应的公式可以计算
差价*合约面值*合约张数=保证金 保证金=(合约面值*合约张数*当前价格)/杠杆倍数 差价*合约面值*合约张数=(合约面值*合约张数*开仓价)/杠杆倍数
最后公式为:
差价 = 开仓价/杠杆倍数
则如果是2w美金,如果是两倍杠杆,则当20000/2=10000,跌幅为1w的情况下会被强行平仓,如果是十倍杠杆,则20000/10=2000,当跌了2000就被平仓,也就是当BTC跌幅为10%,就被强行平仓。
反向合约:
下面来看看反向合约,反向合约是指持有多个币种做对应交易,即币本位合约。反向合约意味着,如果你要做比特币的合约交易,就必须用比特币作为本位币,如果是以太坊合约交易,那就得持有以太坊才行。
假设在反向合约中我们想拥有和上面一样10000USDT的仓位,当前一张反向合约对应100usdt,那么我们需要购买100张合约,算下对应的保证金
反向合约的仓位价值=合约面值*合约张数 反向合约的仓位价值=杠杆倍数*保证金数量*当前价格
所以可以得到如下公式:
合约面值*合约张数=杠杆倍数*保证金数量*当前价格
所以对应的保证金数量为:
保证金数量=(合约面值*合约张数)/(杠杆倍数*当前价格)
对应的我们计算(100*100)/(2*20000)=0.25BTC,计算下0.25BTC,0.25*20000=50000usdt,可以发现和正向合约的价格是一样的,但是我们使用的保证金不是ustd而是对应的本币btc
然后我们同样计算盈利:
反向合约的盈亏 = 合约乘数*合约张数/开仓价-合约乘数*合约张数/平仓价 =(1/开仓价-1/平仓价)*合约乘数*合约张数
如果买的时候是2w美金。卖的时候是3w美金,计算盈利为100*100/20000-100*100/30000=0.1666..btc,按照当前的价格3w计算约等于5000usdt,和正向相同,但是由于我们是反向合约,交易的是btc,做多的时候随着价格升值,我们获得的btc数量是变少的,做少的时候由于价格降低,我们获得的btc是变多的,这个很好理解,因为我们最后还是要将btc对应到usdt价格。
再来看看爆仓,分为做多和做空:
平仓价 = 开仓价(1-1/(杠杆倍数+1)) 做多 平仓价 = 开仓价(1+1/(杠杆倍数-1)) 做空
可以发现如果是做多,当为一倍杠杆的情况下,2w的开仓价,当跌了50%,即1w美金就会爆仓,但是做空的情况下一倍杠杆不会爆仓,因此反向合约做空比做多安全,BitMEX也被称为空军基地。
总结:
上面对智能合约技术层面进行了分析,并讲解了永续合约,智能合约在加密货币市场玩的比较多,永续合约也被很多投资客追捧,但是投资需谨慎,币圈价格震荡太大,还是要做好基础知识的研究再入场,不要脑子一热就冲进去,不要被暴富神话冲昏了头脑。