上一篇學會了如何發起交易,這一篇將會進入到另一個重要功能,就是部署合約!
應該有人看到標題就想問:為什麼已經用了專用函式庫 web3.js ,還要在前端使用 Truffle 呢?難道 web3.js 不能部署合約嗎?其實 web3.js 可以部署合約的,但是當合約需要與函式庫做連結時就會十分麻煩,幸好 Truffle 有提供相關的方法讓我們能夠輕鬆把函式庫與合約接在一起,可喜可賀~
我們其實只需要使用 Truffle 的部分功能,所以安裝要的功能即可,方法很簡單,在專案中使用 npm 安裝@truffle/contract
:
npm install @truffle/contract
然後我們在 ProviderService 中使用:
declare let require: any;
const TruffleContract = require('@truffle/contract');
這樣前置作業就完成了!
我們接下來會用之前設計的 Resume.sol
與 StrLib.sol
來示範部署合約及函式庫。先將智能合約進行編譯:
truffle compile
部署智能合約需要用到 ABI
與 bytecode
,而這些資訊放在 Resume.json
與 StrLib.json
中,所以我們要將這兩個檔案引入。先在 types 資料夾中新增 contract.ts
,並從 index.ts
中 export
:
export * from './contract';
接著在 contract.ts
中使用 require
來引入 Resume.json
與 StrLib.json
:
declare let require: any;
export const ResumeContract = require('../../../truffle/build/contracts/Resume.json');
export const StrLibContract = require('../../../truffle/build/contracts/StrLib.json');
如此一來,就可以從 ResumeContract
與 StrLibContract
中取得 ABI
與 bytecode
囉!
Resume 合約在部署時需要帶上 name
、 address
、 age
與 gender
資訊,所以我們來定義資料格式,就放在 contract.ts
中:
export interface ResumeInitialOptions {
name: string;
address: string;
age: number;
gender: number;
}
好了之後開始定義我們部署合約的方法。一開始要先將編譯的合約帶入 TruffleContract
中,並且要設定 Provider ,理所當然地使用 this.web3.currentProvider
,這邊需要特別去指定 Resume 合約使用的 networkId
,否則會報錯,然後透過 new
進行部署,需要先將 StrLib 部署,再將 StrLib 的合約位址與 Resume 透過 link(name, address)
做連結,然後才部署 Resume 合約:
public deployResume(info: ResumeInitialOptions): Observable<any> {
const strLib = TruffleContract(StrLibContract);
const resume = TruffleContract(ResumeContract);
strLib.setProvider(this.web3.currentProvider);
resume.setProvider(this.web3.currentProvider);
resume.setNetwork(this.web3.currentProvider.networkVersion);
return from(strLib.new({ from: this.defaultAccount })).pipe(
mergeMap((instance: any) => {
resume.link('StrLib', instance.address);
return resume.new(info.name, info.address, info.age, info.gender, { from: this.defaultAccount });
}),
take(1)
);
}
這個設計方法是展示如何部署函式庫與合約,並且連結剛部署上去的 library 合約,真實應用場景可以先用 truffle migrate 把 StrLib 部署上去,再把 address 記起來填入
link(name, address)
中即可。
老樣子在 app.component.ts
中做測試:
constructor(private provider: ProviderService) {
const info = {
name: 'HAO',
address: '0x579c43911C862E16fEB199233ec2d32e441b7713',
age: 21,
gender: 0
} as ResumeInitialOptions;
this.provider.getAccount().pipe(
take(1),
mergeMap(accounts => {
this.provider.defaultAccount = accounts[0];
return this.provider.deployResume(info);
})
).subscribe(instance => {
console.log(instance);
});
}
這時候打開網頁會跳出 MetaMask ,第一個是 StrLib 的交易請求:
按下確定後會跳出 Resume 的交易請求:
都完成後到 Ganache 中查看交易內容:
這樣就成功部署啦~~
借助 web3.js 來取得 Provider ,然後透過 Truffle 部署合約,並且能夠與 library 做連結,這部分算是 DApp 的核心功能之一,務必熟悉!