用户登陆
正在加载
EOS钱包开发:如何买入或卖出RAM?
互联网 · 2019-01-19 09:18:21

目标

  1. 如何获取全网RAM相关的公共数据
  2. 如何使用Bancor算法计算实时的RAM价格
  3. 如何购买RAM
  4. 如何卖出RAM

前言

现在我们能获取到了基于测试网络的账号的网络资源数据,现在我们就介绍如何交易RAM。

交易RAM的前提是我们需要知道它的价格,即买1KB内存需要花费多少EOS,卖1个EOS能获取多少内存。这就需要我们去链上查询数据库获取相应的实时的数据,再进行计算拿到单价。下面我们来一步步实现,最后展示在项目中的相应源码。

一、获取全网RAM数量

全网RAM数量的数据是存在数据库中的,需要使用eosjs库的getTableRows方法获取,或者RPC的chain/get_table_rows接口获取。下面会有eosjs进行交易,所以本章我们统一使用eosjs访问数据,可以到官网查看eosjs-api接口文档。

首先访问主网中RAM的数量。

Eos = require('eosjs')eosconfig = {
    httpEndpoint: 'https://node1.zbeos.com',
    chainId: 'aca376f206b8fc25a6ed44dbdc66547c36c6c33e3a119ffbeaef943642f0e906',    // keyProvider: privatekeyList, // WIF string or array of keys..
    expireInSeconds: 60,
    broadcast: true,
    verbose: false, // API activity
    sign: true
},
eos = Eos(eosconfig)eos.getTableRows(true,"eosio","eosio","global").then(result => {
    console.log(result)
})
输出如下
{ rows:
   [ { max_block_net_usage: 1048576,
       target_block_net_usage_pct: 1000,
       max_transaction_net_usage: 524288,
       base_per_transaction_net_usage: 12,
       net_usage_leeway: 500,
       context_free_discount_net_usage_num: 20,
       context_free_discount_net_usage_den: 100,
       max_block_cpu_usage: 200000,
       target_block_cpu_usage_pct: 2000,
       max_transaction_cpu_usage: 150000,
       min_transaction_cpu_usage: 100,
       max_transaction_lifetime: 3600,
       deferred_trx_expiration_window: 600,
       max_transaction_delay: 3888000,
       max_inline_action_size: 4096,
       max_inline_action_depth: 4,
       max_authority_depth: 6,
       max_ram_size: '88414727168',
       total_ram_bytes_reserved: '49777052734',
       total_ram_stake: '26261375993',
       last_producer_schedule_update: '2018-11-05T06:57:51.000',
       last_pervote_bucket_fill: '1541399606000000',
       pervote_bucket: 219209992,
       perblock_bucket: 36804696,
       total_unpaid_blocks: 95761,
       total_activated_stake: '4035546740321',
       thresh_activated_stake_time: '1529505892000000',
       last_producer_schedule_size: 21,
       total_producer_vote_weight: '24124687214114213888.00000000000000000',
       last_name_close: '2018-11-05T02:08:26.000' } ],
  more: false }
其中“max_ram_size“字段的数据就是全网RAM的数量,单位是bytes,那么转换为G,则结果为:88402589696/(1024*1024*1024)=82.34263134002686 G。获取方式如下:
eos.getTableRows(true,"eosio","eosio","global").then(result => {
    //ram总量,bytes转为G
    let ramTotal = result.rows[0].max_ram_size / (1024*1024*1024)  
})

二、获取RAM使用量、计算RAM价格

与获取RAM总量一样,我们使用eosjs库的getTableRows方法获取主网中RAM的使用量、消耗RAM的EOS数量,最后通过Bancor算法计算RAM价格。

eosconfig = {
    httpEndpoint: 'https://node1.zbeos.com',
    chainId: 'aca376f206b8fc25a6ed44dbdc66547c36c6c33e3a119ffbeaef943642f0e906',    // keyProvider: privatekeyList, // WIF string or array of keys..
    expireInSeconds: 60,
    broadcast: true,
    verbose: false, // API activity
    sign: true
},
eos = Eos(eosconfig)eos.getTableRows(true, "eosio", "eosio", "rammarket").then(ramData => {
    console.log(ramData)
})

输出如下

9A5D836D-283E-40DC-B16A-38AFB4658E5E

  • 其中“base“字段里的“balance”数据就是全网RAM的使用量,单位是bytes。
  • “quote“字段里的“balance”数据就是消耗RAM的EOS数量。

