智能合约开发
1、转账
native币的转账直接用原声的transfer方法
token合约币转账,需要使用合约方法
//以太币转账 address.transfer() // token币转账 IERC20(address).transferFrom()
2、部署
hardhat的api能直接处理好部署发布代理合约和实现合约
async function main() { // 获取合约工厂,保证contracts目录里面有MyContract合约 const MyContract = await ethers.getContractFactory("MyContract"); // 部署可升级合约 console.log("Deploying the upgradable MyContract..."); const myContract = await upgrades.deployProxy(MyContract, ["MyContractV1"], { initializer: "initialize", gasPrice: '...' }); console.log("MyContract deployed to:", myContract.address); }
3、调用
- 在合约中调用另外合约的方法
// 引入接口类型,然后直接用目标合约地址进行调用
// 因为合约本来就在链上,是可信任环境,不需要签名
Interface(address).methodA(param1, param2, ...)
- 从客户端调用合约的方法
// Infura等托管节点服务,它们会处理签名
// 如果没有,需要用web3.js先处理签名
const web3 = new Web3('https://mainnet.infura.io/v3/YOUR_INFURA_API_KEY'); const contract = new web3.eth.Contract(contractABI, contractAddress); // 使用call方法。 用于读取合约状态或数据,不会改变合约状态,通常用于查询合约数据,例如获取合约中的变量值或执行只读函数 contract.methods.YOUR_CONTRACT_METHOD().call() .then(result => { console.log('Result:', result); }) .catch(error => { console.error('Error:', error); }); // 使用send方法。用于执行合约方法,会改变合约状态,通常用于执行会改变合约状态的函数。
// 这种适合用于有钱包插件环境,因为send会被钱包插件补货,内部给它做签名。调用方是完全不会知道privateKey contract.methods.YOUR_CONTRACT_METHOD().send({ from: '0xYOUR_ADDRESS', gas: 1000000 }) .then(receipt => { console.log('Transaction receipt:', receipt); }) .catch(error => { console.error('Error:', error); });
// 适用于服务端调用,调用方掌握了privateKey情况
const signedTx = await web3.eth.accounts.signTransaction(tx, privateKey);
const receipt = await web3.eth.sendSignedTransaction(signedTx.rawTransaction);
调用的错误一般总共有四类
- 连接到节点的JSON-RPC错误
- 交易错误,比如交易因gas不足而失败
- 合约错误,一般是触发了合约的require、revert等
- 调用错误
// json-rpc错误 { message: 'Internal JSON-RPC error.', code: -32603, // ...其他信息 }
// 交易错误
{
message: 'Transaction ran out of gas.',
transactionHash: '0x...',
gasUsed: 12345,
}
4、升级
合约因为功能变更、实现bug等情况,需要升级改动。必须要使用代理模式的合约才可以升级:
- 升级后,合约原本的storage属性不受影响
因为storage
变量存储在代理合约中,而合约逻辑存储在实现合约中。当你升级实现合约时,代理合约会将调用转发到新的实现合约,但storage
变量仍然存储在代理合约中,因此不会发生变化
- 新增的
storage
变量应该位于合约结构的末尾,以确保与现有storage
变量的布局兼容
storage
变量按照声明的顺序在合约中进行布局。如果你在现有变量之间插入新的storage
变量,可能会导致现有变量的布局发生变化,从而导致代理合约无法正确访问storage
变量
1、solidity不足,导致以太坊分叉
2、缺少权限检查,任何人都可以调用
3、缺少可追溯能力