1158 words
6 minutes
从零开始的合约交互小知识(1)

智能合约#

智能合约与平时的代码其实没有什么区别,只是运行于一个以太坊这样的分布式平台上。这个运行的平台,赋予了这些代码不可变,确定性,分布式和可自校验状态等特点。代码运行过程中状态的存储,是不可变的。

在以太坊中,每个合约都有一个唯一的地址来标识它自己(由创建者的哈希地址和曾经发送过的交易的数量推算出来)。客户端可以与这个地址进行交互,可以发送ether,调用函数,查询当前的状态等。

智能合约,本质上就是代码,以及代码运行后存储到区块链上的状态两个元素组成。比如,你用来收发ETH的钱包,本质上就是一个智能合约,只是外面套了一个界面。

Gas#

因为执行计算要花钱,而要执行的运算量与代码直接相关。所以,每个在网络运行的底层操作都需要一定量的gas。gas只是一个名字,它代表的是执行所需要花费的成本(译者注:由于以太坊是图灵完备的,随便一个死循环就将导致网络不可用,所以引入了gas的概念)。

整个分布式网络引入了强制限制,来避免停机问题。因此如果你写一个死循环,当gas耗尽后,网络就会拒绝执行接下来的操作,并且回滚你之前的所有操作。

gas的价格由市场决定,类似于比特币的交易费机制。如果你的gas价格高,节点则将优先因为利益问题打包你的交易。

一般来说,在以太坊网上读取状态是免费的,只有写入状态是收费的。下面这个文章是gas概念的一些深度解析

GWEI & gasPrice & gasLimit#

gasPrice 是给矿工的费用,GWEI 越高 即 gasPrice越高,打包速度越快。而 gasLimit 用于限制本次交易 gas 费用上限,防止无限制烧 gas。

合约交互可入参overrides.gasPrice 修改,示例如下:

// 使用 ethers 设置 GWEI:
const baseGasPrice = await provider.getGasPrice(); // 基础gasPrice { BigNumber: "23610503242" }
const limit = await contract.estimateGas.takeChance(num); // 预估 gaslimt
const options = {
gasPrice: baseGasPrice,
gasLimit: (Number(limit) * 1.5).toFixed(0)
}
const res = await this.contract.takeChance(num, options);// 最后一项override
const reward = await res.wait();

getGasPrice: 返回交易中使用的 gasPrice 的最佳猜测。

estimateGas: 返回执行带有 args 和 overrides 的 METHOD_NAME 所需的估计 gas 单位。

PS:主链币价格的设置方式#

overrides.value 主链币(比如BNB),价格的传参方式不能通过参数传入,而要放在最后一项对象的value属性中

// 使用 ethers 设置 主链币价格:
const options = {
value: 0 // 主链币的数量 bignumber
}
const resp = await contractObj.swap(cloneAmountOut, cloneAmountInMax, options); // 最后一项位对象

MetaMask#

Metamask 是一个Google浏览器扩展,把Chrome变成了一个 DApp 浏览器。它的核心特性是注入以太坊提供的 js 客户端库web3,到每一个界面,来让 DApp 连接到 MetaMask 提供的以太坊节点服务。不过这个 Chrome 扩展,可以允许你管理你的钱包,以及连接到不同的以太坊网络。

常见的 MetaMask 交互

是否安装metamsk#

export function isMetaMask() {
const { ethereum } = window;
return Boolean(ethereum && ethereum.isMetaMask);
}

获取chainid#

async function getChainId() {
const { ethereum } = window;
try {
const chainId = await ethereum.request({
method: "eth_chainId"
});
handleNewChain(chainId);
} catch (err) {
console.error(err);
}
}

主动切换到以太坊网络#

async function switchToEthereum() {
try {
await window.ethereum.request({
method: "wallet_switchEthereumChain",
params: [
{
chainId: "0x1"
}
]
});
} catch (error) {
console.log(error);
}
}

主动切换到其余链配置#

async function switchToOtherNetwork(findChain) {
const data = [];
data.push(findChain);
console.log(findChain, "switchNetwork");
try {
await window.ethereum.request({
method: "wallet_addEthereumChain",
params: data
});
} catch (error) {
console.log(error);
}
}

监听链上钱包配置#

function handelConnectInfo(info) {
console.log(info, "handelConnectInfo");
}
function handleDisConnect(disconnect) {
console.log(disconnect, "handleDisConnect");
}
function handleNewAccount(account) {
updateAccount(account[0]);
}
function handelNewMessage(msg) {
console.log(msg, "handelNewMessage");
}
function _listeningMetamsk() {
const { ethereum } = window;
ethereum.on("chainChanged", handleNewChain);
ethereum.on("accountsChanged", handleNewAccount);
ethereum.on("message", handelNewMessage);
ethereum.on("connect", throttle(handelConnectInfo, 1000));
ethereum.on("disconnect", throttle(handleDisConnect, 1000));
}

添加自定义代币到metamask#

async function addToken() {
let contractAddress = getContractAddress();
window.ethereum
.request({
method: "wallet_watchAsset",
params: {
type: "ERC20",
options: {
address: contractAddress.IPISTR,
symbol: "IPISTR",
decimals: 18,
image: "https://i.loli.net/2021/08/12/BNYGAD9RZUl6nch.png"
}
}
})
.then(success => {
if (success) {
Message.success("IPISTR Token added successfully!");
} else {
Message.error("Something went wrong.");
}
})
.catch(console.error);
}

综合实例-连接钱包#

export async function getMetamskConnect() {
if (!isMetaMask()) {
openUrl("https://metamask.io/", "install metamsk");
}
if (window.ethereum) {
window.provider = window.ethereum;
try {
let accounts = await window.ethereum.request({
method: "eth_requestAccounts"
});
await updateAccount(accounts[0]);
} catch (error) {
console.warn("Please authorize to access tour account");
}
}
await getChainId();
_listeningMetamsk();
}

内容参考: Getting Up to Speed on Ethereum

21个基于ethers的Dapp常用工具函数 | 登链社区 | 区块链技术社区

从零开始的合约交互小知识(1)
https://evanyuki.github.io/posts/65f1273e08074de9b1083d57cc16977c/
Author
Evanyuki
Published at
2022-09-15
License
CC BY-NC-SA 4.0