下面根据Bancor算法算出RAM的价格

ramPrice = quote.balance / (base.balance / 1024)

Bancor协议是底层货币协议,通过区块链技术和智能合约为加密数字货币提供连续流动性和实现异步价格。

所以ramPrice的获取方式如下:

eos.getTableRows(true, "eosio", "eosio", "rammarket").then(ramData => {
    console.log(ramData)
    //RAM消耗的EOS数量
    let eosAmount = ramData.rows[0].quote.balance.split(" ")[0];
    //RAM使用量
    let ramAmount = ramData.rows[0].base.balance.split(" ")[0] / 1024;
    //RAM价格
    let ramPriceWithEOS = eosAmount / ramAmount
    console.log(eosAmount, ramAmount, ramPriceWithEOS);
})

三、买入RAM

买入RAM的API其实我们已经使用过了,在创建账号的时候我们为别人创建的账号就需要为它购买一定的RAM,现在我们在来单独调用购买的API。由于现在需要交易,所以会使用资源,因此我们重新配置一下eosconfig切换到测试网络进行测试。

eosconfig = {
    httpEndpoint:"http://jungle.cryptolions.io:18888",
    chainId: "038f4b0fc8ff18a4f0842a8f0564611f6e96e8535901dd45e43ac8691a1c4dca", // 32 byte (64 char) hex string
    keyProvider: ["5HqCj7sg4K2xZ1KD5sSH38kuJkKGqfE1wSGiLL3M599ajacVmTs"], 
    expireInSeconds: 60,
    broadcast: true,
    verbose: false, // API activity
    sign: true
},eos = Eos(eosconfig)eos.getTableRows(true, "eosio", "eosio", "rammarket").then(ramData => {
    console.log(ramData)
    //RAM消耗的EOS数量
    let eosAmount = ramData.rows[0].quote.balance.split(" ")[0];
    //RAM使用量
    let ramAmount = ramData.rows[0].base.balance.split(" ")[0] / 1024;
    //RAM价格
    let ramPriceWithEOS = eosAmount / ramAmount
    console.log(eosAmount, ramAmount, ramPriceWithEOS);
})let account = "lixutest1111"
let ramAmount = 8*1024
async function buyRAM() {
    result = await eos.transaction(tr => {
        tr.buyrambytes({
            payer: account,
            receiver: account,
            bytes: ramAmount
        })
    })
    console.log(result)
}
buyRAM()

在运行之前先记录下来账号“lixutest1111”的网络资源数据。

16922119-4D43-4E58-BE15-1A91CD49EAC1

运行后看到价格是0.07576784159120188 EOS/KB

1A22A00B-D38E-481B-BA95-43991A32D684

代码中是买了8KB的RAM,那我们计算一下,需要花费多少EOS,其实很简单

8KB * 0.07576784159120188 EOS/KB = 0.6061EOS
那我们再计算一下账号“lixutest1111”现在的EOS可用余额和RAM总量是多少
78.7959 - 0.6061 = 78.1898EOS
13.30 + 8 = 21.30KB

计算好以后我们再看看现在账号“lixutest1111”的在链上的资源数据是多少。

6C676B46-83CF-4BB3-A84B-FCE67370E536

可以发现计算的结果和链上的结果有了一定的偏差,这是因为RAM价格会随着市场波动而变化,所以导致结果有一点点偏差,这是不可避免的。另外我们在购买RAM的时候,需要输入的是EOS数量,然后根据RAM价格转换成需要购买的RAM大小,再进行交易。

四、卖出RAM

卖出RAM需要用到另外一个方法 sellram

