梵克雅寶四葉草項(xiàng)鏈官網(wǎng)刷seo排名
上文 Web3 敘述交易所授權(quán)置換概念 編寫transferFrom與approve函數(shù)我們寫完一個簡單授權(quán)交易所的邏輯 但是并沒有測試
其實(shí)也不是我不想 主要是 交易所也沒實(shí)例化 現(xiàn)在也測試不了
我們先運(yùn)行 ganache 啟動一個虛擬的區(qū)塊鏈環(huán)境
先發(fā)布 在終端執(zhí)行
truffle migrate
如果你跟著我一步一步來的 那編譯應(yīng)該就會通過的
然后的話 我們要將交易所的合約也創(chuàng)建一下
在項(xiàng)目根目錄下的 contracts 目錄下 創(chuàng)建一個文件叫 Exchange.sol
然后 先編寫出最基本的結(jié)構(gòu)
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.4.16 <0.9.0;
import "@openzeppelin/contracts/utils/math/SafeMath.sol";contract Exchange {using SafeMath for uint256;
}
然后 這里 我們需要指定一個收費(fèi)賬號 因?yàn)?我們交易所大家可以直接理解為中介
但與互聯(lián)網(wǎng)中介不同的在于 我們這個合約是純公開透明的 但大家在這里交換代幣 比如 預(yù)料到什么代幣可能要漲了 趕緊轉(zhuǎn)入一些 交易所從中間獲取部分利益自然也是無可厚非的 而且 這個都是公開透明的
然后 還有一個費(fèi)率的問題 例如 有些 我們每次交易 費(fèi)率是百分之六 就比如你在虎牙送主播禮物其實(shí)主播只能拿到一小部分,大部分是平臺的 你可以理解為被平臺拿走的部分就叫費(fèi)率 當(dāng)然直播平臺估計要到百分之五十以上 平臺拿到的會比主播多 一般交易平臺費(fèi)率應(yīng)該就會少一點(diǎn) 大概在百分之十以內(nèi)
我們可以直接這樣寫
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.4.16 <0.9.0;
import "@openzeppelin/contracts/utils/math/SafeMath.sol";contract Exchange {using SafeMath for uint256;//收費(fèi)賬號地址address public feeAccout;//費(fèi)率uint256 public feePercent;//實(shí)例化合約交易所constructor(address _feeAccout,uint256 _feePercent) {//用接到的參數(shù)給賬號地址和費(fèi)率賦值feeAccout = _feeAccout;feePercent = _feePercent;}
}
這里 我們先定義了兩個變量 address 地址類型 feeAccout 設(shè)置了public表示這個變量是公開的 用于存儲收費(fèi)賬號的地址
然后uint256數(shù)字類型的feePercent 記錄費(fèi)率使用
然后在合約實(shí)例化的constructor中從外面接受賬號地址和費(fèi)率的值 然后給上面兩個變量賦值
但還有一個問題 我們的交易所不可能只存一種貨幣 不然我們那什么去跟別人兌換呢 是不是 或者是 你只存一種 對話來干嘛呢?
那么 我們交易所中就可以存一個這樣的對象
我們先用js結(jié)構(gòu)闡述
{"A代幣地址":{"A用戶地址": 300,"B用戶地址": 400},"B代幣地址": {"A用戶地址": 500}
}
大概就是這樣的一個結(jié)構(gòu) 第一層對象是目前有存儲的所有代幣地址 他們對應(yīng)的值 是 這個代幣下 每個用戶 值對應(yīng)擁有的數(shù)量
在solidity中 我們可以這樣寫
mapping(address=> mapping(address=>uint256)) public tokens;
我們定義了一個對象 然后 鍵是一個address地址類型 值是一個對象 值中的對象 鍵也是address地址類型 值是uint256數(shù)字類型
然后設(shè)置public表示它是公開的 然后名字叫 tokens 名字可以看心情去定義
但是 光有數(shù)據(jù)自然是無法完成邏輯 我們還需要一個存款的方法
我們可以這樣寫
這里 我們定義了兩個方法 第一個用來充值ETH 第二個則是gerToken的充值函數(shù)
然后我們用public聲明函數(shù)公開
然后payable則聲明這是個充值的函數(shù)
//轉(zhuǎn)入 ETHfunction depositEther() payable public {}//轉(zhuǎn)入 gerTokenfunction depositToken() payable public {}
然后 我們在上面定義一個常量
// ETH 代幣地址
address constant ETHER = address(0);
正常來講 這個的值應(yīng)該是一個地址 是我們 ETH代幣對應(yīng)的地址 但是 我們這里只是模擬 就隨便寫了一個 address(0)
這樣也符合address的一個地址規(guī)范
然后 我們還得寫一個事件來充當(dāng)日志 記錄充值操作
這里 我寫的 叫 Deposit 這個 其實(shí)大家可以順便取名字 你叫 A 叫B都可以
參考代碼如下
event Deposit(address token,address user,uint256 amount,uint256 balance);//存入ETH
然后 我們的depositEther 存入 ETH 的函數(shù)邏輯就可以開始寫了
//轉(zhuǎn)入 ETH
function depositEther() payable public {tokens[ETHER][msg.sender] = tokens[ETHER][msg.sender].add(msg.value);emit Deposit(ETHER,msg.sender, msg.value, tokens[ETHER][msg.sender]);
}
ETHER 就是我們剛剛創(chuàng)建的代幣標(biāo)識 值是address(0) 這個只是我們亂寫的一個地址 因?yàn)槲覀兡壳爸皇菧y試
我們就假設(shè)我們的交易所 0就代表ETH 然后msg.sender 代表當(dāng)前用戶的地址 然后msg.value是需要操作的金額
之前我們說過 這個tokens是存儲 代幣地址 然后 用戶持有數(shù)量的對象
這里 我們操作 add 給用戶在token對象中的對應(yīng)ETH 加上msg.value的數(shù)值
然后 我們調(diào)用自己剛剛寫的Deposit來記錄這次交易
Deposit 第一個參數(shù) ETHER 代幣地址 msg.sender 當(dāng)前用戶 msg.value 操作數(shù)值 tokens[ETHER][msg.sender] 在tokens中找到代幣地址對應(yīng)的對象下的對應(yīng)當(dāng)前用戶對應(yīng)的數(shù)值 簡單說 最后一個要的是用戶該代幣的總數(shù)
然后 ETH的充值操作已經(jīng)完成了
那么 grToken也需要一個充值邏輯
但是 我們不應(yīng)該直接在交易所中操作 而是要通過我們代幣的合約 去操作
我們引入 grToken的合約文件
然后 depositToken 代碼編寫如下
//轉(zhuǎn)入 gerToken
function depositToken(address _token, uint256 _amount) payable public {require(grToken(_token).transferFrom(msg.sender,address(this),_amount));tokens[_token][msg.sender] = tokens[_token][msg.sender].add(_amount);emit Deposit(_token,msg.sender, _amount, tokens[_token][msg.sender]);
}
這里 我們兩個參數(shù) _token代幣地址 _amount需要充入金額
然后 我們的下一句可能有問題 所以套上了require來調(diào)用 之前我們講過 require 如果代碼錯誤 他會立刻停止程序 并將錯誤記錄在區(qū)塊鏈上
然后我們實(shí)例化grToken 合約對象 地址就 傳入我們的_token調(diào)用其中的transferFrom函數(shù) 扣款用戶就是msg.sender 當(dāng)前操作這個函數(shù)的用戶 收款地址address(this)我們交易所本身 數(shù)額就是方法接到的_amount參數(shù)
然后 操作完成之后 我們再次通過tokens 操作用戶在對象中的代幣數(shù)值
然后調(diào)用 我們剛剛定義的 Deposit 記錄交易
然后 我們編譯一下試試
終端輸入
truffle compile
沒有任何問題
但 我們部署之前 還需要寫個腳本 你別合約好不容易寫完了 但沒有寫腳本去使用它
我們在migrations目錄下創(chuàng)建一個2_contract.js
編寫代碼如下
const grToken = artifacts.require("grToken.sol")
const Exchange = artifacts.require("Exchange.sol")
module.exports = async function(deployer) {const accounts = await web3.eth.getAccounts();await deployer.deploy(grToken);await deployer.deploy(Exchange,accounts[0],3);
}
這里 我們導(dǎo)入了grToken代幣合約和Exchange交易所合約
然后 調(diào)用web3的getAccounts拿到用戶列表
然后發(fā)布兩個合約
其中 Exchange本身需要兩個參數(shù) 一個是 收款用戶 就是交易所得到的小費(fèi)給哪個用戶 以及后面的費(fèi)率
我們這里費(fèi)率少一點(diǎn) 寫個百分之三吧
然后 地址 我們直接在用戶列表中找到下標(biāo)為0的用戶 因?yàn)榘l(fā)布時 燃料消耗的第一個用戶 那么 小費(fèi)自然也應(yīng)該歸他
我們終端執(zhí)行
truffle migrate --reser
更新發(fā)布一下智能合約
這里 發(fā)布成功了 但是 我們還是得測試一下
首先 我們用MetaMask導(dǎo)入一下 我們ganache中的第一個用戶
我們在項(xiàng)目根目錄下的scripts 目錄下創(chuàng)建 test.js
參考代碼如下
const GrToken = artifacts.require("grToken.sol")
const Exchange = artifacts.require("Exchange.sol")const toWei = (bn) => {return web3.utils.fromWei(bn, "ether");
}
const inWei = (bn) => {return web3.utils.toWei(bn.toString(), "ether");
}module.exports = async function(callback) {const grTokenDai = await GrToken.deployed();const exchage = await Exchange.deployed();const accounts= await web3.eth.getAccounts()await exchage.depositEther({from: accounts[0],value: inWei(10)});callback()
}
我們先導(dǎo)入了 代幣 grToken 和 交易所 Exchange的合約
然后 調(diào)用了Exchange的depositEther 來充值ETH 具體要存入的用戶 依舊通過getAccounts拿取用戶列表 然后操作第一個去存儲
然后 我們終端執(zhí)行
truffle exec .\scripts\test.js
然后查看 MetaMask 會發(fā)現(xiàn)用戶的款確實(shí)扣了
在運(yùn)行一次 就又少 10
當(dāng)然 這里只是存入 但對用于來講 最直觀的就是看ETH少了
而且應(yīng)該還會更少一些 因?yàn)?還有燃料需要消耗
還挺坑的 老實(shí)說
然后 我們可以查一下存款
scripts 目錄下創(chuàng)建 test.js
編寫代碼如下
const GrToken = artifacts.require("grToken.sol")
const Exchange = artifacts.require("Exchange.sol")
const ETHER_ADDRESS = '0x0000000000000000000000000000000000000000';const toWei = (bn) => {return web3.utils.fromWei(bn, "ether");
}
const inWei = (bn) => {return web3.utils.toWei(bn.toString(), "ether");
}module.exports = async function(callback) {const grTokenDai = await GrToken.deployed();const exchage = await Exchange.deployed();const accounts= await web3.eth.getAccounts()await exchage.depositEther({from: accounts[0],value: inWei(10)});let res = await exchage.tokens(ETHER_ADDRESS,accounts[0])console.log(toWei(res));callback()
}
我們這里直接寫死了0x0000000000000000000000000000000000000000 這個就是我們設(shè)置以太坊的地址
然后 通過交易所定義的 tokens 定義的get特性 通過ETH 的地址和賬號地址查看存入的代幣
然后 我們再次運(yùn)行
truffle exec .\scripts\test.js
因?yàn)槲覀儨y試操作了很多次 所以 這個數(shù)值是沒問題的
大不了 我們再來一次
又存進(jìn)去10 變成了 130
我們賬號也其實(shí)少了很多
那么 ETH就好了
然后 我們來操作 grToken
但是 這個 我們需要先授權(quán) 允許交易所來操作我們的grToken
我們直接給scripts 目錄下創(chuàng)建 test.js 寫成這樣
const GrToken = artifacts.require("grToken.sol")
const Exchange = artifacts.require("Exchange.sol")const toWei = (bn) => {return web3.utils.fromWei(bn, "ether");
}
const inWei = (bn) => {return web3.utils.toWei(bn.toString(), "ether");
}module.exports = async function(callback) {const grTokenDai = await GrToken.deployed();const exchage = await Exchange.deployed();const accounts= await web3.eth.getAccounts()await grTokenDai.approve(exchage.address,inWei(100000),{from: accounts[0]})await exchage.depositToken(grTokenDai.address,inWei(10000),{from: accounts[0]})let res = await exchage.tokens(grTokenDai.address,accounts[0])console.log(toWei(res));callback()
}
這里 我們先調(diào)用grTokenDai我們上文中寫的 交易所授權(quán)函數(shù)approve 第一個參數(shù) 交易所地址 我們?nèi)xchage的address 授權(quán)的數(shù)量 是 100000授權(quán)賬號是 第一個賬號
然后 我們調(diào)用我們交易所寫的depositToken 存入grToken代幣
然后 第一個參數(shù)是grTokenDai的address地址 然后數(shù)量10000 存入的用戶還是我們的第一個用戶
然后 我們查看grtoken數(shù)量
因?yàn)間rTokenDai.address
我們再次運(yùn)行
truffle exec .\scripts\test.js
可以看到這個效果