第十八課 【ERC875】Hiblock黑客馬拉松門票從定制到編碼實(shí)現(xiàn)

1槽地,摘要

【本文目標(biāo)】
通過本文,可以從一個(gè)HiBlock黑客馬拉松活動(dòng)門票定制并鸵,轉(zhuǎn)讓鸳粉,出售和簽到為例,說明ERC875的設(shè)計(jì)初心园担,ERC875的標(biāo)準(zhǔn)接口分析届谈,也給出了官網(wǎng)的ERC875的代碼和本地測(cè)試枯夜,便于更多項(xiàng)目使用ERC875解決區(qū)塊鏈業(yè)務(wù)中遇到的實(shí)際問題。
【前置條件】
(1)體驗(yàn)門票受讓的用戶不需要有任何技術(shù)門檻艰山;
(2)做門票定制和開發(fā)的需要本地已安裝好MetaMASK湖雹,在Reposton Test Net獲取了幾個(gè)測(cè)試ETH(免費(fèi))的,要懂Solidity語言曙搬。
不熟悉的建議參考文檔《第六課 技術(shù)小白如何開發(fā)一個(gè)DAPP區(qū)塊鏈應(yīng)用(以寵物商店為例)》的“5. 安裝 MetaMask和配置區(qū)塊鏈網(wǎng)絡(luò)”章節(jié)摔吏。

2,Hiblock黑客馬拉松區(qū)塊鏈門票全體驗(yàn)

2.1 門票定制創(chuàng)建 - [輝哥]

ALPHA WALLET團(tuán)隊(duì)已經(jīng)封裝好了ERC785協(xié)議實(shí)現(xiàn)纵装,可以通過瀏覽器完成票務(wù)類ERC875的智能合約創(chuàng)建征讲。對(duì)應(yīng)的TOKEN工廠網(wǎng)址為https://alpha-wallet.github.io/ERC875-token-factory/index.html
測(cè)試使用,MetaMASK選擇的測(cè)試網(wǎng)絡(luò)為"Ropsten Test Net"橡娄。

1) “Deploy Contract”
定義名稱和標(biāo)識(shí)诗箍,對(duì)應(yīng)的地址是以太坊錢包地址。Owner Address必須為MetaMast的當(dāng)前賬號(hào)地址挽唉,然后點(diǎn)擊“Deploy Contract”按鈕滤祖。[名稱和標(biāo)識(shí)命名跟一般使用的搞反了,將就用吧]
Contract Name: HHT
Ticket Symbol: Hiblock Hackathon Ticket
Owner Address:0xB51Fa936B744CFEbAeD8DbB79d2060903e689F89
Recipient Address:0xB51Fa936B744CFEbAeD8DbB79d2060903e689F89

1. 提交合約部署

2)“Submmit”按鈕
“Gas Price”設(shè)置為30橱夭,點(diǎn)擊“Submmit”按鈕氨距。該賬號(hào)要有一定的ETH測(cè)試幣,否則點(diǎn)擊"Buy"找平臺(tái)免費(fèi)買點(diǎn)棘劣。

2. 確認(rèn)交易

3)購買成功確認(rèn)
購買成功的會(huì)有彈出提示俏让。點(diǎn)擊“確定”按鈕后,拉到下方的按鈕可以查看智能合約部署鏈接和ABI合約信息茬暇。

3.合約部署成功
4. 查看ABI信息和合約記錄

4)查看部署合約成功地址
點(diǎn)擊可知其部署成功:https://ropsten.etherscan.io/address/0x07fc44d796d30b317013cb907fadb6d738f5779e

2.2 安裝APP首昔,導(dǎo)入錢包,導(dǎo)入門票 - [輝哥]

1) 安裝APP
輝哥在官網(wǎng)(https://awallet.io/)下載APP完成安裝糙俗。

2) 導(dǎo)入錢包
點(diǎn)擊配置頁面勒奇,更換網(wǎng)絡(luò)為"Ropsten(Test)"網(wǎng)絡(luò),導(dǎo)入創(chuàng)建門票的錢包私鑰巧骚。

