智能合约笔记

前言:

首先了解下为什么会出现智能合约,打个比方现在有两个人A和B打赌明天会不会下雨,每个人赌注100元,如果第二天下雨则A拿走200元,否则B拿走200元,这样就有一个问题,赌注要到第二天才能见效,如果两个人是知根知底的熟人还是君子,那么可以定一个君子协定,但是这个并不适用于陌生人或者信誉不好的人,那么应该怎么办,只能找个中间人,类似于裁判,需要对赌注结果进行判断而且保管赌金,这就带来了第二个问题,这个中间人可靠不可靠,信任如何解决,这里就出现了智能合约,通过计算机代码来控制合约内容,并保管金额,只要代码经过双方审核没有问题合约生效,就不会有人为因素来干扰,解决了信任问题。

所以智能合约(Smart contracts)是一种基于区块链技术的自动化合约。它们是一组以编程形式定义的计算机代码,旨在执行、验证或执行合同中的特定条件或条款。

智能合约运行在区块链上,通过区块链的去中心化和分布式特性,实现了在没有中间人的情况下进行可靠的交易和合约执行。智能合约的代码和执行结果被记录在区块链的区块中,具有透明性、不可篡改性和可验证性。

智能合约可以用于各种场景,例如数字货币交易、资产转让、投票、供应链管理、保险索赔等。合约的条件和逻辑由编程语言来定义,常见的智能合约平台使用的编程语言包括 Solidity(用于以太坊)、Vyper(用于以太坊)、Corda(用于 Corda 区块链平台)等。

智能合约的执行通常基于预先设定的条件和触发事件。一旦满足了合约的条件,智能合约将自动执行相应的操作,例如转移资金、更新状态或触发其他合约。这种自动化的执行消除了中介机构的需求,减少了交易成本并提高了执行的效率。

搭建以太坊合约:

这里我们以以太坊为例,讲讲底层是如何实现智能合约,首先我们需要知道以以太坊有C和go两个版本,但是其智能合约可以使用如下四种语言:

  1. Solidity ,受JavaScript 启发
  2. Serpent ,受Python启发
  3. Mutan,受Go 启发
  4. 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.accounts1、查看账户余额,返回值的单位是 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)是两个不同的区块链网络,它们在设计目标、功能和特点上有一些显著的区别。

  1. 设计目标:

    • 比特币链:比特币链的主要设计目标是实现去中心化的数字货币系统,即比特币(BTC)。它旨在提供安全、可靠的价值转移和存储,使用户可以进行去中心化的交易,而不依赖于中心化的机构。
    • 以太坊链:以太坊链的设计目标是提供一个通用的区块链平台,支持智能合约和去中心化应用(DApps)的创建和执行。以太坊旨在实现一个可编程的区块链,使开发人员能够构建和部署各种去中心化应用和智能合约。
  2. 智能合约功能:

    • 比特币链:比特币链本身没有原生支持智能合约功能。虽然比特币脚本语言(Script)提供了一些简单的脚本操作,如多重签名和时间锁定,但它的功能相对有限。
    • 以太坊链:以太坊链是一个专为智能合约而设计的平台。它提供了一个完整的智能合约执行环境,使用 Solidity 等编程语言编写智能合约。以太坊的智能合约能够运行复杂的逻辑、与其他合约进行交互,并支持创建去中心化应用程序(DApps)和发行自定义代币。
  3. 编程语言和开发生态系统:

    • 比特币链:比特币链的脚本语言相对简单,不太适合复杂的应用程序开发。因此,比特币上的开发生态系统相对较小,主要集中在与比特币交易和钱包相关的工具和库上。
    • 以太坊链:以太坊提供了更丰富的编程语言和开发工具,主要使用 Solidity 进行智能合约开发。以太坊拥有庞大的开发者社区和丰富的开发生态系统,涵盖了各种开发框架、库和工具,以支持以太坊智能合约和DApps的开发。
  4. 扩展性和性能:

    • 比特币链:比特币链的设计注重安全性和去中心化,因此其扩展性相对较低。比特币链的区块确认时间较长(约10分钟),交易吞吐量有限。
    • 以太坊链:以太坊链在追求扩展性方面做出了一些努力,但仍面临着性能和可扩展性挑战。以太坊的区块确认时间较短(约15秒),但随着交易增加,网络拥堵和交易费用也可能增加。

总结起来,比特币链和以太坊链是两个不同的区块链网络,各自有不同的设计目标和功能。比特币链专注于去中心化的数字货币交易,而以太坊链则提供了更丰富的智能合约平台和去中心化应用开发能力。所以目前有很多基于以太坊创建的智能合约,但是比特币只能采用其他方法来创建智能合约,具体的方法后续会进行讲解。

