-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: nft - sample usage of hedera hts forking in hardhat and foundry…
… when testing nft (#191) Signed-off-by: Mariusz Jasuwienas <mariusz.jasuwienas@arianelabs.com>
- Loading branch information
1 parent
8533630
commit 5d8b6f7
Showing
11 changed files
with
420 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
// SPDX-License-Identifier: Apache-2.0 | ||
pragma solidity ^0.8.0; | ||
|
||
import {Test} from "forge-std/Test.sol"; | ||
import {htsSetup} from "hedera-forking/contracts/htsSetup.sol"; | ||
import {IERC721} from "hedera-forking/contracts/IERC721.sol"; | ||
|
||
contract NFTExampleTest is Test { | ||
// https://hashscan.io/mainnet/token/0.0.4970613 | ||
address NFT_mainnet = 0x00000000000000000000000000000000004Bd875; | ||
|
||
address private user; | ||
|
||
function setUp() external { | ||
htsSetup(); | ||
|
||
user = makeAddr("user"); | ||
deal(NFT_mainnet, user, 3); | ||
} | ||
|
||
function test_get_owner_of_existing_account() view external { | ||
assertNotEq(IERC721(NFT_mainnet).ownerOf(1), address(0)); | ||
} | ||
|
||
function test_dealt_nft_assigned_to_local_account() view external { | ||
assertEq(IERC721(NFT_mainnet).ownerOf(3), user); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
// SPDX-License-Identifier: Apache-2.0 | ||
pragma solidity ^0.8.0; | ||
|
||
import {Test, console} from "forge-std/Test.sol"; | ||
import {htsSetup} from "hedera-forking/contracts/htsSetup.sol"; | ||
import {IERC721} from "hedera-forking/contracts/IERC721.sol"; | ||
|
||
contract NFTConsoleExampleTest is Test { | ||
function setUp() external { | ||
htsSetup(); | ||
} | ||
|
||
function test_using_console_log() view external { | ||
// https://hashscan.io/mainnet/token/0.0.4970613 | ||
address NFT_mainnet = 0x00000000000000000000000000000000004Bd875; | ||
|
||
string memory name = IERC721(NFT_mainnet).name(); | ||
string memory symbol = IERC721(NFT_mainnet).symbol(); | ||
string memory tokenURI = IERC721(NFT_mainnet).tokenURI(1); | ||
assertEq(name, "Concierge Collectibles"); | ||
assertEq(symbol, "Concierge Collectibles"); | ||
assertEq(tokenURI, "ipfs://QmVtsRvgZkqbBr5h5NB17LntAWC9DgXToLTLhNKCzB9RHZ"); | ||
console.log("name: %s, symbol: %s, tokenURI: %s", name, symbol, tokenURI); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
// SPDX-License-Identifier: Apache-2.0 | ||
pragma solidity ^0.8.0; | ||
|
||
import {IERC721} from "./IERC721.sol"; | ||
import {console} from "hardhat/console.sol"; | ||
|
||
contract CallNFT { | ||
function getTokenName(address tokenAddress) external view returns (string memory) { | ||
return IERC721(tokenAddress).name(); | ||
} | ||
|
||
function invokeTransferFrom(address tokenAddress, address to, uint256 serialId) external { | ||
// You can use `console.log` as usual | ||
// https://hardhat.org/tutorial/debugging-with-hardhat-network#solidity--console.log | ||
console.log("Transferring from %s to %s %s tokens", msg.sender, to, serialId); | ||
address owner = IERC721(tokenAddress).ownerOf(serialId); | ||
IERC721(tokenAddress).transferFrom(owner, to, serialId); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
// SPDX-License-Identifier: Apache-2.0 | ||
pragma solidity ^0.8.0; | ||
|
||
/** | ||
* See https://ethereum.org/en/developers/docs/standards/tokens/erc-721/#events for more information. | ||
*/ | ||
interface IERC721Events { | ||
event ApprovalForAll(address indexed owner, address indexed operator, bool approved); | ||
} | ||
|
||
/** | ||
* This interface is used to get the selectors and for testing. | ||
* | ||
* https://hips.hedera.com/hip/hip-218 | ||
* https://hips.hedera.com/hip/hip-376 | ||
*/ | ||
interface IERC721 { | ||
/** | ||
* @dev Returns the token collection name. | ||
*/ | ||
function name() external view returns (string memory); | ||
|
||
/** | ||
* @dev Returns the token collection symbol. | ||
*/ | ||
function symbol() external view returns (string memory); | ||
|
||
/** | ||
* @dev Returns the Uniform Resource Identifier (URI) for `serialId` token. | ||
*/ | ||
function tokenURI(uint256 serialId) external view returns (string memory); | ||
|
||
/** | ||
* @dev Returns the total amount of tokens stored by the contract. | ||
*/ | ||
function totalSupply() external view returns (uint256); | ||
|
||
/** | ||
* @dev Returns the number of tokens in `owner`'s account. | ||
*/ | ||
function balanceOf(address owner) external view returns (uint256 balance); | ||
|
||
/** | ||
* @dev Returns the owner of the `serialId` token. | ||
* | ||
* Requirements: | ||
* - `serialId` must exist. | ||
*/ | ||
function ownerOf(uint256 serialId) external view returns (address); | ||
|
||
/** | ||
* @dev Transfers `serialId` token from `sender` to `recipient`. | ||
* | ||
* Requirements: | ||
* - `sender` cannot be the zero address. | ||
* - `recipient` cannot be the zero address. | ||
* - `serialId` token must be owned by `sender`. | ||
* - If the caller is not `sender`, it must be approved to move this token by either {approve} or {setApprovalForAll}. | ||
* | ||
* Emits a {Transfer} event. | ||
*/ | ||
function transferFrom(address sender, address recipient, uint256 serialId) external payable; | ||
|
||
/** | ||
* @dev Gives permission to `spender` to transfer `serialId` token to another account. | ||
* The approval is cleared when the token is transferred. | ||
* | ||
* Only a single account can be approved at a time, so approving the zero address clears previous approvals. | ||
* | ||
* Requirements: | ||
* - The caller must own the token or be an approved operator. | ||
* - `serialId` must exist. | ||
* | ||
* Emits an {Approval} event. | ||
*/ | ||
function approve(address spender, uint256 serialId) external payable; | ||
|
||
/** | ||
* @dev Approve or remove `operator` as an operator for the caller. | ||
* Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller. | ||
* | ||
* Requirements: | ||
* - The `operator` cannot be the address zero. | ||
* | ||
* Emits an {ApprovalForAll} event. | ||
*/ | ||
function setApprovalForAll(address operator, bool approved) external; | ||
|
||
/** | ||
* @dev Returns the account approved for `serialId` token. | ||
* | ||
* Requirements: | ||
* - `serialId` must exist. | ||
*/ | ||
function getApproved(uint256 serialId) external view returns (address operator); | ||
|
||
/** | ||
* @dev Returns if the `operator` is allowed to manage all of the assets of `owner`. | ||
* | ||
* See {setApprovalForAll} | ||
*/ | ||
function isApprovedForAll(address owner, address operator) external view returns (bool); | ||
} |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
/*- | ||
* Hedera Hardhat Forking Plugin | ||
* | ||
* Copyright (C) 2024 Hedera Hashgraph, LLC | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
const { expect } = require('chai'); | ||
// prettier-ignore | ||
const { ethers: { getContractAt } } = require('hardhat'); | ||
|
||
describe('NFT example -- informational', function () { | ||
it('should get name and symbol', async function () { | ||
// https://hashscan.io/mainnet/token/0.0.4970613 | ||
const nft = await getContractAt('IERC721', '0x00000000000000000000000000000000004bd875'); | ||
expect(await nft['name']()).to.be.equal('Concierge Collectibles'); | ||
expect(await nft['symbol']()).to.be.equal('Concierge Collectibles'); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
/*- | ||
* Hedera Hardhat Forking Plugin | ||
* | ||
* Copyright (C) 2024 Hedera Hashgraph, LLC | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
const { expect } = require('chai'); | ||
// prettier-ignore | ||
const { ethers: { getContractAt } } = require('hardhat'); | ||
|
||
describe('NFT example -- ownerOf', function () { | ||
it('should get `ownerOf` account holder', async function () { | ||
// https://hashscan.io/mainnet/token/0.0.4970613 | ||
const nft = await getContractAt('IERC721', '0x00000000000000000000000000000000004bd875'); | ||
expect(await nft['ownerOf'](1)).to.not.be.equal( | ||
'0x0000000000000000000000000000000000000000' | ||
); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
/*- | ||
* Hedera Hardhat Forking Plugin | ||
* | ||
* Copyright (C) 2024 Hedera Hashgraph, LLC | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
const { expect } = require('chai'); | ||
// prettier-ignore | ||
const { ethers: { getSigner, getSigners, getContractAt }, network: { provider } } = require('hardhat'); | ||
const { loadFixture } = require('@nomicfoundation/hardhat-toolbox/network-helpers'); | ||
|
||
describe('NFT example -- transferFrom', function () { | ||
async function id() { | ||
return [(await getSigners())[0]]; | ||
} | ||
|
||
it("should `transferFrom` tokens from account holder to one of Hardhat' signers", async function () { | ||
const [receiver] = await loadFixture(id); | ||
|
||
// https://hashscan.io/mainnet/token/0.0.4970613 | ||
const nft = await getContractAt('IERC721', '0x00000000000000000000000000000000004bd875'); | ||
|
||
const holderAddress = await nft['ownerOf'](1n); | ||
|
||
await provider.request({ | ||
method: 'hardhat_impersonateAccount', | ||
params: [holderAddress], | ||
}); | ||
|
||
const holder = await getSigner(holderAddress); | ||
await nft.connect(holder)['transferFrom'](holder, receiver, 1n); | ||
|
||
expect(await nft['ownerOf'](1n)).to.be.equal(receiver.address); | ||
}); | ||
}); |
Oops, something went wrong.