3)添加代幣
輸入之前的智能合約地址赊颠,符號(hào)和名稱會(huì)自動(dòng)聯(lián)想出來的。

導(dǎo)入成功后劈彪,錢包頁面可以看到對(duì)應(yīng)的通證信息竣蹦。如果是沒有這個(gè)資產(chǎn)的錢包導(dǎo)入這個(gè)通證,錢包頁面是看不到這個(gè)通證門票的沧奴。


2.3 轉(zhuǎn)讓門票 - [輝哥-歐陽哥哥]

通過報(bào)名渠道痘括,輝哥知道歐陽哥哥已報(bào)名參加HiBlock黑客馬拉松,所以把區(qū)塊鏈門票轉(zhuǎn)給他。
1) 輝哥點(diǎn)擊“轉(zhuǎn)讓”按鈕
選擇HHT后纲菌,點(diǎn)擊右下角的“轉(zhuǎn)讓”按鈕進(jìn)行票務(wù)轉(zhuǎn)讓挠日。

2)點(diǎn)擊“轉(zhuǎn)讓”按鈕
選擇“現(xiàn)在直接轉(zhuǎn)讓門票”,

獲取歐陽哥哥的錢包地址翰舌,輸入:


輸入歐陽哥哥的錢包地址

3)確認(rèn)轉(zhuǎn)讓

轉(zhuǎn)讓門票按鈕

轉(zhuǎn)賬成功

2.4 出售門票 - [歐陽哥哥-小輝]

1)導(dǎo)入通證
歐陽哥哥在AlphaWallet錢包中輸入HHT的合約地址(0x07fc44d796d30b317013cb907fadb6d738f5779e)即可查看到輝哥轉(zhuǎn)賬過來的門票通證嚣潜。

2) 出售門票
小輝同學(xué)知道了黑客馬拉松的事情,也很想?yún)⒓釉钪ァW陽哥哥剛好弄了2張票郑原,就同意把一張票低價(jià)轉(zhuǎn)讓給小輝。雙方協(xié)商好價(jià)格是0.2個(gè)ETH夜涕。
歐陽哥哥點(diǎn)擊出售按鈕,設(shè)置好價(jià)格属愤,最后鏈接通過微信發(fā)給小輝女器。

設(shè)置價(jià)格

設(shè)置截止時(shí)間
確認(rèn)出售,把鏈接微信發(fā)給小輝

3) 導(dǎo)入支付
小輝安裝好APP住诸。復(fù)制鏈接打開APP時(shí)驾胆,會(huì)提示導(dǎo)入門票。點(diǎn)擊購買贱呐,支付了0.2個(gè)ETH后即可完成支付丧诺。

門票
確認(rèn)購買
購買成功

4) 導(dǎo)入代幣地址完成呈現(xiàn)
小輝在錢包導(dǎo)入HHT智能合約的地址(0x07fc44d796d30b317013cb907fadb6d738f5779e)后,即可在APP上呈現(xiàn)購買的HHT門票一張奄薇。

2.5 兌現(xiàn)門票

歐陽哥哥和小輝到達(dá)HiBlock黑客馬拉松現(xiàn)場(chǎng)驳阎,點(diǎn)擊門票的“兌換”按鈕,主辦方Bob根據(jù)他們展示的二維碼掃描完成馁蒂。該門票的狀態(tài)會(huì)變更為已兌換呵晚。

【后記】他們組隊(duì)參加黑客馬拉松,依靠其過硬的技術(shù)實(shí)力沫屡,獲得了一個(gè)二等獎(jiǎng)饵隙!

3,ERC875設(shè)計(jì)目標(biāo)

AlphaWallet團(tuán)隊(duì)核心成員(左二:CEO張中南沮脖;右二:創(chuàng)始人兼CTO張韡武)

ERC875協(xié)議是由AlphaWallet團(tuán)隊(duì)提出的金矛,他們希望基于ERC875協(xié)議族,能夠?qū)崿F(xiàn)人勺届、事驶俊、物、權(quán)token化涮因。