永续合约:

在币圈经常会听到永续合约,很多新手对这个概念可能比较模糊,这里对永续合约进行讲解,要理解永续合约首先要理解什么叫期货,永续合约的全称为永续期货合约。

首先了解下什么是期货,正常我们购买东西都是一手交钱一手交货,这个就是现货交易,那么期货交易就是双方约定好在将来某个时间以某个价格交易某商品,约定的这个合约就是期货合约,比如我们和经销商约定好六个月后以十元一斤价格购买一百斤土豆,等到半年后的这天交割日经销商必须按照十元一斤给我一百斤土豆,而我也要支付响应的价格,这个就是期货交割合约,在这半年中如何保证双方不会违约,这就双方要交的保证金到对应的监管方,如果半年后土豆价格暴涨,我们就赚了,反之就要承担响应的损失。

理解了什么是期货合约,我们就知道合约就是双方进行一个约定,到约定日期生效就是我们的期货合约,但是如果我们不约定时间,或者说不受时间限制双方约定的就属于永续合约,双方均可以随时进行平仓结束合约或开始合约,这就是永续合约。

永续合约是一种衍生品合约,其特点如下:

  1. 无到期日:与传统期货合约不同,永续合约没有固定的到期日。交易者可以持有合约的头寸,直到决定平仓或被强制平仓。

  2. 资金费率机制:为了保持永续合约价格与标的资产价格的接近程度,永续合约引入了资金费率机制。资金费率是交易者之间的利息交换。如果合约价格与标的资产价格之间存在差异,资金费率将根据差异情况进行调整,以鼓励合约价格向标的资产价格靠近。

  3. 杠杆交易:永续合约通常支持杠杆交易,允许交易者使用较少的自有资金来控制更大数量的标的资产。交易者可以通过选择适当的杠杆倍数来放大头寸规模,以增加潜在盈利机会。然而,杠杆交易也带来了增加的风险,可能导致损失扩大。

  4. 强平机制:由于没有到期日,永续合约引入了强平机制,以防止交易者因持有不可持续的头寸而遭受巨大损失。交易所会设定一定的保证金要求,并根据市场价格波动情况对持仓进行标记和强制平仓。

简单说当我们购买永续合约的时候会根据当前行情对未来进行一个判断,比如我预计以后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也被称为空军基地。

总结:

上面对智能合约技术层面进行了分析,并讲解了永续合约,智能合约在加密货币市场玩的比较多,永续合约也被很多投资客追捧,但是投资需谨慎,币圈价格震荡太大,还是要做好基础知识的研究再入场,不要脑子一热就冲进去,不要被暴富神话冲昏了头脑。

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/239638.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

每日一题——LeetCode1189.气球的最大数量

方法一 个人方法: 统计text字符串中b、a、l、o、n 这几个字符出现的次数 l和n需要两个才能拼成一个balloon,所以碰到l和o加1,其他字符加2 最后求出出现次数最少的那个字符再除以2就是能拼凑成的单词数量,避免出现小数要使用向下…

MySQL 从零开始:04 增删改查

文章目录 1、准备工作2、insert 增加数据2.1 添加所有列的数据2.2 添加部分列2.3 一次插入多条数据 3、delete 删除记录4、update 更新记录5、select 查询记录5.1 查询所有行所有列5.2 查询指定行的所有列5.3 查询所有行的指定列5.4 查询指定行的指定列 在上一小节中介绍了 MyS…

leetcode第365题:水壶问题

有两个水壶,容量分别为 jug1Capacity 和 jug2Capacity 升。水的供应是无限的。确定是否有可能使用这两个壶准确得到 targetCapacity 升。 如果可以得到 targetCapacity 升水,最后请用以上水壶中的一或两个来盛放取得的 targetCapacity 升水。 你可以&a…

C练习——杨辉三角

题目: 打印近似杨辉三角,行数n自选 百度找的杨辉三角,参考一下: 解析: 把它的全部元素左对齐,就可以看成近似杨辉三角的样子 1 1 1 1 2 1 1 3 3 1 1 4 6 4 1 …… 每个数等于它上方两数…

第一个 OpenGL 程序:旋转的立方体(VS2022 / MFC)

文章目录 OpenGL API开发环境在 MFC 中使用 OpenGL初始化 OpenGL绘制图形重置视口大小 创建 MFC 对话框项目添加 OpenGL 头文件和库文件初始化 OpenGL画一个正方形OpenGL 坐标系改变默认颜色 重置视口大小绘制立方体使用箭头按键旋转立方体深度测试添加纹理应用纹理换一个纹理 …

随笔03 笔记整理

