Skip to content

Commit

Permalink
add tests, comments
Browse files Browse the repository at this point in the history
  • Loading branch information
loic1 committed Feb 11, 2025
1 parent a29f2ab commit a2d7e50
Show file tree
Hide file tree
Showing 2 changed files with 74 additions and 59 deletions.
104 changes: 45 additions & 59 deletions evm-bridging/README.md
Original file line number Diff line number Diff line change
@@ -1,113 +1,99 @@
# <h1 align="center"> NBA TopShot on FlowEVM [Initial Draft Version] </h1>

**! This directory currently contains work in progress only !**
# <h1 align="center"> NBA TopShot on FlowEVM </h1>

## Introduction

The `BridgedTopShotMoments` smart contract facilitates the creation of 1:1 ERC721 references for existing Cadence-native NBA Top Shot moments. By associating these references with the same metadata, it ensures seamless integration and interaction between Cadence and FlowEVM environments. This allows users to enjoy the benefits of both ecosystems while maintaining the integrity and uniqueness of their NBA Top Shot moments.
The `BridgedTopShotMoments` smart contract enables NBA Top Shot moments to exist on FlowEVM as ERC721 tokens. Each ERC721 token is a 1:1 reference to a Cadence-native NBA Top Shot moment, maintaining the same metadata and uniqueness while allowing users to leverage both Flow and EVM ecosystems.


## Getting Started
## Prerequisites

Install Foundry:
1. Install Foundry:

```sh
curl -L https://foundry.paradigm.xyz | bash
foundryup
```

