智能合约
智能合约与平时的代码其实没有什么区别,只是运行于一个以太坊这样的分布式平台上。这个运行的平台,赋予了这些代码不可变,确定性,分布式和可自校验状态等特点。代码运行过程中状态的存储,是不可变的。
在以太坊中,每个合约都有一个唯一的地址来标识它自己(由创建者的哈希地址和曾经发送过的交易的数量推算出来)。客户端可以与这个地址进行交互,可以发送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); // 预估 gaslimtconst options = { gasPrice: baseGasPrice, gasLimit: (Number(limit) * 1.5).toFixed(0)}
const res = await this.contract.takeChance(num, options);// 最后一项overrideconst 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 扩展,可以允许你管理你的钱包,以及连接到不同的以太坊网络。
是否安装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();}