在創(chuàng)始人張中南看來废睦,人、事养泡、物嗜湃、權(quán)全部token化奈应,即可以用token來替代物理世界里面的任何商品。在此其中购披,token替代的是一個(gè)權(quán)益杖挣,可以指代各種各樣的權(quán)益。比如刚陡,「人」的token化惩妇,「跟吳亦凡今天晚上6點(diǎn)鐘到8點(diǎn)鐘一起吃飯的權(quán)益,可以做成一個(gè)token」筐乳,「事」的token化歌殃,「用信用卡在商店買了一瓶水,也可以做成一個(gè)token」蝙云,而「物」氓皱、「權(quán)」的token化,就更好理解了勃刨。
將人波材、事、物身隐、權(quán)token化廷区,可以有不同層級(jí)的愿景和意義。張中南介紹:
第一層級(jí)贾铝,簡(jiǎn)單的來說隙轻,就是把 人、事忌傻、物大脉、權(quán)做成token,放到區(qū)塊鏈上面流通水孩,或者說放到錢包里镰矿,做成APP,能夠使用token做流轉(zhuǎn)俘种。
再往上一個(gè)級(jí)別秤标,是這些token和token之間的交互。比如宙刘,可能有一件事苍姜,可以同時(shí)調(diào)用7、8個(gè)token悬包,不再是簡(jiǎn)單的轉(zhuǎn)讓或流通衙猪。
再往上一個(gè)級(jí)別,「我們能夠看到最遠(yuǎn)的地方就是這些token用來指代人、事垫释、物丝格、權(quán)之后,它們本身可以變成一個(gè)集成點(diǎn)棵譬,可以在用戶端集成各種各樣的服務(wù)和應(yīng)用显蝌。比如,租車服務(wù)订咸、保險(xiǎn)曼尊、信用卡公司等,當(dāng)需要調(diào)用他們的服務(wù)時(shí)脏嚷,不再通過微信來使用骆撇,而是直接在用戶端就能集成。
現(xiàn)階段父叙,為了實(shí)現(xiàn)初級(jí)目標(biāo)艾船,AlphaWallet選擇從一款可編程錢包切入。今年5月23日高每,該公司正式發(fā)布了這款籌備已久的錢包產(chǎn)品——AlphaWallet 1.0版。
公開資料顯示践宴,這是一款直接支持不可替代性token的錢包鲸匿,可作為連接虛擬世界和真實(shí)世界的網(wǎng)關(guān)∽杓纾基于該錢包之上带欢,真實(shí)世界內(nèi)的生活服務(wù)可利用區(qū)塊鏈技術(shù)而具備強(qiáng)有力的基礎(chǔ)技術(shù)平臺(tái),從而擁有無限想象的可能性烤惊。
通常來說乔煞,大量token廣泛使用的是ERC20協(xié)議。遵循ERC20的token可以跟蹤任何人在任何時(shí)候擁有多少token柒室。在一些開源組織的推動(dòng)下渡贾,目前第三方基于ERC20接口5分鐘即能發(fā)行一個(gè)ERC20的token。不過雄右,相對(duì)來說空骚,ERC20還存在兩個(gè)問題:
第一,ERC20無法代表現(xiàn)實(shí)世界中無法拆分擂仍、獨(dú)一無二的資產(chǎn)囤屹;
第二,現(xiàn)有的打包逢渔、轉(zhuǎn)賬流程復(fù)雜肋坚,ERC20缺乏可擴(kuò)展性,無法實(shí)現(xiàn)更復(fù)雜的功能。
基于此智厌,AlphaWallet自主開發(fā)了ERC875協(xié)議族诲泌。該協(xié)議不僅會(huì)讓數(shù)字資產(chǎn)變得具有收藏價(jià)值,同時(shí)也能幫助現(xiàn)實(shí)世界中不可拆分替代峦剔、具有物權(quán)唯一性的資產(chǎn)上鏈档礁,這就能為線下服務(wù)的鏈上操作提供了可能性。
雖然另一種協(xié)議ERC721也能實(shí)現(xiàn)token的不可置換性吝沫,但其存在需要交易雙方支付gas費(fèi)用呻澜、無法簡(jiǎn)單實(shí)現(xiàn)原子化交易等一些不易于用戶使用的問題。
張中南向雷鋒網(wǎng)AI金融評(píng)論介紹稱惨险,ERC875內(nèi)置了兩個(gè)密碼學(xué)協(xié)議羹幸, 一方面能夠簡(jiǎn)單實(shí)現(xiàn)原子化交易(atomic swap)——直接搭建去中心化市場(chǎng)、降低普通用戶使用門檻辫愉,賣家無需持有以太幣栅受,買家支付一次gas即能完成;另外一方面可以簡(jiǎn)單打包處理大量交易恭朗。
拿基于ERC721的加密貓來說屏镊,換用ERC875協(xié)議的話,能夠?qū)崿F(xiàn)痰腮。用戶在商家網(wǎng)站法幣購貓而芥,通過MagicLink免費(fèi)把貓導(dǎo)入用戶的錢包,之后用戶還可以在不需要持有以太幣的情況下膀值,通過MagicLink把貓售出或者免費(fèi)轉(zhuǎn)讓棍丐,全部過程都是無中心的原子化交易。另外商家可以一次批發(fā)100只貓給分銷商沧踏。

