Dapp跨平台相容性解決方案2. Mars Peng (Mars Orange)
Experience
LEADBEST 資深技術經理
區塊鏈相關產品開發
時間軸(遠時)科技股份有限公司 技術部經理
Friday購物與鮮網開發
時間軸科技股份有限公司 資深工程師
行動裝置跨平台軟體開發以及網站服務開發
超過十年的開發與管理經驗
撰寫多種前後端框架與APP,
Ember, Ag, React, Vue, Loopback ...
多次重大系統分析與技術選型
10. Wallet Web3 Provider Type
wallet postMessage customAPI export PKey
Metamask ✓ ✗ ✗
Imtoken ✗ ✓ ✗
Trust ✓ ✗ ✗
Edge ✗ ✗ ✓
14. Export PKey
Dapp
Get PKey
Dapp
confirm UI
Ethereumjs-tx
signTransaction
Block chain
Web3
sendRawTransaction
All in the
DApp
javascript
runtime
User Input
or
Edge wallet
Check
transaction
data
Sign transaction
Send transaction
TxHash event
or
callback
16. 以Edge為例
3.send transaction
function sendSigned(txData, cb) {
const privateKey = ethereumjs.Buffer.Buffer.from('xxx', 'hex')
const transaction = new ethereumjs.Tx(txData)
transaction.sign(privateKey)
const serializedTx = transaction.serialize().toString('hex')
web3.eth.sendRawTransaction('0x' + serializedTx, cb)
}
1.Edge Wallet Info
keys: {
dataKey: ""
ethereumAddress: ""
ethereumKey: "pkey"
syncKey: ""
}
2.get txCount and create txData
web3.eth.getTransactionCount
const txData = {
nonce: web3.utils.toHex(txCount),
gasLimit: web3.utils.toHex(25000),
gasPrice: web3.utils.toHex(10e9), // 10 Gwei
to: xxx,
from: xxx,
value: web3.utils.toHex(100000000000000000),
chainId: 1
}
20. Trust Provider sendAsync method
sendAsync method
switch (payload.method) {
// ...
case "eth_sign":
return this.eth_sign(payload);
case "personal_sign":
return this.personal_sign(payload);
… //
}
postMessage method
function eth_sign(payload) {
this.postMessage("signMessage", payload.id, { data: payload.params[1] });
}
21. Using Web3 1.0.0 for Wallet App
Web3 0.20.6
web3.version.getNetwork(function (err, networkId) {
return networkTypeName(networkId);
});
Web3 1.0.0
window.web3 = new Web3(web3.currentProvider);
web3.eth.net.getNetworkType().then(function (networkType) {
return networkType;
});
22. Using Web3 1.0.0 for Wallet App (New Rule)
if (window.ethereum) {
if (!window.web3old) {
window.web3 = new Web3(ethereum);
// try catch …
await ethereum.enable();
}
}
else if (window.web3) {
if (!window.web3old) {
window.web3 = new Web3(web3.currentProvider);
}
}
// else …
web3.eth.net.getNetworkType().then(function (networkType) {
return networkType;
});
24. ImToken Provider sendAsync method
sendAsync method
else if ('personal_sign' == e.method) {
var t = e.params;
imToken.callAPI('transaction.personalSign', {
message: t[0],
address: t[1]
}
}
ImToken 採用自有 SDK 進行呼叫
這會造成既使 web3 成功了 還是會遭到 SDK 阻擋
且2.0的早期版本還必須使用原始的 Provider
無法採用 1.0 API
26. Dapp
Loaded
Metamask
Inject
Web3 v0.20
Dapp
Load
Web3 v1.0
Dapp
Web3 v1.0
Wrapper
Web3 v0.20
Dapp
Call
Web3 v1.0
Metamask
Metamask
Support
Web3 1.0
Dapp
Loaded
Imtoken
Inject
Web3 v0.18
Dapp
Load
Web3 v1.0
Dapp
Web3 v1.0
Wrapper
Web3 v0.18
Dapp
Call
Web3 v1.0
Imtoken
Imtoken
Not support
Web3 1.0
Dapp
Load
Web3 Extend
Leadbest
Web3 Extend
Call
Provider
Then
Wrapper
Returen
Promise
Imtoken
Web3 v0.18
Dapp
Load
Web3 v0.20
Leadbest
Web3 Extend
Call
Ethereumjs-tx
Then
Wrapper
Returen
Promise
Browser
Web3 Extend
Create
Web3 v1.0
API
Web3 Extend
Create
Web3 v1.0
API
Dapp
Load
Web3 Extend
Imtoken?
Edge?
27. Extend Web3 to 1.0
if (web3.eth.Contract && web3.eth.Contract.constructor) {
var contract = new web3.eth.Contract(ltcontract.main.interface);
return contract;
}
else {
web3.eth.Contract = function(abi, data) {
if (typeof data == 'string') {
this.MyContract = web3old.eth.contract(abi);
this.contractInstance = this.MyContract.at(addr);
coverFactory[`coverContractMethods${getProviderName()}`].call(this, this.contractInstance);
return this.contractInstance;
}
else {
this.MyContract = web3old.eth.contract(abi);
coverFactory[`coverContractDeploy${getProviderName()}`].call(this, this.MyContract);
return this.MyContract;
}
};
}
28. coverFactory.coverContractMethods = function(ins) {
var self = this;
ins.methods = {};
Object.keys(ins).map(function(value) {
ins.methods[value] = function() {
var obj = {};
var methodData = arguments;
// ... call method
obj.send = function(sendData) {
var promiEvent = Web3PromiEvent();
ins[value].sendTransaction(...methodData, sendData, function(err, result) {
if(err) {
return promiEvent.reject(err);
}
promiEvent.eventEmitter.emit('transactionHash', result);
promiEvent.resolve(result);
});
return promiEvent.eventEmitter;
};
return obj;
};
});
29. 相容問題 全是坑
Metamask 不支援 signTransaction
Imtoken SDK 檢查不能沒有 to address
Trust gas 預估不準確
chiper 吃 cookie
coinbase IOS 錯誤沒反應
等等等...
30. coverFactory.coverContractDployImtoken = function(ins) {
ins.deploy = function(deployData) {
var obj = {};
obj.send = function(sendData) {
var contractData = ins.new.getData(...deployData.arguments, { data: deployData.data });
web3.eth.getTransactionCount(sendData.from, ‘pending', async function (err, txCount) {
const txData = createTxData(contractData, txCount);
// try catch
const pKey = await promiseModal('pKeyModal');
const serializedTx = signTransactionTx(pKey, txData);
var confirm = await promiseModal('confirmModal');
web3.eth.sendRawTransaction('0x' + serializedTx, function (err, result) {
if (err) {
return promiEvent.reject(err);
}
promiEvent.eventEmitter.emit('transactionHash', result);
promiEvent.resolve(result);
})
});
}
}
Imtoken 客製擴展
32. WS Provider
var poolAddress = this.poolAddress;
var web3WS = new Web3(new Web3.providers.WebsocketProvider(this.chainNetworkWS));
// wss://mainnet.infura.io/ws
var czEvents = new web3WS.eth.Contract(ERC20Interface, this.tokenAddress);
var options = {}
czEvents.events.Transfer(options, async (error, event) => {
if (error) {
console.log(error)
return
}
// some code
})
36. 完整方案
Check DApp Browser
Load Web3 & Extend
Boot Web3
web3
web3old
web3WS
Check Network
Check Account
Check Whitelist
Get in
Plugin Extend
extend-imtoken,
extend-edge….
Editor's Notes Web3 很好的封裝了 JSON RPC API
Ethereumjs-tx 讓我們 sign Transaction 自行發布上鏈 分散式架構 逃不出 CAP 原理