Update Solidity files in docs (#4956)
Co-authored-by: Hadrien Croubois <hadrien.croubois@gmail.com>
This commit is contained in:
9
contracts/mocks/docs/MyNFT.sol
Normal file
9
contracts/mocks/docs/MyNFT.sol
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
// contracts/MyNFT.sol
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
pragma solidity ^0.8.20;
|
||||||
|
|
||||||
|
import {ERC721} from "../../token/ERC721/ERC721.sol";
|
||||||
|
|
||||||
|
contract MyNFT is ERC721 {
|
||||||
|
constructor() ERC721("MyNFT", "MNFT") {}
|
||||||
|
}
|
||||||
@ -0,0 +1,14 @@
|
|||||||
|
// contracts/AccessControlModified.sol
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
pragma solidity ^0.8.20;
|
||||||
|
|
||||||
|
import {AccessControl} from "../../../access/AccessControl.sol";
|
||||||
|
|
||||||
|
contract AccessControlModified is AccessControl {
|
||||||
|
error AccessControlNonRevokable();
|
||||||
|
|
||||||
|
// Override the revokeRole function
|
||||||
|
function revokeRole(bytes32, address) public pure override {
|
||||||
|
revert AccessControlNonRevokable();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,17 @@
|
|||||||
|
// contracts/AccessControlNonRevokableAdmin.sol
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
pragma solidity ^0.8.20;
|
||||||
|
|
||||||
|
import {AccessControl} from "../../../access/AccessControl.sol";
|
||||||
|
|
||||||
|
contract AccessControlNonRevokableAdmin is AccessControl {
|
||||||
|
error AccessControlNonRevokable();
|
||||||
|
|
||||||
|
function revokeRole(bytes32 role, address account) public override {
|
||||||
|
if (role == DEFAULT_ADMIN_ROLE) {
|
||||||
|
revert AccessControlNonRevokable();
|
||||||
|
}
|
||||||
|
|
||||||
|
super.revokeRole(role, account);
|
||||||
|
}
|
||||||
|
}
|
||||||
21
contracts/mocks/docs/token/ERC1155/GameItems.sol
Normal file
21
contracts/mocks/docs/token/ERC1155/GameItems.sol
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
// contracts/GameItems.sol
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
pragma solidity ^0.8.20;
|
||||||
|
|
||||||
|
import {ERC1155} from "../../../../token/ERC1155/ERC1155.sol";
|
||||||
|
|
||||||
|
contract GameItems is ERC1155 {
|
||||||
|
uint256 public constant GOLD = 0;
|
||||||
|
uint256 public constant SILVER = 1;
|
||||||
|
uint256 public constant THORS_HAMMER = 2;
|
||||||
|
uint256 public constant SWORD = 3;
|
||||||
|
uint256 public constant SHIELD = 4;
|
||||||
|
|
||||||
|
constructor() ERC1155("https://game.example/api/item/{id}.json") {
|
||||||
|
_mint(msg.sender, GOLD, 10 ** 18, "");
|
||||||
|
_mint(msg.sender, SILVER, 10 ** 27, "");
|
||||||
|
_mint(msg.sender, THORS_HAMMER, 1, "");
|
||||||
|
_mint(msg.sender, SWORD, 10 ** 9, "");
|
||||||
|
_mint(msg.sender, SHIELD, 10 ** 9, "");
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,7 @@
|
|||||||
|
// contracts/MyERC115HolderContract.sol
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
pragma solidity ^0.8.20;
|
||||||
|
|
||||||
|
import {ERC1155Holder} from "../../../../token/ERC1155/utils/ERC1155Holder.sol";
|
||||||
|
|
||||||
|
contract MyERC115HolderContract is ERC1155Holder {}
|
||||||
11
contracts/mocks/docs/token/ERC20/GLDToken.sol
Normal file
11
contracts/mocks/docs/token/ERC20/GLDToken.sol
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
// contracts/GLDToken.sol
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
pragma solidity ^0.8.20;
|
||||||
|
|
||||||
|
import {ERC20} from "../../../../token/ERC20/ERC20.sol";
|
||||||
|
|
||||||
|
contract GLDToken is ERC20 {
|
||||||
|
constructor(uint256 initialSupply) ERC20("Gold", "GLD") {
|
||||||
|
_mint(msg.sender, initialSupply);
|
||||||
|
}
|
||||||
|
}
|
||||||
19
contracts/mocks/docs/token/ERC721/GameItem.sol
Normal file
19
contracts/mocks/docs/token/ERC721/GameItem.sol
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
// contracts/GameItem.sol
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
pragma solidity ^0.8.20;
|
||||||
|
|
||||||
|
import {ERC721URIStorage, ERC721} from "../../../../token/ERC721/extensions/ERC721URIStorage.sol";
|
||||||
|
|
||||||
|
contract GameItem is ERC721URIStorage {
|
||||||
|
uint256 private _nextTokenId;
|
||||||
|
|
||||||
|
constructor() ERC721("GameItem", "ITM") {}
|
||||||
|
|
||||||
|
function awardItem(address player, string memory tokenURI) public returns (uint256) {
|
||||||
|
uint256 tokenId = _nextTokenId++;
|
||||||
|
_mint(player, tokenId);
|
||||||
|
_setTokenURI(tokenId, tokenURI);
|
||||||
|
|
||||||
|
return tokenId;
|
||||||
|
}
|
||||||
|
}
|
||||||
27
contracts/mocks/docs/utilities/Base64NFT.sol
Normal file
27
contracts/mocks/docs/utilities/Base64NFT.sol
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
pragma solidity ^0.8.20;
|
||||||
|
|
||||||
|
import {ERC721} from "../../../token/ERC721/ERC721.sol";
|
||||||
|
import {Strings} from "../../../utils/Strings.sol";
|
||||||
|
import {Base64} from "../../../utils/Base64.sol";
|
||||||
|
|
||||||
|
contract Base64NFT is ERC721 {
|
||||||
|
using Strings for uint256;
|
||||||
|
|
||||||
|
constructor() ERC721("Base64NFT", "MTK") {}
|
||||||
|
|
||||||
|
// ...
|
||||||
|
|
||||||
|
function tokenURI(uint256 tokenId) public pure override returns (string memory) {
|
||||||
|
// Equivalent to:
|
||||||
|
// {
|
||||||
|
// "name": "Base64NFT #1",
|
||||||
|
// // Replace with extra ERC-721 Metadata properties
|
||||||
|
// }
|
||||||
|
// prettier-ignore
|
||||||
|
string memory dataURI = string.concat("{\"name\": \"Base64NFT #", tokenId.toString(), "\"}");
|
||||||
|
|
||||||
|
return string.concat("data:application/json;base64,", Base64.encode(bytes(dataURI)));
|
||||||
|
}
|
||||||
|
}
|
||||||
15
contracts/mocks/docs/utilities/Multicall.sol
Normal file
15
contracts/mocks/docs/utilities/Multicall.sol
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
// contracts/Box.sol
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
pragma solidity ^0.8.20;
|
||||||
|
|
||||||
|
import {Multicall} from "../../../utils/Multicall.sol";
|
||||||
|
|
||||||
|
contract Box is Multicall {
|
||||||
|
function foo() public {
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
|
||||||
|
function bar() public {
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -32,27 +32,7 @@ Here's what a contract for tokenized items might look like:
|
|||||||
|
|
||||||
[source,solidity]
|
[source,solidity]
|
||||||
----
|
----
|
||||||
// contracts/GameItems.sol
|
include::api:example$token/ERC1155/GameItems.sol[]
|
||||||
// SPDX-License-Identifier: MIT
|
|
||||||
pragma solidity ^0.8.20;
|
|
||||||
|
|
||||||
import {ERC1155} from "@openzeppelin/contracts/token/ERC1155/ERC1155.sol";
|
|
||||||
|
|
||||||
contract GameItems is ERC1155 {
|
|
||||||
uint256 public constant GOLD = 0;
|
|
||||||
uint256 public constant SILVER = 1;
|
|
||||||
uint256 public constant THORS_HAMMER = 2;
|
|
||||||
uint256 public constant SWORD = 3;
|
|
||||||
uint256 public constant SHIELD = 4;
|
|
||||||
|
|
||||||
constructor() ERC1155("https://game.example/api/item/{id}.json") {
|
|
||||||
_mint(msg.sender, GOLD, 10**18, "");
|
|
||||||
_mint(msg.sender, SILVER, 10**27, "");
|
|
||||||
_mint(msg.sender, THORS_HAMMER, 1, "");
|
|
||||||
_mint(msg.sender, SWORD, 10**9, "");
|
|
||||||
_mint(msg.sender, SHIELD, 10**9, "");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
----
|
----
|
||||||
|
|
||||||
Note that for our Game Items, Gold is a fungible token whilst Thor's Hammer is a non-fungible token as we minted only one.
|
Note that for our Game Items, Gold is a fungible token whilst Thor's Hammer is a non-fungible token as we minted only one.
|
||||||
@ -119,11 +99,11 @@ TIP: If you'd like to put all item information on-chain, you can extend ERC-721
|
|||||||
[[sending-to-contracts]]
|
[[sending-to-contracts]]
|
||||||
== Sending Tokens to Contracts
|
== Sending Tokens to Contracts
|
||||||
|
|
||||||
A key difference when using xref:api:token/ERC1155.adoc#IERC1155-safeTransferFrom-address-address-uint256-uint256-bytes-[`safeTransferFrom`] is that token transfers to other contracts may revert with the following message:
|
A key difference when using xref:api:token/ERC1155.adoc#IERC1155-safeTransferFrom-address-address-uint256-uint256-bytes-[`safeTransferFrom`] is that token transfers to other contracts may revert with the following custom error:
|
||||||
|
|
||||||
[source,text]
|
[source,text]
|
||||||
----
|
----
|
||||||
ERC-1155: transfer to non ERC-1155 Receiver implementer
|
ERC1155InvalidReceiver("<ADDRESS>")
|
||||||
----
|
----
|
||||||
|
|
||||||
This is a good thing! It means that the recipient contract has not registered itself as aware of the ERC-1155 protocol, so transfers to it are disabled to *prevent tokens from being locked forever*. As an example, https://etherscan.io/token/0xa74476443119A942dE498590Fe1f2454d7D4aC0d?a=0xa74476443119A942dE498590Fe1f2454d7D4aC0d[the Golem contract currently holds over 350k `GNT` tokens], worth multiple tens of thousands of dollars, and lacks methods to get them out of there. This has happened to virtually every ERC20-backed project, usually due to user error.
|
This is a good thing! It means that the recipient contract has not registered itself as aware of the ERC-1155 protocol, so transfers to it are disabled to *prevent tokens from being locked forever*. As an example, https://etherscan.io/token/0xa74476443119A942dE498590Fe1f2454d7D4aC0d?a=0xa74476443119A942dE498590Fe1f2454d7D4aC0d[the Golem contract currently holds over 350k `GNT` tokens], worth multiple tens of thousands of dollars, and lacks methods to get them out of there. This has happened to virtually every ERC20-backed project, usually due to user error.
|
||||||
@ -132,14 +112,7 @@ In order for our contract to receive ERC-1155 tokens we can inherit from the con
|
|||||||
|
|
||||||
[source,solidity]
|
[source,solidity]
|
||||||
----
|
----
|
||||||
// contracts/MyContract.sol
|
include::api:example$token/ERC1155/MyERC115HolderContract.sol[]
|
||||||
// SPDX-License-Identifier: MIT
|
|
||||||
pragma solidity ^0.8.20;
|
|
||||||
|
|
||||||
import {ERC1155Holder} from "@openzeppelin/contracts/token/ERC1155/utils/ERC1155Holder.sol";
|
|
||||||
|
|
||||||
contract MyContract is ERC1155Holder {
|
|
||||||
}
|
|
||||||
----
|
----
|
||||||
|
|
||||||
We can also implement more complex scenarios using the xref:api:token/ERC1155.adoc#IERC1155Receiver-onERC1155Received-address-address-uint256-uint256-bytes-[`onERC1155Received`] and xref:api:token/ERC1155.adoc#IERC1155Receiver-onERC1155BatchReceived-address-address-uint256---uint256---bytes-[`onERC1155BatchReceived`] functions.
|
We can also implement more complex scenarios using the xref:api:token/ERC1155.adoc#IERC1155Receiver-onERC1155Received-address-address-uint256-uint256-bytes-[`onERC1155Received`] and xref:api:token/ERC1155.adoc#IERC1155Receiver-onERC1155BatchReceived-address-address-uint256---uint256---bytes-[`onERC1155BatchReceived`] functions.
|
||||||
|
|||||||
@ -13,17 +13,7 @@ Here's what our GLD token might look like.
|
|||||||
|
|
||||||
[source,solidity]
|
[source,solidity]
|
||||||
----
|
----
|
||||||
// contracts/GLDToken.sol
|
include::api:example$token/ERC20/GLDToken.sol[]
|
||||||
// SPDX-License-Identifier: MIT
|
|
||||||
pragma solidity ^0.8.20;
|
|
||||||
|
|
||||||
import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
|
|
||||||
|
|
||||||
contract GLDToken is ERC20 {
|
|
||||||
constructor(uint256 initialSupply) ERC20("Gold", "GLD") {
|
|
||||||
_mint(msg.sender, initialSupply);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
----
|
----
|
||||||
|
|
||||||
Our contracts are often used via https://solidity.readthedocs.io/en/latest/contracts.html#inheritance[inheritance], and here we're reusing xref:api:token/ERC20.adoc#erc20[`ERC20`] for both the basic standard implementation and the xref:api:token/ERC20.adoc#ERC20-name--[`name`], xref:api:token/ERC20.adoc#ERC20-symbol--[`symbol`], and xref:api:token/ERC20.adoc#ERC20-decimals--[`decimals`] optional extensions. Additionally, we're creating an `initialSupply` of tokens, which will be assigned to the address that deploys the contract.
|
Our contracts are often used via https://solidity.readthedocs.io/en/latest/contracts.html#inheritance[inheritance], and here we're reusing xref:api:token/ERC20.adoc#erc20[`ERC20`] for both the basic standard implementation and the xref:api:token/ERC20.adoc#ERC20-name--[`name`], xref:api:token/ERC20.adoc#ERC20-symbol--[`symbol`], and xref:api:token/ERC20.adoc#ERC20-decimals--[`decimals`] optional extensions. Additionally, we're creating an `initialSupply` of tokens, which will be assigned to the address that deploys the contract.
|
||||||
|
|||||||
@ -12,28 +12,7 @@ Here's what a contract for tokenized items might look like:
|
|||||||
|
|
||||||
[source,solidity]
|
[source,solidity]
|
||||||
----
|
----
|
||||||
// contracts/GameItem.sol
|
include::api:example$token/ERC721/GameItem.sol[]
|
||||||
// SPDX-License-Identifier: MIT
|
|
||||||
pragma solidity ^0.8.20;
|
|
||||||
|
|
||||||
import {ERC721URIStorage} from "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
|
|
||||||
|
|
||||||
contract GameItem is ERC721URIStorage {
|
|
||||||
uint256 private _nextTokenId;
|
|
||||||
|
|
||||||
constructor() ERC721("GameItem", "ITM") {}
|
|
||||||
|
|
||||||
function awardItem(address player, string memory tokenURI)
|
|
||||||
public
|
|
||||||
returns (uint256)
|
|
||||||
{
|
|
||||||
uint256 tokenId = _nextTokenId++;
|
|
||||||
_mint(player, tokenId);
|
|
||||||
_setTokenURI(tokenId, tokenURI);
|
|
||||||
|
|
||||||
return tokenId;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
----
|
----
|
||||||
|
|
||||||
The xref:api:token/ERC721.adoc#ERC721URIStorage[`ERC721URIStorage`] contract is an implementation of ERC-721 that includes the metadata standard extensions (xref:api:token/ERC721.adoc#IERC721Metadata[`IERC721Metadata`]) as well as a mechanism for per-token metadata. That's where the xref:api:token/ERC721.adoc#ERC721-_setTokenURI-uint256-string-[`_setTokenURI`] method comes from: we use it to store an item's metadata.
|
The xref:api:token/ERC721.adoc#ERC721URIStorage[`ERC721URIStorage`] contract is an implementation of ERC-721 that includes the metadata standard extensions (xref:api:token/ERC721.adoc#IERC721Metadata[`IERC721Metadata`]) as well as a mechanism for per-token metadata. That's where the xref:api:token/ERC721.adoc#ERC721-_setTokenURI-uint256-string-[`_setTokenURI`] method comes from: we use it to store an item's metadata.
|
||||||
|
|||||||
@ -18,18 +18,7 @@ Inheritance is often used to add the parent contract's functionality to your own
|
|||||||
For example, imagine you want to change xref:api:access.adoc#AccessControl[`AccessControl`] so that xref:api:access.adoc#AccessControl-revokeRole-bytes32-address-[`revokeRole`] can no longer be called. This can be achieved using overrides:
|
For example, imagine you want to change xref:api:access.adoc#AccessControl[`AccessControl`] so that xref:api:access.adoc#AccessControl-revokeRole-bytes32-address-[`revokeRole`] can no longer be called. This can be achieved using overrides:
|
||||||
|
|
||||||
```solidity
|
```solidity
|
||||||
// contracts/ModifiedAccessControl.sol
|
include::api:example$access-control/AccessControlModified.sol[]
|
||||||
// SPDX-License-Identifier: MIT
|
|
||||||
pragma solidity ^0.8.20;
|
|
||||||
|
|
||||||
import {AccessControl} from "@openzeppelin/contracts/access/AccessControl.sol";
|
|
||||||
|
|
||||||
contract ModifiedAccessControl is AccessControl {
|
|
||||||
// Override the revokeRole function
|
|
||||||
function revokeRole(bytes32, address) public override {
|
|
||||||
revert("ModifiedAccessControl: cannot revoke roles");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
```
|
||||||
|
|
||||||
The old `revokeRole` is then replaced by our override, and any calls to it will immediately revert. We cannot _remove_ the function from the contract, but reverting on all calls is good enough.
|
The old `revokeRole` is then replaced by our override, and any calls to it will immediately revert. We cannot _remove_ the function from the contract, but reverting on all calls is good enough.
|
||||||
@ -46,22 +35,7 @@ Here is a modified version of xref:api:access.adoc#AccessControl[`AccessControl`
|
|||||||
|
|
||||||
|
|
||||||
```solidity
|
```solidity
|
||||||
// contracts/ModifiedAccessControl.sol
|
include::api:example$access-control/AccessControlNonRevokableAdmin.sol[]
|
||||||
// SPDX-License-Identifier: MIT
|
|
||||||
pragma solidity ^0.8.20;
|
|
||||||
|
|
||||||
import {AccessControl} from "@openzeppelin/contracts/access/AccessControl.sol";
|
|
||||||
|
|
||||||
contract ModifiedAccessControl is AccessControl {
|
|
||||||
function revokeRole(bytes32 role, address account) public override {
|
|
||||||
require(
|
|
||||||
role != DEFAULT_ADMIN_ROLE,
|
|
||||||
"ModifiedAccessControl: cannot revoke default admin role"
|
|
||||||
);
|
|
||||||
|
|
||||||
super.revokeRole(role, account);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
```
|
||||||
|
|
||||||
The `super.revokeRole` statement at the end will invoke ``AccessControl``'s original version of `revokeRole`, the same code that would've run if there were no overrides in place.
|
The `super.revokeRole` statement at the end will invoke ``AccessControl``'s original version of `revokeRole`, the same code that would've run if there were no overrides in place.
|
||||||
|
|||||||
@ -230,7 +230,6 @@ contract MyGovernor is Governor, GovernorCountingSimple, GovernorVotes, Governor
|
|||||||
|
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
=== Disclaimer
|
=== Disclaimer
|
||||||
|
|||||||
@ -38,16 +38,7 @@ Once installed, you can use the contracts in the library by importing them:
|
|||||||
|
|
||||||
[source,solidity]
|
[source,solidity]
|
||||||
----
|
----
|
||||||
// contracts/MyNFT.sol
|
include::api:example$MyNFT.sol[]
|
||||||
// SPDX-License-Identifier: MIT
|
|
||||||
pragma solidity ^0.8.20;
|
|
||||||
|
|
||||||
import {ERC721} from "@openzeppelin/contracts/token/ERC721/ERC721.sol";
|
|
||||||
|
|
||||||
contract MyNFT is ERC721 {
|
|
||||||
constructor() ERC721("MyNFT", "MNFT") {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
----
|
----
|
||||||
|
|
||||||
TIP: If you're new to smart contract development, head to xref:learn::developing-smart-contracts.adoc[Developing Smart Contracts] to learn about creating a new project and compiling your contracts.
|
TIP: If you're new to smart contract development, head to xref:learn::developing-smart-contracts.adoc[Developing Smart Contracts] to learn about creating a new project and compiling your contracts.
|
||||||
|
|||||||
@ -124,41 +124,7 @@ Here is an example to send JSON Metadata through a Base64 Data URI using an ERC-
|
|||||||
|
|
||||||
[source, solidity]
|
[source, solidity]
|
||||||
----
|
----
|
||||||
// contracts/My721Token.sol
|
include::api:example$utilities/Base64NFT.sol[]
|
||||||
// SPDX-License-Identifier: MIT
|
|
||||||
|
|
||||||
import {ERC721} from "@openzeppelin/contracts/token/ERC721/ERC721.sol";
|
|
||||||
import {Strings} from "@openzeppelin/contracts/utils/Strings.sol";
|
|
||||||
import {Base64} from "@openzeppelin/contracts/utils/Base64.sol";
|
|
||||||
|
|
||||||
contract My721Token is ERC721 {
|
|
||||||
using Strings for uint256;
|
|
||||||
|
|
||||||
constructor() ERC721("My721Token", "MTK") {}
|
|
||||||
|
|
||||||
...
|
|
||||||
|
|
||||||
function tokenURI(uint256 tokenId)
|
|
||||||
public
|
|
||||||
pure
|
|
||||||
override
|
|
||||||
returns (string memory)
|
|
||||||
{
|
|
||||||
bytes memory dataURI = abi.encodePacked(
|
|
||||||
'{',
|
|
||||||
'"name": "My721Token #', tokenId.toString(), '"',
|
|
||||||
// Replace with extra ERC-721 Metadata properties
|
|
||||||
'}'
|
|
||||||
);
|
|
||||||
|
|
||||||
return string(
|
|
||||||
abi.encodePacked(
|
|
||||||
"data:application/json;base64,",
|
|
||||||
Base64.encode(dataURI)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
----
|
----
|
||||||
|
|
||||||
=== Multicall
|
=== Multicall
|
||||||
@ -169,21 +135,7 @@ Consider this dummy contract:
|
|||||||
|
|
||||||
[source,solidity]
|
[source,solidity]
|
||||||
----
|
----
|
||||||
// contracts/Box.sol
|
include::api:example$utilities/Multicall.sol[]
|
||||||
// SPDX-License-Identifier: MIT
|
|
||||||
pragma solidity ^0.8.20;
|
|
||||||
|
|
||||||
import "@openzeppelin/contracts/utils/Multicall.sol";
|
|
||||||
|
|
||||||
contract Box is Multicall {
|
|
||||||
function foo() public {
|
|
||||||
...
|
|
||||||
}
|
|
||||||
|
|
||||||
function bar() public {
|
|
||||||
...
|
|
||||||
}
|
|
||||||
}
|
|
||||||
----
|
----
|
||||||
|
|
||||||
This is how to call the `multicall` function using Ethers.js, allowing `foo` and `bar` to be called in a single transaction:
|
This is how to call the `multicall` function using Ethers.js, allowing `foo` and `bar` to be called in a single transaction:
|
||||||
|
|||||||
Reference in New Issue
Block a user