首個(gè)落地應(yīng)用:體育票務(wù)
或許與張中南在票務(wù)業(yè)務(wù)的經(jīng)歷有關(guān)歌逢,AlphaWallet選擇從ERC875和錢包切入的第一個(gè)use case就是俄羅斯世界杯門票。
相較人翘狱、事而言秘案,「票務(wù)」由于具備物理和權(quán)益屬性,利用區(qū)塊鏈技術(shù)來實(shí)現(xiàn)不可置換的token的流轉(zhuǎn)盒蟆,更具操作性和可行性踏烙。
目前 AlphaWallet 已與盛開體育達(dá)成合作。今年的俄羅斯世界杯历等,二者聯(lián)合引入?yún)^(qū)塊鏈技術(shù)以測(cè)試新的票務(wù)解決方案讨惩,將盛開體育世界杯票庫內(nèi)的部分門票轉(zhuǎn)化為以太坊上的ERC875的token。由于這些token具有不可置換性寒屯,用戶通過AlphaWallet錢包的動(dòng)態(tài)二維碼荐捻,以及線下的現(xiàn)場(chǎng)掃描黍少,即可獲得世界杯門票〈γ妫考慮到進(jìn)一步安全的問題厂置,AlphaWallet錢包顯示的動(dòng)態(tài)二維碼,每隔10s就會(huì)變一次魂角。

AlphaWallet錢包兌換俄羅斯世界杯門票(test)流程體驗(yàn)

據(jù)張中南介紹昵济,這次合作,「盛開那邊做了10張票野揪,AlphaWallet則拿了10張開幕式的VIP門票访忿,所以一共只有20張門票」。經(jīng)過雷鋒網(wǎng)AI金融評(píng)論現(xiàn)場(chǎng)測(cè)試體驗(yàn)斯稳,通過AlphaWallet錢包流轉(zhuǎn)一張世界杯門票海铆,所花時(shí)間在4-7s以內(nèi)。而買方從賣方手里通過支付以太坊的方式買入一張門票挣惰,所需時(shí)間則在10s左右卧斟。
「這應(yīng)該是目前世界上首個(gè)不可替代通證與現(xiàn)實(shí)物權(quán)交互的落地案例≡髅」團(tuán)隊(duì)向雷鋒網(wǎng)AI金融評(píng)論表示珍语。
除票務(wù)外,AlphaWallet近期還會(huì)繼續(xù)考慮在「物」上面開發(fā)use case竖幔,主要專注在物理商品這一塊廊酣,如 奢侈手表和限量球鞋等等。
不過赏枚,也有業(yè)內(nèi)人士指出,通過不可置換協(xié)議晓猛,從token到實(shí)物的映射饿幅,可能還是難以避免實(shí)物造假的情況,這點(diǎn)又該如何防范戒职?在張中南看來栗恩,給物理商品配備數(shù)字身份證,是通過經(jīng)濟(jì)學(xué)原理來實(shí)現(xiàn)防偽的洪燥。這點(diǎn)與溯源磕秤、防偽等又不一樣。

