Skip to content

Commit

Permalink
Update tutorials to the latest version of toolkit (#173)
Browse files Browse the repository at this point in the history
  • Loading branch information
fadeev authored Oct 10, 2023
1 parent fc91e08 commit c58d7d1
Show file tree
Hide file tree
Showing 13 changed files with 426 additions and 755 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,8 @@ This is an example app of cross-chain counter using

```
git clone https://github.com/zeta-chain/template
```

Install the dependencies:

```
yarn add --dev @openzeppelin/contracts
cd template
yarn
```

## Create a new contract
Expand All @@ -42,20 +38,18 @@ import "@openzeppelin/contracts/access/Ownable.sol";
import "@zetachain/protocol-contracts/contracts/evm/tools/ZetaInteractor.sol";
import "@zetachain/protocol-contracts/contracts/evm/interfaces/ZetaInterfaces.sol";
interface CounterErrors {
contract Counter is ZetaInteractor, ZetaReceiver {
error InvalidMessageType();
// highlight-next-line
error DecrementOverflow();
}
contract Counter is ZetaInteractor, ZetaReceiver, CounterErrors {
bytes32 public constant COUNTER_MESSAGE_TYPE =
keccak256("CROSS_CHAIN_COUNTER");
event CounterEvent(address);
event CounterRevertedEvent(address);
// highlight-next-line
mapping(address => uint256) public counter;
bytes32 public constant COUNTER_MESSAGE_TYPE =
keccak256("CROSS_CHAIN_COUNTER");
ZetaTokenConsumer private immutable _zetaConsumer;
IERC20 internal immutable _zetaToken;
Expand All @@ -79,7 +73,6 @@ contract Counter is ZetaInteractor, ZetaReceiver, CounterErrors {
}(address(this), crossChainGas);
_zetaToken.approve(address(connector), zetaValueAndGas);
counter[msg.sender]++;
connector.send(
ZetaInterfaces.SendInput({
destinationChainId: destinationChainId,
Expand Down Expand Up @@ -129,7 +122,7 @@ contract Counter is ZetaInteractor, ZetaReceiver, CounterErrors {

## Create a task to get the counter value

```solidity title="tasks/counter_show.ts"
```ts title="tasks/counter_show.ts"
import { task } from "hardhat/config";
import { HardhatRuntimeEnvironment } from "hardhat/types";

Expand Down Expand Up @@ -162,22 +155,44 @@ import "./tasks/counter_show.ts";
## Create a task to increment the counter value

```ts title="tasks/interact.ts"
import { task } from "hardhat/config";
import { HardhatRuntimeEnvironment } from "hardhat/types";
import { parseEther } from "@ethersproject/units";

const main = async (args: any, hre: HardhatRuntimeEnvironment) => {
const [signer] = await hre.ethers.getSigners();

const factory = await hre.ethers.getContractFactory("Counter");
const contract = factory.attach(args.contract);

const destination = hre.config.networks[args.destination]?.chainId;
if (destination === undefined) {
throw new Error(`${args.destination} is not a valid destination chain`);
}

// remove-next-line
const paramFrom = hre.ethers.utils.getAddress(args.from);

const value = parseEther(args.amount);

const tx = await contract
.connect(signer)
// highlight-next-line
.sendMessage(destination, { value: parseEther(args.amount) });
.sendMessage(destination, { value });

const receipt = await tx.wait();
console.log(`✅ The transaction has been broadcasted to ${hre.network.name}
if (args.json) {
console.log(JSON.stringify(tx, null, 2));
} else {
console.log(`🔑 Using account: ${signer.address}\n`);
console.log(`✅ The transaction has been broadcasted to ${hre.network.name}
📝 Transaction hash: ${receipt.transactionHash}
`);
await trackCCTX(tx.hash);
}
};

task("interact", "Sends a message from one chain to another.", main)
.addFlag("json", "Output JSON")
.addParam("contract", "Contract address")
.addParam("amount", "Token amount to send")
.addParam("destination", "Destination chain")
Expand Down
78 changes: 34 additions & 44 deletions docs/developers/cross-chain-messaging/examples/cross-chain-nft.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,12 @@ capabilities using

![Cross-chain NFT transfer](/img/graphs/cross-chain-nft-transfer.svg)

## Set Up Your Environment
## Set up your environment

```
git clone https://github.com/zeta-chain/template
```

Install dependencies:

```
cd template
yarn add --dev @openzeppelin/contracts
yarn
```

## Create a new contract
Expand All @@ -47,41 +42,38 @@ pragma solidity 0.8.7;
import "@openzeppelin/contracts/interfaces/IERC20.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@zetachain/protocol-contracts/contracts/evm/tools/ZetaInteractor.sol";
import "@zetachain/protocol-contracts/contracts/evm/interfaces/ZetaInterfaces.sol";
// highlight-start
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/utils/Counters.sol";
// highlight-end
import "@zetachain/protocol-contracts/contracts/evm/tools/ZetaInteractor.sol";
import "@zetachain/protocol-contracts/contracts/evm/interfaces/ZetaInterfaces.sol";
interface CrossChainWarriorsErrors {
error InvalidMessageType();
}
contract CrossChainWarriors is
ZetaInteractor,
ZetaReceiver,
CrossChainWarriorsErrors,
// highlight-next-line
ERC721("CrossChainWarriors", "CCWAR")
{
// highlight-next-line
using Counters for Counters.Counter;
bytes32 public constant CROSS_CHAIN_WARRIORS_MESSAGE_TYPE =
keccak256("CROSS_CHAIN_CROSS_CHAIN_WARRIORS");
error InvalidMessageType();
event CrossChainWarriorsEvent(uint256, address, address);
event CrossChainWarriorsRevertedEvent(uint256, address, address);
// highlight-start
using Counters for Counters.Counter;
Counters.Counter public tokenIds;
// highlight-end
bytes32 public constant CROSS_CHAIN_WARRIORS_MESSAGE_TYPE =
keccak256("CROSS_CHAIN_CROSS_CHAIN_WARRIORS");
ZetaTokenConsumer private immutable _zetaConsumer;
IERC20 internal immutable _zetaToken;
// highlight-next-line
Counters.Counter public tokenIds;
constructor(
address connectorAddress,
address zetaTokenAddress,
address zetaConsumerAddress,
// highlight-next-line
bool useEven
) ZetaInteractor(connectorAddress) {
_zetaToken = IERC20(zetaTokenAddress);
Expand Down Expand Up @@ -111,16 +103,12 @@ contract CrossChainWarriors is
function _burnWarrior(uint256 burnedWarriorId) internal {
_burn(burnedWarriorId);
}
// highlight-end
function sendMessage(
uint256 destinationChainId,
uint256 token,
// remove-next-line
address sender,
address to
) external payable {
if (!_isValidChainId(destinationChainId))
revert InvalidDestinationChainId();
Expand All @@ -138,7 +126,7 @@ contract CrossChainWarriors is
ZetaInterfaces.SendInput({
destinationChainId: destinationChainId,
destinationAddress: interactorsByChainId[destinationChainId],
destinationGasLimit: 500000,
destinationGasLimit: 300000,
message: abi.encode(
CROSS_CHAIN_WARRIORS_MESSAGE_TYPE,
token,
Expand Down Expand Up @@ -197,14 +185,15 @@ Introduce a new state variable by leveraging the `Counters.Counter` data
structure. Name this variable `tokenIds`. This state variable will be used to
manage unique IDs for the ERC721 tokens that the contract will mint.

Modify the constructor of the contract to incorporate the changes. It's
important that the `tokenIds` counter is incremented twice when the contract is
deployed. This action guarantees unique IDs for the initial tokens.
Modify the constructor of the contract to accept a new parameter `bool useEven`.
This parameter will be used to determine the parity of NFT IDs on different
chains: even IDs on one chain and odd IDs on another. This action guarantees
unique IDs for the initial tokens.

Furthermore, incorporate a series of new functions to extend the contract's
functionalities:

- Introduce a `mint(address to)`` function, a public-facing method that allows
- Introduce a `mint(address to)` function, a public-facing method that allows
minting a new ERC721 token to a specified address and returns the ID of the
newly minted token. Remember to increment the tokenIds counter twice within
this function to ensure unique IDs.
Expand Down Expand Up @@ -240,7 +229,7 @@ function on it, searches the events for a "Transfer" event and prints out the
token ID.

```ts title="tasks/mint.ts" reference
https://github.com/zeta-chain/example-contracts/blob/feat/import-toolkit/messaging/warriors/tasks/mint.ts
https://github.com/zeta-chain/example-contracts/blob/main/messaging/warriors/tasks/mint.ts
```

```ts title="hardhat.config.ts"
Expand All @@ -259,13 +248,12 @@ const paramSender = hre.ethers.utils.getAddress(args.sender);
const tx = await contract
.connect(signer)
// highlight-next-line
.sendMessage(destination, paramToken, paramTo, {
value: parseEther(args.amount),
});
.sendMessage(destination, paramToken, paramTo, { value });

//...

task("interact", "Sends a message from one chain to another.", main)
.addFlag("json", "Output JSON")
.addParam("contract", "Contract address")
.addParam("amount", "Token amount to send")
.addParam("destination", "Destination chain")
Expand All @@ -275,10 +263,6 @@ task("interact", "Sends a message from one chain to another.", main)
.addParam("to", "address");
```

```
npx hardhat transfer --network goerli --contract 0xFeAF74733B6f046F3d609e663F667Ba61B19A148 --address 0x2cD3D070aE1BD365909dD859d29F387AA96911e1 --destination 97 --token 2 --amount 0.4
```

## Update the Deploy Task

Modify the deploy task by adding a new argument `parity` and passing it to the
Expand All @@ -288,35 +272,41 @@ of NFT IDs on different chains: even IDs on one chain and odd IDs on another.
```ts title="tasks/deploy.ts"
const main = async (args: any, hre: HardhatRuntimeEnvironment) => {
const networks = args.networks.split(",");
// A mapping between network names and deployed contract addresses.
const contracts: { [key: string]: string } = {};
await Promise.all(
// highlight-start
networks.map(async (networkName: string, i: number) => {
const parity = i % 2 == 0;
contracts[networkName] = await deployContract(hre, networkName, parity);
contracts[networkName] = await deployContract(
hre,
networkName,
parity,
args.json,
args.gasLimit
);
})
// highlight-end
);

for (const source in contracts) {
await setInteractors(hre, source, contracts);
}
// ...
};

const deployContract = async (
hre: HardhatRuntimeEnvironment,
networkName: string,
// highlight-next-line
parity: boolean
parity: boolean,
json: boolean = false,
gasLimit: number
) => {
//...
const contract = await factory.deploy(
connector,
zetaToken,
zetaTokenConsumerUniV2 || zetaTokenConsumerUniV3,
// highlight-next-line
parity
parity,
{ gasLimit }
);
//...
};
Expand Down
Loading

0 comments on commit c58d7d1

Please sign in to comment.