如果您還沒有完成,請下載並安裝Android Studio。開啟它,第一步是建立一個新的Android Studio專案,如下所示:
選擇手機和平板電腦作為您的專案型別,然後單擊Empty Activity:
將專案命名為smartContractCall並將Language更改為Java。然後,單擊完成:
我們要做的第一件事是從AndroidManifest.xml檔案中的application標記中刪除android:allowBackup =“ true”。這很關鍵,如果我們跳過這一步,TezosJ_SDK將不起作用:
現在是時候將TezosJ_SDK新增到我們的專案中了。開啟您的build.gradle(Module: app)檔案。轉到依賴項部分,然後新增:實現‘com.milfont.tezos:tezosj_android:0.9.998’。 然後,單擊立即同步(在視窗的右上角):
關於配置,我們差不多完成了。最後一步是在同一檔案中將minSdkVersion更改為26。然後,再次同步:
全做完了! 現在我們已經準備好一切,讓我們首先構建一個Tezos錢包。 在MainActivity檔案的onCreate方法上,放置一個如下所示的宣告(不要忘記try-catch塊):
現在新增一些Logcat輸出,以檢查是否成功建立了我們的錢包。 我們將列印有關此資訊:錢包的公鑰雜湊(Tezos地址),其助記詞和當前餘額:
新增Log.i()命令後,執行該專案,您將獲得如下內容(check Logcat):
我們能夠生成一個新的錢包並得到其助記符。但是嘗試從區塊鏈獲取錢包餘額時出現錯誤。這是因為我們試圖直接透過MainActivity類訪問Internet,而在Android環境中則禁止此類。對於本教程,讓我們使用一個小的解決方法。將下面的方法放入您的MainActivity類中:
public void enableStrictMode()
{
StrictMode.ThreadPolicy policy = new
StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
}
並從onCreate方法呼叫它:
enableStrictMode();
此處使用嚴格模式僅出於說明目的。 不建議直接透過MainActivity類訪問Internet(在新執行緒中進行操作):
再次執行該專案,現在它將正常執行,並且您將能夠正確檢視Logcat上的錢包餘額:
現在我們有了一個功能正常的Tezos錢包,並且可以呼叫客戶Tezos智慧合約了。
我們將使用SmartPy.io線上IDE在Tezos區塊鏈測試網上建立並部署了我們將要使用的客戶智慧合約。檢查下面的智慧合約原始碼:
# Imports the SmartPy library.
import smartpy as sp# Defines the Customer class and its constructor.
class Customer(sp.Contract):
def __init__(self):
self.init(customers = sp.map())
# Defines the addCustomer entry point.
@sp.entry_point
def addCustomer(self, params):
# Verifies if mandatory fields have values.
sp.verify(params.id != "")
sp.verify(params.name != "")
sp.verify(params.phoneNumber > 0)
# Declare the parameter types.
sp.set_type(params.id, sp.TString)
sp.set_type(params.name, sp.TString)
sp.set_type(params.phoneNumber, sp.TNat)
sp.set_type(params.balance, sp.TMutez)
# Defines a customer record, so we can add to a Map.
customer = sp.record(name=params.name, phoneNumber=params.phoneNumber, balance=params.balance)
# Adds the new customer record to a Map (that will reside in the contract's storage).
self.data.customers[params.id] = customer
# Defines the removeCustomer entry point.
@sp.entry_point
def removeCustomer(self, params):
# Verifies if mandatory fields have values.
sp.verify(params.id != "")
# Declare the parameter types.
sp.set_type(params.id, sp.TString)
# Remove the customer from the Map.
del self.data.customers[params.id]
# Defines the updateBalance entry point.
@sp.entry_point
def updateBalance(self, params):
# Verifies if mandatory fields have values.
sp.verify(params.id != "")
# Declare the parameter types.
sp.set_type(params.id, sp.TString)
sp.set_type(params.amount, sp.TMutez)
# Updates the balance.
self.data.customers[params.id].balance = params.amount
# Defines the transfer entry point.
@sp.entry_point
def transfer(self, params):
# Verifies if mandatory fields have values.
sp.verify(params.idFrom != "")
sp.verify(params.idTo != "")
sp.verify(params.amount > sp.mutez(0) )
# Verifies if customer has enough funds to be transfered.
sp.verify(params.amount <= self.data.customers[params.idFrom].balance )
# Declare the parameter types.
sp.set_type(params.idFrom, sp.TString)
sp.set_type(params.idTo, sp.TString)
sp.set_type(params.amount, sp.TMutez)
# Updates the balance.
self.data.customers[params.idFrom].balance = self.data.customers[params.idFrom].balance - params.amount
self.data.customers[params.idTo].balance = self.data.customers[params.idTo].balance + params.amount
# Creates the test scenario, to simulate a contract call in SmartPy.io IDE.
@sp.add_test(name = "Customers")
def test():
# Instantiate a contract inherited from the Customer Class.
myCustomersContract = Customer()
# Defines a test scenario.
scenario = sp.test_scenario()
# Adds the contract to the test scenario.
scenario += myCustomersContract
# Inserts the customers, calling the contract's addCustomer entry point.
# This customers will reside in the contract's storage.
scenario += myCustomersContract.addCustomer(id="123456",name="Daniel",phoneNumber=99984537,balance=sp.mutez(0))
scenario += myCustomersContract.addCustomer(id="345678",name="Eleonor",phoneNumber=85375677,balance=sp.mutez(0))
scenario += myCustomersContract.addCustomer(id="678905",name="Fabian",phoneNumber=78655567,balance=sp.mutez(0))
# Removes a customer through its id number.
scenario += myCustomersContract.removeCustomer(id="678905")
# Updates a customer's balance.
scenario += myCustomersContract.updateBalance(id="123456",amount=sp.mutez(10000000))
# Transfers funds from a customer to another.
scenario += myCustomersContract.transfer(idFrom="123456", idTo="345678", amount=sp.mutez(5000000))
此處顯示的SmartPy智慧合約的原始碼僅用於說明目的,我們不需要再次編譯和部署它。它已經位於Tezos區塊鏈測試網上,地址為:KT18pK2MGrnTZqyTafUe1sWp2ubJ75eYT86t
現在我們擁有從Android呼叫智慧合約所需的一切。 首先,我們將使用智慧合約的“ addCustomer”入口點新增新客戶。讓我們考慮客戶的名字“ Bob”,他的ID將是“ 98765”,電話號碼是“ 99876787”。 鮑勃的餘額為10英鎊(1000萬個互斥量)。 因此,我們的智慧合約呼叫命令將如下所示:
JSONObject jsonObject = wallet.callContractEntryPoint(
wallet.getPublicKeyHash(), "KT18pK2MGrnTZqyTafUe1sWp2ubJ75eYT86t",
amount, fee, "", "", "addCustomer", new String[]{
"1000000", "98765","Bob","99876787"});
首先,我們需要通知TezosJ,我們將使用Tezos測試網(實際釋出智慧合約的地方)。我們還需要設定交易金額和費用。這是透過以下Java程式碼完成的:
// Change wallet provider to use testnet.
wallet.setProvider(“https://tezos-dev.cryptonomic-infra.tech");
// Sets amount and fee for the transaction.
BigDecimal amount = new BigDecimal(“0”);
BigDecimal fee = new BigDecimal(“0.1”);
// Calls the contract entry point.
JSONObject jsonObject = wallet.callContractEntryPoint(
wallet.getPublicKeyHash(), “KT18pK2MGrnTZqyTafUe1sWp2ubJ75eYT86t”,
amount, fee, “”, “”, “addCustomer”, new String[]{
“1000000”, “98765”,”Bob”,”99876787"});
// Prints the operation hash in the console.
String opHash = (String) jsonObject.get("result");
Log.i("output", "OpHash : " + opHash);
複製程式碼並將其貼上到我們的MainActivity類中,使其保持如下所示:
請注意,要使此呼叫正常工作,您首先需要注資並顯示您的Tezos帳戶。否則,您可能會收到如下錯誤:
There were errors: kind ‘branch’ id ‘proto.005-PsBabyM1.implicit.empty_implicit_contract’
執行專案! 如果一切正常,您將得到LogCat中顯示的事務雜湊(此處為onuvzSRu9GiUBtPxEVf958jPUkG8NTxo7UHCYvFXKB8Chtci3Jm):
這表明我們已成功將callContract事務傳送到Tezos testnet區塊鏈(因為我們有一個操作雜湊)。 現在讓我們檢查交易是否被Tezos區塊連結受。我們將使用TezBlock資源管理器執行此操作。在您喜歡的瀏覽器中開啟https://tezblock.io,首先,在螢幕的右上角,將“ mainnet”更改為“ balylonnet”(與testnet相同)。 然後將我們從Java執行中獲得的操作雜湊值貼上到搜尋框中,然後按“ enter”鍵:
這將顯示我們智慧合約的結果以及操作細節。透過單擊“display”,您將能夠檢查從我們的Java程式碼傳遞到Tezos區塊鏈的引數:
引數:
Left (Left (Left (Pair (Pair (Pair 1000000 "98765") "Bob") 99876787)))
這是我們從Android應用程式呼叫生成的Micheline格式的引數。部署時,Tezos智慧合約以Michelson語言編寫,它們期望以這種格式傳送的輸入引數。使用TezosJ庫的好處之一是它可以實時生成Micheline格式的引數,而您不必擔心它是如何完成的。
大結局
到目前為止,我們可以確保正確呼叫了智慧合約,傳遞了引數並且操作已被Tezos區塊連結受。 現在我們要做的最後一件事是檢查是否將新客戶Bob插入了智慧合約的儲存中。 為此,我們將使用Better-call.dev工具。只需開啟瀏覽器並將其指向https://better-call.dev。 在搜尋欄位中輸入我們的客戶智慧合約的地址(KT18pK2MGrnTZqyTafUe1sWp2ubJ75eYT86t),將網路更改為babylonnet,然後按Enter:
結果將是曾經傳送到智慧合約地址的所有操作的列表,以及智慧合約儲存的當前狀態。您將在此處檢查從Java傳遞過來的引數,以及它們是否正確儲存在儲存器中:
您可以嘗試智慧合約的其他入口點,例如removeCustomer,transfer和updateBalance。切記始終檢查每個入口點所需的引數數量。
執行程式碼時,如果遇到Java錯誤,則表示未傳送事務。在這種情況下,您必須重新檢查引數,其順序,帳戶餘額,費用以及您正在使用的網路(主網或測試網)。此外,還要檢查gasLimit和storageLimit引數。
另一方面,如果您曾經獲得過操作雜湊,則意味著您的Android應用已成功將交易傳送到了區塊鏈。但是您還必須檢查可能的與區塊鏈相關的錯誤。在這種情況下,當您使用TezBlock Explorer進行檢查時,它將顯示帶有鮭魚色背景的錯誤,這意味著在區塊鏈上下文中發生了錯誤(例如傳遞的引數數量錯誤,引數Micheline格式錯誤,甚至智慧合約未接受的條件-例如:您呼叫了轉移入口點,但“發件人”客戶沒有足夠的資金可傳送)。
結論
開發人員使用區塊鏈智慧合約從未如此簡單。 特別是Tezos,提供了許多出色的工具和無數的計算機語言庫,可促進與大多數系統的整合。TezosJ庫透過提供一種易於使用的callContractEntryPoint方法進行創新,該方法可以即時建立Micheline格式的引數。它具有Android開發人員在與區塊鏈無縫互動的應用程式開發中蓬勃發展所需的所有工具。