4捧韵,ERC875標(biāo)準(zhǔn)

function name() constant returns (string name)

返回智能合約的名字市咆,例如CarLotContract。

function symbol() constant returns (string symbol)

返回智能合約通證的標(biāo)識(shí)符再来。

function balanceOf(address _owner) public view returns (uint256[] balance)

返回一組賬戶余額的數(shù)組蒙兰。

function transfer(address _to, uint256[] _tokens) public;

通過包含通證索引的數(shù)組參數(shù),把一組獨(dú)一無二的通證轉(zhuǎn)移給一個(gè)賬戶地址。相比ERC721一次只能轉(zhuǎn)賬一個(gè)通證威根,ERC875更顯友好瓶竭,它可以一次批量轉(zhuǎn)賬一組通證。這樣既便利又能節(jié)約大量的GAS消耗挠他。

function transferFrom(address _from, address _to, uint256[] _tokens) public;

從一個(gè)賬戶給另一個(gè)賬戶轉(zhuǎn)賬批量通證扳抽。這個(gè)可由一個(gè)獲得特定KEY例如合同創(chuàng)建者的授權(quán)的賬號(hào)來完成。

【以下為可選函數(shù)】

function totalSupply() constant returns (uint256 totalSupply);

返回給定合同的通證總數(shù)殖侵。這個(gè)通證總數(shù)可能是可變的贸呢。

function ownerOf(uint256 _tokenId) public view returns (address _owner);

返回特定通證的擁有者。這個(gè)函數(shù)是可選的愉耙,因?yàn)椴⒉皇敲恳粋€(gè)通證合約都需要跟蹤每一個(gè)獨(dú)一無二通知的擁有者贮尉,并且每次查詢需要消耗GAS用于遍歷和匹配token id于擁有者的關(guān)系。

function trade(uint256 expiryTimeStamp, uint256[] tokenIndices, uint8 v, bytes32 r, bytes32 s) public payable

該函數(shù)允許用戶出售一組非同質(zhì)通證而不需要支付GAS費(fèi)朴沿,只需要購買者支付猜谚。這是通過簽署包含要銷售的代幣數(shù)量,合同地址赌渣,到期時(shí)間戳魏铅,價(jià)格和包含ERC規(guī)范名稱和鏈ID的前綴的證明來實(shí)現(xiàn)的。然后坚芜,買方可以通過附加適當(dāng)?shù)囊蕴珟牛╡ther)來滿足交易览芳,從而在一次交易中支付交易。
這種設(shè)計(jì)也更有效鸿竖,因?yàn)樗试S訂單在離線前完成沧竟,而不是在智能合約中創(chuàng)建訂單并更新訂單。到期時(shí)間戳保護(hù)賣方免受使用舊訂單的人的影響缚忧。
這為點(diǎn)對(duì)點(diǎn)(p2p)原子交換(atomic swap)打開了大門悟泵,但對(duì)于這個(gè)標(biāo)準(zhǔn)應(yīng)該是可選的,因?yàn)橛行┛赡軟]有用它闪水。
需要在消息中添加一些保護(hù)糕非,例如編碼鏈ID,合同地址和ERC規(guī)范名稱球榆,以防止重放和欺騙人們簽署允許交易的消息朽肥。

5,ERC875樣例代碼

官方給出的ERC875代碼樣例如下持钉,函數(shù)含義參考第4章衡招。

contract ERC
{
  event Transfer(address indexed _from, address indexed _to, uint256[] tokenIndices);
 
  function name() constant public returns (string name);
  function symbol() constant public returns (string symbol);
  function balanceOf(address _owner) public view returns (uint256[] _balances);
  //function ownerOf(uint256 _tokenId) public view returns (address _owner);
  function transfer(address _to, uint256[] _tokens) public;
  function transferFrom(address _from, address _to, uint256[] _tokens) public;
 
  //optional
  //function totalSupply() public constant returns (uint256 totalSupply);
  function trade(uint256 expiryTimeStamp, uint256[] tokenIndices, uint8 v, bytes32 r, bytes32 s) public payable;
}