图源:文心一言 关于我的考研与信息安全类博文整理~🥝🥝 第1版:整理考研类博文~🧩🧩 第2版:提前列出博文链接,以便小伙伴查阅~🧩🧩 第3版:整理We…

SLF4J Spring Boot日志框架

JAVA日志框架 JAVA有好多优秀的日志框架,比如log4j、log4j2、logback、JUL(java.util.logging)、JCL(JAVA Common Logging)等等,logback是后起之秀,是Spring Boot默认日志框架。 今天文章的目…

快速了解——逻辑回归及模型评估方法

一、逻辑回归 应用场景:解决二分类问题 1、sigmoid函数 1. 公式: 2. 作用:把 (-∞,∞) 映射到 (0, 1) 3. 数学性质:单调递增函数,拐点在x0,y0.5的位置 4. 导函数公式:f…

【镜像制作】OS云主机镜像的制作——以H3C为例

一、云主机镜像简介 1.云主机镜像 云主机镜像不同于容器镜像,是一个含有引导分区、操作系统以及必要应用的单一文件,可以理解成是对整个系统安装光盘所有数据的克隆文件。云用户在创建和申请云主机时可通过选择不同的镜像来快速获取相应操作…

一文读懂「Prompt Engineering」提示词工程

在了解提示过程之前,先了解一下什么是提示prompt,见最后附录部分 一、什么是Prompt Engingering? 提示工程(Prompt Engingering),也被称为上下文提示(In-Context Prompting)&#x…

Android的setContentView流程

一.Activity里面的mWindow是啥 在ActivityThread的performLaunchActivity方法里面: private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {ActivityInfo aInfo r.activityInfo;if (r.packageInfo null) {r.packageInfo getP…

常见面试题之CSS

CSS3的新特性 新增选择器::nth-child()、:first-of-type、:last-of-type等 弹性盒子:display: flex 媒体查询:media根据设备的特性和屏幕大小应用不同的样式规则 多列布局:column-count和column-with等属性可以实现将内容分为多…

SpringBoot读取配置文件中的内容

文章目录 1. 读取配置文件application.yml中内容的方法1.1 Environment1.2 Value注解1.3 ConfigurationProperties 注解1.4 PropertySources 注解,获取自定义配置文件中的内容,yml文件需要自行实现适配器1.5 YamlPropertiesFactoryBean 加载 YAML 文件1.…

缓存和数据库一致性

前言: 项目的难点是如何保证缓存和数据库的一致性。无论我们是先更新数据库,后更新缓存还是先更新数据库,然后删除缓存,在并发场景之下,仍然会存在数据不一致的情况(也存在删除失败的情况,删除…

软件测试|解决Github port 443 : Timed out连接超时的问题

前言 GitHub是全球最大的开源代码托管平台之一,许多开发者和团队使用它来管理和协作开源项目。但在当下,我们在clone或者提交代码时会经常遇到"GitHub Port 443: Timed Out"错误,这意味着我们的电脑无法建立与GitHub服务器的安全连…

鸿蒙Harmony--AppStorage--应用全局的UI状态存储详解

无所求必满载而归,当你降低期待,降低欲望,往往会得到比较好的结果,把行动交给现在,用心甘情愿的态度,过随遇而安的生活,无论结果如何,都是一场惊喜的获得! 目录 一,定义 …

MySQL单表查询练习题

一、创建表的素材 表名:worker——表中字段均为中文,比如:部门号、工资、职工号、参加工作等 CREATE TABLE worker ( 部门号 int(11) NOT NULL, 职工号 int(11) NOT NULL, 工作时间 date NOT NULL, 工资 float(8,2) NOT NULL, 政治面貌 …

MySQL进阶45讲【1】基础架构:一条SQL查询语句是如何执行的?

1 前言 我们经常说,看一个事儿千万不要直接陷入细节里,应该先鸟瞰其全貌,这样能够帮助你从高维度理解问题。同样,对于MySQL的学习也是这样。平时我们使用数据库,看到的通常都是一个整体。比如,有个最简单的…

uniapp 字母索引列表插件(组件版) Ba-SortList

简介(下载地址) Ba-SortList 是一款字母索引列表组件版插件,可自定义样式,支持首字母字母检索、首字检索、搜索等等;支持点击事件。 支持首字母字母检索支持首字检索支持搜索支持点击事件支持长按事件支持在uniapp界…

八:分布式锁

1、为什么要使用分布式锁 锁是多线程代码中的概念,只有多任务访问同一个互斥的共享资源时才需要锁。单机应用开发时一般使用synchronized或lock。多线程的运行都是在同一个JVM之下。应用是分布式集群,属于多JVM的工作环境,JVM之间已经无法通过…