eosconfig = {
    httpEndpoint: "http://jungle.cryptolions.io:18888",
    chainId: "038f4b0fc8ff18a4f0842a8f0564611f6e96e8535901dd45e43ac8691a1c4dca", // 32 byte (64 char) hex string
    keyProvider: ["5HqCj7sg4K2xZ1KD5sSH38kuJkKGqfE1wSGiLL3M599ajacVmTs"],
    expireInSeconds: 60,
    broadcast: true,
    verbose: false, // API activity
    sign: true
},    eos = Eos(eosconfig)eos.getTableRows(true, "eosio", "eosio", "rammarket").then(ramData => {
    console.log(ramData)
    //RAM消耗的EOS数量
    let eosAmount = ramData.rows[0].quote.balance.split(" ")[0];
    //RAM使用量
    let ramAmount = ramData.rows[0].base.balance.split(" ")[0] / 1024;
    //RAM价格
    let ramPriceWithEOS = eosAmount / ramAmount
    console.log(eosAmount, ramAmount, ramPriceWithEOS);
})let account = "lixutest1111"
let ramAmount = 8*1024
async function sellRAM() {
    result = await eos.transaction(tr => {
        tr.sellram({
            account: account,
            bytes: ramAmount
        })
    })
    console.log(result)
}
sellRAM()

运行后看到价格是0.0757692783033557 EOS/KB,确实与上一次获取到的价格有点偏差。

6E4A29E6-5782-4632-8D14-65287FD5775D

这里就不花时间作计算了,大家可以在根据价格与出售量计算在做比较。重新查看账号“lixutest1111”的EOS数量多了0.6,RAM内存减少了8KB。

88594B86-16C7-46F6-A2D6-4104CA9E36EA

五、项目源码

1. controllers/netResource.js

在controllers文件夹下新建netResource.js文件,实现获取全局RAM数据与买入卖出RAM的功能。

let { success, fail } = require("../utils/myUtils")
let myUtils = require("../utils/myUtils")
let walletModel = require("../models/wallet")async function getRamInfo() {
    ramData = await eos.getTableRows(true, "eosio", "eosio", "rammarket")
    //RAM消耗的EOS数量
    let eosAmount = ramData.rows[0].quote.balance.split(" ")[0];
    //RAM使用量
    let ramAmount = ramData.rows[0].base.balance.split(" ")[0] / 1024;
    //RAM价格
    let ramPriceWithEOS = eosAmount / ramAmount
    console.log(eosAmount, ramAmount, ramPriceWithEOS);
    return {
        ramUsed: ramAmount / (1024 * 1024),
        ramPrice: ramPriceWithEOS,
    }
}module.exports = {
    netResourceGetRAMInfo: async (ctx) => {
        console.log(ctx.request.body)
        let { wallet, password } = ctx.request.body
        //获取钱包里面所有的私钥配置EOSJS
        let privatekeyList = await walletModel.getWalletPrivatekeyList(wallet, password)
        eos = myUtils.getEOSJS(privatekeyList)        let ramData = await eos.getTableRows(true, "eosio", "eosio", "global")
        //ram总量,bytes转为G
        let ramTotal = ramData.rows[0].max_ram_size / (1024 * 1024 * 1024)
        console.log(ramTotal);        let ramInfo = await getRamInfo()
        ctx.body = success({
            ramPrice: ramInfo.ramPrice,
            ramTotal: ramTotal,
            ramAvailable: ramTotal - ramInfo.ramUsed,
        })
    },    netResourceTransactionRAM: async (ctx) => {
        console.log(ctx.request.body)
        let { amount, transaction_type, account, wallet, password } = ctx.request.body
        //获取钱包里面所有的私钥配置EOSJS
        let privatekeyList = await walletModel.getWalletPrivatekeyList(wallet, password)
        eos = myUtils.getEOSJS(privatekeyList)        let result
        if (transaction_type == '1') {
            //买RAM
            console.log("买RAM")
            let ramInfo = await getRamInfo()
            let ramAmount = parseInt((amount / ramInfo.ramPrice) * 1024)
            console.log("ramAmount:", ramAmount)
            result = await eos.transaction(tr => {
                tr.buyrambytes({
                    payer: account,
                    receiver: account,
                    bytes: ramAmount
                })
            })
        } else {
            //卖RAM
            console.log("卖RAM")
            let ramAmount = parseInt(amount*1024)
            result = await eos.transaction(tr => {
                tr.sellram({
                    account: account,
                    bytes: ramAmount 
                })
            })
        }        console.log("data:", result)
        if (result.broadcast) {
            ctx.body = success("ok")
        } else {
            ctx.body = fail("error")
        }
    }}

2. router/router.js

将获取全局RAM数据与买入卖出RAM的接口绑定到路由。

......
let netresourceController = require("../controllers/netResource")//网络资源
router.post("/net_resource/ram/info", netresourceController.netResourceGetRAMInfo)
router.post("/net_resource/ram/transaction", netresourceController.netResourceTransactionRAM)