pragma solidity ^0.4.17;
contract Token is ERC
{
    uint totalTickets;
    mapping(address => uint256[]) inventory;
    uint16 ticketIndex = 0; //to track mapping in tickets
    uint expiryTimeStamp;
    address owner;   // the address that calls selfdestruct() and takes fees
    address admin;
    uint transferFee;
    uint numOfTransfers = 0;
    string public name;
    string public symbol;
    uint8 public constant decimals = 0; //no decimals as tickets cannot be split

    event Transfer(address indexed _from, address indexed _to, uint256[] tokenIndices);
    event TransferFrom(address indexed _from, address indexed _to, uint _value);
    
    modifier adminOnly()
    {
        if(msg.sender != admin) revert();
        else _;
    }

    function() public { revert(); } //should not send any ether directly

    // example: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15], "MJ comeback", 1603152000, "MJC", "0x007bEe82BDd9e866b2bd114780a47f2261C684E3"
    function Token(
        uint256[] numberOfTokens,
        string evName,
        uint expiry,
        string eventSymbol,
        address adminAddr) public
    {
        totalTickets = numberOfTokens.length;
        //assign some tickets to event admin
        expiryTimeStamp = expiry;
        owner = msg.sender;
        admin = adminAddr;
        inventory[admin] = numberOfTokens;
        symbol = eventSymbol;
        name = evName;
    }

    function getDecimals() public pure returns(uint)
    {
        return decimals;
    }
    
    // price is 1 in the example and the contract address is 0xfFAB5Ce7C012bc942F5CA0cd42c3C2e1AE5F0005
    // example: 0, [3, 4], 27, "0x2C011885E2D8FF02F813A4CB83EC51E1BFD5A7848B3B3400AE746FB08ADCFBFB", "0x21E80BAD65535DA1D692B4CEE3E740CD3282CCDC0174D4CF1E2F70483A6F4EB2"
    // price is encoded in the server and the msg.value is added to the message digest,
    // if the message digest is thus invalid then either the price or something else in the message is invalid
    function trade(uint256 expiry,
                   uint256[] tokenIndices,
                   uint8 v,
                   bytes32 r,
                   bytes32 s) public payable
    {
        //checks expiry timestamp,
        //if fake timestamp is added then message verification will fail
        require(expiry > block.timestamp || expiry == 0);
        //id 1 for mainnet
        bytes12 prefix = "ERC800-CNID1";
        bytes32 message = encodeMessage(prefix, msg.value, expiry, tokenIndices);
        address seller = ecrecover(message, v, r, s);
        
        for(uint i = 0; i < tokenIndices.length; i++)
        { // transfer each individual tickets in the ask order
            uint index = uint(tokenIndices[i]);
            require((inventory[seller][index] > 0)); // 0 means ticket sold.
            inventory[msg.sender].push(inventory[seller][index]);
            inventory[seller][index] = 0; // 0 means ticket sold.
        }
        seller.transfer(msg.value);
    }


    //must also sign in the contractAddress
    //prefix must contain ERC and chain id
    function encodeMessage(bytes12 prefix, uint value, 
        uint expiry, uint256[] tokenIndices)
        internal view returns (bytes32)
    {
        bytes memory message = new bytes(96 + tokenIndices.length * 2);
        address contractAddress = getContractAddress();
        for (uint i = 0; i < 32; i++)
        {   // convert bytes32 to bytes[32]
            // this adds the price to the message
            message[i] = byte(bytes32(value << (8 * i)));
        }

        for (i = 0; i < 32; i++)
        {
            message[i + 32] = byte(bytes32(expiry << (8 * i)));
        }
        
        for(i = 0; i < 12; i++)
        {
            message[i + 64] = byte(prefix << (8 * i));    
        }

        for(i = 0; i < 20; i++)
        {
            message[76 + i] = byte(bytes20(bytes20(contractAddress) << (8 * i)));
        }

        for (i = 0; i < tokenIndices.length; i++)
        {
            // convert int[] to bytes
            message[96 + i * 2 ] = byte(tokenIndices[i] >> 8);
            message[96 + i * 2 + 1] = byte(tokenIndices[i]);
        }

        return keccak256(message);
    }

    function name() public view returns(string)
    {
        return name;
    }

    function symbol() public view returns(string)
    {
        return symbol;
    }

    function getAmountTransferred() public view returns (uint)
    {
        return numOfTransfers;
    }

    function isContractExpired() public view returns (bool)
    {
        if(block.timestamp > expiryTimeStamp)
        {
            return true;
        }
        else return false;
    }

    function balanceOf(address _owner) public view returns (uint256[])
    {
        return inventory[_owner];
    }

    function myBalance() public view returns(uint256[])
    {
        return inventory[msg.sender];
    }

    function transfer(address _to, uint256[] tokenIndices) public
    {
        for(uint i = 0; i < tokenIndices.length; i++)
        {
            require(inventory[msg.sender][i] != 0);
            //pushes each element with ordering
            uint index = uint(tokenIndices[i]);
            inventory[_to].push(inventory[msg.sender][index]);
            inventory[msg.sender][index] = 0;
        }
    }

    function transferFrom(address _from, address _to, uint256[] tokenIndices)
        adminOnly public
    {
        bool isadmin = msg.sender == admin;
        for(uint i = 0; i < tokenIndices.length; i++)
        {
            require(inventory[_from][i] != 0 || isadmin);
            //pushes each element with ordering
            uint index = uint(tokenIndices[i]);
            inventory[_to].push(inventory[msg.sender][index]);
            inventory[_from][index] = 0;
        }
    }

    function endContract() public
    {
        if(msg.sender == owner)
        {
            selfdestruct(owner);
        }
        else revert();
    }

    function getContractAddress() public view returns(address)
    {
        return this;
    }
}