Compile contracts and run tests:
2. Install Flow CLI: [Instructions](https://developers.flow.com/tools/flow-cli/install)

## Development

1. Compile and test contracts:

```sh
forge test --force -vvv
```

Install Flow CLI: [Instructions](https://developers.flow.com/tools/flow-cli/install)

### Deploy & Verify Contracts
2. Set up environment:

Load environment variables after populating address and key details:

```sh
cp .env.example.testnet .env
# Add your account details to .env and source it
source .env
```

Run script to deploy and verify contracts (proxy and implementation):
3. Deploy and verify contracts:

```sh
# Deploy both proxy and implementation contracts
forge script --rpc-url $RPC_URL --private-key $DEPLOYER_PRIVATE_KEY --legacy script/Deploy.s.sol:DeployScript --broadcast --verify --verifier $VERIFIER_PROVIDER --verifier-url $VERIFIER_URL
```

If verification fails for one or both contracts, verify separately:

```sh
# If verification fails, verify individually
forge verify-contract --rpc-url $RPC_URL --verifier $VERIFIER_PROVIDER --verifier-url $VERIFIER_URL <address-of-contract-to-verify>
```

## Run Transactions
## Usage

### Direct EVM Calls

Set NFT symbol (admin):
### EVM Operations

```sh
cast send $DEPLOYED_PROXY_CONTRACT_ADDRESS --rpc-url $RPC_URL --private-key $DEPLOYER_PRIVATE_KEY --legacy "setSymbol(string)" <new-nft-symbol>
```
# Approve operator for a NFT
cast send $DEPLOYED_PROXY_CONTRACT_ADDRESS --rpc-url $RPC_URL --private-key <private-key> --legacy "approve(address,uint256)" <operator-address> <token-id>

### EVM Calls From Cadence
# Approve operator for all NFTs
cast send $DEPLOYED_PROXY_CONTRACT_ADDRESS --rpc-url $RPC_URL --private-key <private-key> --legacy "setApprovalForAll(address,bool)" <operator-address> <true>

Note: Populate arguments in json file before submitting the transactions.
# Transfer NFT
cast send $DEPLOYED_PROXY_CONTRACT_ADDRESS --rpc-url $RPC_URL --private-key <private-key> --legacy "safeTransferFrom(address,address,uint256)" <from-address> <to-address> <token-id>

Bridge NFTs to EVM and wrap:
# Query balance
cast call $DEPLOYED_PROXY_CONTRACT_ADDRESS --rpc-url $RPC_URL "balanceOf(address)(uint256)" $DEPLOYER_ADDRESS

```sh
flow transactions send ./cadence/transactions/bridge_nfts_to_evm_and_wrap.cdc --args-json "$(cat ./cadence/transactions/bridge_nft_to_evm_and_wrap_args.json)" --network <network> --signer <signer> --gas-limit 8000
```
# Query owner
cast call $DEPLOYED_PROXY_CONTRACT_ADDRESS --rpc-url $RPC_URL "ownerOf(uint256)(address)" <nft-id>

Wrap NFTs (NFTs already bridged to EVM):
# Query token URI
cast call $DEPLOYED_PROXY_CONTRACT_ADDRESS --rpc-url $RPC_URL "tokenURI(uint256)(string)" <nft-id>

```sh
flow transactions send ./cadence/transactions/wrap_nfts.cdc --args-json "$(cat ./cadence/transactions/wrap_nfts_args.json)" --network <network> --signer <signer>
# Set NFT symbol (admin only)
cast send $DEPLOYED_PROXY_CONTRACT_ADDRESS --rpc-url $RPC_URL --private-key $DEPLOYER_PRIVATE_KEY --legacy "setSymbol(string)" <new-nft-symbol>
```

Unwrap NFTs and Bridge NFTs from EVM:

```sh
flow transactions send ./cadence/transactions/unwrap_nfts_and_bridge_from_evm.cdc --args-json "$(cat ./cadence/transactions/unwrap_nfts_and_bridge_from_evm_args.json)" --network <network> --signer <signer> --gas-limit 8000
```
### Cadence Operations

Unwrap NFTs:
> **Note**: Populate arguments in json file before submitting the transactions.
```sh
flow transactions send ./cadence/transactions/unwrap_nfts.cdc --args-json "$(cat ./cadence/transactions/unwrap_nfts_args.json)" --network <network> --signer <signer>
```



## Execute Queries

### Direct EVM Calls
# Bridge and wrap NFTs
flow transactions send ./cadence/transactions/bridge_nfts_to_evm_and_wrap.cdc --args-json "$(cat ./cadence/transactions/bridge_nft_to_evm_and_wrap_args.json)" --network <network> --signer <signer> --gas-limit 8000

BalanceOf:
```sh
cast call $DEPLOYED_PROXY_CONTRACT_ADDRESS --rpc-url $RPC_URL "balanceOf(address)(uint256)" $DEPLOYER_ADDRESS
```
# Wrap already-bridged NFTs
flow transactions send ./cadence/transactions/wrap_nfts.cdc --args-json "$(cat ./cadence/transactions/wrap_nfts_args.json)" --network <network> --signer <signer>

OwnerOf:
```sh
cast call $DEPLOYED_PROXY_CONTRACT_ADDRESS --rpc-url $RPC_URL "ownerOf(uint256)(address)" <nft-id>
```
# Unwrap and bridge back NFTs
flow transactions send ./cadence/transactions/unwrap_nfts_and_bridge_from_evm.cdc --args-json "$(cat ./cadence/transactions/unwrap_nfts_and_bridge_from_evm_args.json)" --network <network> --signer <signer> --gas-limit 8000

### EVM Calls From Cadence
# Unwrap NFTs
flow transactions send ./cadence/transactions/unwrap_nfts.cdc --args-json "$(cat ./cadence/transactions/unwrap_nfts_args.json)" --network <network> --signer <signer>

```sh
# Query ERC721 address
flow scripts execute ./evm-bridging/cadence/scripts/get_underlying_erc721_address.cdc <nft_contract_flow_address> <nft_contract_evm_address> --network testnet
```

## Misc

Fund testnet Flow EVM account:
### Testnet Setup

1. Use Flow Faucet: https://faucet.flow.com/fund-account
1. Get testnet FLOW from [Flow Faucet](https://faucet.flow.com/fund-account)

2. Transfer FLOW to EVM address:

Expand Down
29 changes: 29 additions & 0 deletions evm-bridging/test/BridgedTopShotMoments.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,16 @@ import {Strings} from "openzeppelin-contracts/contracts/utils/Strings.sol";
import {CrossVMBridgeERC721FulfillmentUpgradeable} from "../src/lib/CrossVMBridgeERC721FulfillmentUpgradeable.sol";
import {CrossVMBridgeCallableUpgradeable} from "../src/lib/CrossVMBridgeCallableUpgradeable.sol";

import {IERC721} from "@openzeppelin/contracts/interfaces/IERC721.sol";
import {IERC721Metadata} from "@openzeppelin/contracts/interfaces/IERC721Metadata.sol";
import {IERC721Enumerable} from "@openzeppelin/contracts/interfaces/IERC721Enumerable.sol";
import {ICrossVMBridgeERC721Fulfillment} from "../src/interfaces/ICrossVMBridgeERC721Fulfillment.sol";
import {ICrossVM} from "../src/interfaces/ICrossVM.sol";
import {ICreatorToken, ILegacyCreatorToken} from "../src/interfaces/ICreatorToken.sol";
import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
import {IERC2981} from "@openzeppelin/contracts/interfaces/IERC2981.sol";
import {IBridgePermissions} from "../src/interfaces/IBridgePermissions.sol";

// Add this minimal ERC721 implementation for testing
contract UnderlyingERC721 is ERC721, Ownable {
constructor(string memory name, string memory symbol) ERC721(name, symbol) Ownable(msg.sender) {}
Expand Down Expand Up @@ -86,6 +96,21 @@ contract BridgedTopShotMomentsTest is Test {
nftContract = BridgedTopShotMoments(proxyAddr);
}

/* Test interface implementations */

function test_SupportsInterface() public view {
assertEq(nftContract.supportsInterface(type(IERC165).interfaceId), true);
assertEq(nftContract.supportsInterface(type(IERC721).interfaceId), true);
assertEq(nftContract.supportsInterface(type(IERC721Metadata).interfaceId), true);
assertEq(nftContract.supportsInterface(type(IERC721Enumerable).interfaceId), true);
assertEq(nftContract.supportsInterface(type(ICrossVM).interfaceId), true);
assertEq(nftContract.supportsInterface(type(ICreatorToken).interfaceId), true);
assertEq(nftContract.supportsInterface(type(ILegacyCreatorToken).interfaceId), true);
assertEq(nftContract.supportsInterface(type(IERC2981).interfaceId), true);
assertEq(nftContract.supportsInterface(type(ICrossVMBridgeERC721Fulfillment).interfaceId), true);
assertEq(nftContract.supportsInterface(type(IBridgePermissions).interfaceId), true);
}

/* Test contract initialization */

function test_GetContractInfo() public view {
Expand All @@ -96,6 +121,10 @@ contract BridgedTopShotMomentsTest is Test {
assertEq(nftContract.getCadenceIdentifier(), cadenceNFTIdentifier);
assertEq(nftContract.contractURI(), contractURI);
assertEq(address(nftContract.underlying()), underlyingNftContractAddress);
assertEq(nftContract.vmBridgeAddress(), vmBridgeAddress);
assertEq(nftContract.getTransferValidator(), address(0));
assertEq(nftContract.royaltyAddress(), address(0));
assertEq(nftContract.royaltyBasisPoints(), 0);
}


Expand Down

0 comments on commit a2d7e50

Please sign in to comment.