3. views/netResource.html

编辑views文件夹下的netResource.html文件,实现RAM交易的表单显示。

......<div class="interactive">
    <form id="ram-transaction">
        <input type="radio" id="ram-transaction-buy" name="transaction_type" value="1" checked="checked">
        <label for="ram-transaction-buy">买入</label>        <input type="radio" id="ram-transaction-sell" name="transaction_type" value="2"  checked>
        <label for="ram-transaction-sell">卖出</label>
        <br>        <div>全网内存:<span id="ram-total"></span></div>
        <div>内存价格:<span id="ram-price"></span> EOS/KB</div>        <label>数量:</label>
        <input type="text" name="amount" placeholder="请输入EOS数量"><br>        <input type="text" name="account" hidden="hidden">
        <input type="text" name="wallet" hidden="hidden">
        <input type="text" name="password" hidden="hidden">
        <button type="submit" id="ram-transaction-button">买入</button>
    </form>
</div>......

4. static/js/netResource.js

对全局RAM数据与买入卖出RAM的表单进行网络请求处理与页面渲染。

$(document).ready(function () {
    ......    $("input[name=account][hidden=hidden]").val(currentAccount)
    let currentwallet = localStorage.getItem("currentwallet")
    let walletPassword = localStorage.getItem(currentwallet)
    $("input[name=wallet][hidden=hidden]").val(currentwallet)
    $("input[name=password][hidden=hidden]").val(walletPassword)    $("input[name=transaction_type]").change(function () {
        if (this.value == 1) {
            $("#ram-transaction-button").text("买入")
            $("input[name=amount]").attr({"placeholder":"请输入EOS数量"})
        } else {
            $("#ram-transaction-button").text("卖出")
            $("input[name=amount]").attr({"placeholder":"请输入RAM(KB)数量"})        }
    })    //ram全局数据
    $.post("/net_resource/ram/info", { "account": currentAccount }, function (res, status) {
        console.log(status + JSON.stringify(res))
        if (res.code == 0) {
            $("#ram-total").text(res.data.ramAvailable.toFixed(2) + " GB / " + res.data.ramTotal.toFixed(2) + "GB")
            $("#ram-price").text(res.data.ramPrice.toFixed(6))
        }
    })    //交易RAM
    $("#ram-transaction").validate({
        rules: {
            amount: {required: true,},
        },
        messages: {
            name: {required: "请输入要交易的数量",},
        },
        submitHandler: function (form) {
            $(form).ajaxSubmit({
                url: "/net_resource/ram/transaction",
                type: "post",
                dataType: "json",
                success: function (res, status) {
                    console.log(status + JSON.stringify(res))
                    if (res.code == 0) {
                        alert("交易成功")
                        location.reload() 
                    } else {
                        alert("交易失败")
                    }
                },
                error: function (res, status) {
                    console.log(status + JSON.stringify(res))
                    alert(res.data)
                }
            });
        }
    })
})

六、项目效果

504E68A9-7F20-4789-9668-58154FA21490

项目源码Github地址

版权声明:博客中的文章版权归博主所有,未经授权禁止转载,转载请联系作者(微信:lixu1770105)取得同意并注明出处。

未经授权禁止转载、改编,转载请注明出处!

免责声明:
本网站所提供的所有信息仅供参考,不构成任何投资建议。用户在使用本网站的信息时应自行判断和承担风险。币界网不对用户因使用本网站信息而导致的任何损失负责。用户在进行任何投资活动前应自行进行调查和研究,并谨慎决策。币界网不对用户基于本网站信息做出的任何投资决策负责。用户在本网站发布的任何内容均由其个人负责,与币界网无关。
免责声明:本网站、超链接、相关应用程序、论坛、博客等媒体账户以及其他平台和用户发布的所有内容均来源于第三方平台及平台用户。币界网对于网站及其内容不作任何类型的保证,网站所有区块链相关数据以及其他内容资料仅供用户学习及研究之用,不构成任何投资、法律等其他领域的建议和依据。币界网用户以及其他第三方平台在本网站发布的任何内容均由其个人负责,与币界网无关。币界网不对任何因使用本网站信息而导致的任何损失负责。您需谨慎使用相关数据及内容,并自行承担所带来的一切风险。强烈建议您独自对内容进行研究、审查、分析和验证。
s_logo
App内打开