【函數(shù)說明】
1,trade函數(shù)是發(fā)起批量轉(zhuǎn)讓的智能合約函數(shù)
trade(uint256 expiry,/超時(shí)時(shí)間每强,以s計(jì)算/
uint256[] tokenIndices, /通證索引/
uint8 v, /*v,r,s是賣家簽名的3個(gè)部分蚁吝,產(chǎn)生的方法參考文件 */
bytes32 r,
bytes32 s )

6旱爆,ERC875測(cè)試(REMIX+MetaMASK環(huán)境)

6.1 創(chuàng)建合約

[1] 管理員(0xca35b7d915458ef540ade6068dfe2f44e8fa733c)構(gòu)建函數(shù)CREATE

 [101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115], "DJ Family", 1603152000, "DJ", "0xca35b7d915458ef540ade6068dfe2f44e8fa733c"

【結(jié)果】
智能合約創(chuàng)建成功,得到智能合約地址:0x692a70d2e424a56d2c6c27aa97d1a86395877b3a

6.2 門票轉(zhuǎn)讓

管理員(0xca35b7d915458ef540ade6068dfe2f44e8fa733c)轉(zhuǎn)移2張座位號(hào)為101,102的門票給李四(0x4b0897b0513fdc7c541b6d9d7e929c4e5364d2db)

transfer("0x4b0897b0513fdc7c541b6d9d7e929c4e5364d2db", [0,1])

*【結(jié)果】:門票已轉(zhuǎn)讓給李四,李四并沒有消耗GAS窘茁,是管理員消耗了GAS怀伦。

6.3 trade門票

管理員(0xca35b7d915458ef540ade6068dfe2f44e8fa733c)把門票trade給趙六(0xdd870fa1b7c4700f2bd7f44238821c26f7392148)
當(dāng)智能合約地址為0xfFAB5Ce7C012bc942F5CA0cd42c3C2e1AE5F0005,price is 1時(shí)山林,

trade(0, [3, 4], 27, "0x2C011885E2D8FF02F813A4CB83EC51E1BFD5A7848B3B3400AE746FB08ADCFBFB", "0x21E80BAD65535DA1D692B4CEE3E740CD3282CCDC0174D4CF1E2F70483A6F4EB2")

【結(jié)果】操作失敗了房待,也無法觸發(fā)購買。
【官方答復(fù)】
那個(gè)Trade function的功能是驼抹,在賣家發(fā)了簽名信息給買家桑孩,然后買家聯(lián)合賣家的簽名信息和自己的簽名信息一起call trade fundction來完成交易。你在現(xiàn)在的模式框冀,是創(chuàng)建不出來賣家簽名信息的流椒, 你需要參考AlphaWallet的代碼。
源碼參考地址:
https://github.com/alpha-wallet/AlphaWallet-Mobile-Apps
【詳細(xì)說明】
(1) START TO TRANSFER:
transferTicketDetailVeiwModel.java - CreateTicketTransfer
(2) HOW TO BUY A TICKET
ImportTokenViewModel.java - PerformImport

7 參考

1) 2018世界杯門票的一筆交易記錄
2) 深入淺出以太坊ERC875標(biāo)準(zhǔn)(不可替代性通證標(biāo)準(zhǔn))
3) AlphaWallet野心有點(diǎn)大:基于ERC875協(xié)議族明也,實(shí)現(xiàn)人宣虾、事、物温数、權(quán)token化
4)ERC875 for non fungible tokens and simple atomic swaps
5) AlphaWallet代碼
6) ERC875智能合約案例 (TradeImplementationExample.java 和ERCTokenImplementation.sol)
7) AlphaWallet錢包下載-支持測(cè)試網(wǎng)絡(luò)代幣

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末绣硝,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子撑刺,更是在濱河造成了極大的恐慌鹉胖,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,454評(píng)論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件够傍,死亡現(xiàn)場(chǎng)離奇詭異甫菠,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)冕屯,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,553評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門淑蔚,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人愕撰,你說我怎么就攤上這事〈浊蓿” “怎么了搞挣?”我有些...
    開封第一講書人閱讀 157,921評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)音羞。 經(jīng)常有香客問我囱桨,道長(zhǎng),這世上最難降的妖魔是什么嗅绰? 我笑而不...
    開封第一講書人閱讀 56,648評(píng)論 1 284
  • 正文 為了忘掉前任舍肠,我火速辦了婚禮搀继,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘翠语。我一直安慰自己叽躯,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,770評(píng)論 6 386
  • 文/花漫 我一把揭開白布肌括。 她就那樣靜靜地躺著点骑,像睡著了一般。 火紅的嫁衣襯著肌膚如雪谍夭。 梳的紋絲不亂的頭發(fā)上黑滴,一...
    開封第一講書人閱讀 49,950評(píng)論 1 291
  • 那天,我揣著相機(jī)與錄音紧索,去河邊找鬼袁辈。 笑死,一個(gè)胖子當(dāng)著我的面吹牛珠漂,可吹牛的內(nèi)容都是我干的晚缩。 我是一名探鬼主播,決...
    沈念sama閱讀 39,090評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼甘磨,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼橡羞!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起济舆,我...
    開封第一講書人閱讀 37,817評(píng)論 0 268
  • 序言:老撾萬榮一對(duì)情侶失蹤卿泽,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后滋觉,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體签夭,經(jīng)...
    沈念sama閱讀 44,275評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,592評(píng)論 2 327
  • 正文 我和宋清朗相戀三年椎侠,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了第租。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,724評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡我纪,死狀恐怖慎宾,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情浅悉,我是刑警寧澤趟据,帶...
    沈念sama閱讀 34,409評(píng)論 4 333
  • 正文 年R本政府宣布,位于F島的核電站术健,受9級(jí)特大地震影響汹碱,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜荞估,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,052評(píng)論 3 316
  • 文/蒙蒙 一咳促、第九天 我趴在偏房一處隱蔽的房頂上張望稚新。 院中可真熱鬧,春花似錦跪腹、人聲如沸褂删。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,815評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽笤妙。三九已至,卻和暖如春噪裕,著一層夾襖步出監(jiān)牢的瞬間蹲盘,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,043評(píng)論 1 266
  • 我被黑心中介騙來泰國打工膳音, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留召衔,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,503評(píng)論 2 361
  • 正文 我出身青樓祭陷,卻偏偏與公主長(zhǎng)得像苍凛,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子兵志,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,627評(píng)論 2 350

推薦閱讀更多精彩內(nèi)容