# 使用Brownie部署合约

By [Yooma](https://paragraph.com/@yooma) · 2022-12-26

---

**关于Brownie的安装测试在**[**这里**](https://mirror.xyz/0x450AF1Ea236932c0e18B53BC1FeB15E47AA292df/VW2cNhU45VQu-7oJBBNkpZUdPcspW2bjvugIPv_AyZs)**已经讲到，本篇着重讲如何部署合约。**

### 一：

**首先在**[**infura**](https://infura.io/dashboard/explorer)**创建一个项目**

![](https://storage.googleapis.com/papyrus_images/d019a56c8371f5e6730aa850c0ed566898acdc92dfa966900f6381ca51cdc30e.png)

![](https://storage.googleapis.com/papyrus_images/763541c8cbacdc904e21d1306d86ce9e8332e831a7a290b2596742e512d82b8e.png)

![](https://storage.googleapis.com/papyrus_images/3a0543ec977258780595a2109dd801ac699c46975ea335c1019054be8930d3c9.png)

### 二：

（如果读过[本篇文章](https://mirror.xyz/0x450AF1Ea236932c0e18B53BC1FeB15E47AA292df/VW2cNhU45VQu-7oJBBNkpZUdPcspW2bjvugIPv_AyZs)的话可以忽略下面这个步骤）

**初始化brownie项目编译合约代码**

1.  执行 brownie init
    
2.  编写合约代码
    
        // SPDX-License-Identifier: MIT
        pragma solidity ^0.8.0;
        
        import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
        import "@openzeppelin/contracts/utils/Counters.sol";
        import "../interfaces/IERC4907.sol";
        
        contract ERC4907 is ERC721, IERC4907 {
            struct UserInfo
            {
                address user;   // address of user role
                uint64 expires; // unix timestamp, user expires
            }
        
            mapping (uint256  => UserInfo) private _users;
        
            constructor()
             ERC721("RentNFTTest","RNT"){
        
             }
        
            /// @notice set the user and expires of a NFT
            /// @dev The zero address indicates there is no user
            /// Throws if `tokenId` is not valid NFT
            /// @param user  The new user of the NFT
            /// @param expires  UNIX timestamp, The new user could use the NFT before expires
            function setUser(uint256 tokenId, address user, uint64 expires) public override virtual{
                // 判断msg.sender是否是该token的owner
                require(_isApprovedOrOwner(msg.sender, tokenId), "ERC4907: transfer caller is not owner nor approved");
        
                // 设置 租赁者以及到期时间
                UserInfo storage info = _users[tokenId];
                info.user = user;
                info.expires = expires;
                // 更新该token的User
                emit UpdateUser(tokenId,user,expires);
            }
        
            /// @notice Get the user address of an NFT
            /// @dev The zero address indicates that there is no user or the user is expired
            /// @param tokenId The NFT to get the user address for
            /// @return The user address for this NFT
            function userOf(uint256 tokenId) public view override virtual returns(address){
                if( uint256(_users[tokenId].expires) >=  block.timestamp){
                    return _users[tokenId].user;
                }
                return address(0);
            }
        
            /// @notice Get the user expires of an NFT
            /// @dev The zero value indicates that there is no user
            /// @param tokenId The NFT to get the user expires for
            /// @return The user expires for this NFT
            function userExpires(uint256 tokenId) public view override virtual returns(uint256){
                return _users[tokenId].expires;
            }
        
            /// @dev See {IERC165-supportsInterface}.
            function supportsInterface(bytes4 interfaceId) public view virtual override(ERC721) returns (bool) {
                return interfaceId == type(IERC4907).interfaceId || super.supportsInterface(interfaceId);
            }
        
            function mint(tokenId) public returns (uint256){
                _safeMint(msg.sender, tokenId);
                return tokenId;
            }
        }
        
    

代码在[这篇文章](https://mirror.xyz/0x450AF1Ea236932c0e18B53BC1FeB15E47AA292df/VW2cNhU45VQu-7oJBBNkpZUdPcspW2bjvugIPv_AyZs)功能测试已经提到，这里直接搬过来用

1.  配置 brownie-config.yaml
    
2.  执行 brownie compile来编译生成abi文件等
    

**在之前的基础上配置brownie-config.yaml**

    dotenv: .env
    networks:  #  指定使用 goerli测试网 WEB3_INFURA_PROJECT_ID是上方infura截图中框出的api_key
      goerli:
        host: https://goerli.infura.io/v3/${WEB3_INFURA_PROJECT_ID}
    wallets:
      PRIVATE_KEY: ${PRIVATE_KEY}   # 钱包地址的私钥，因为比较重要通过导入.env
    

在项目目录中创建一个.env

![](https://storage.googleapis.com/papyrus_images/32181b116970df1444dba1ebfea9172275a02cd43933f873c81b6d6e55bce47a.png)

![](https://storage.googleapis.com/papyrus_images/07c638fe3b380d5b0c35b190dc24b096d25a261985e46b47bd5e76ab76733e60.png)

![在.env中写上私钥和infrua的project_id（api_key）](https://storage.googleapis.com/papyrus_images/500fc3193ff2fa13b81265d39881d295ae2a66a2f853c60838e75624368909d4.png)

在.env中写上私钥和infrua的project\_id（api\_key）

**在 scripts/ 中创建一个脚本 depoly.py**

    
    from brownie import ERC4907, accounts, config
    import brownie
    
    
    def get_account():
        # 要部署到测试网络不在本地，添加账户对象
        # config数据来自brownie-config.yaml
        return accounts.add(config['wallets']['PRIVATE_KEY'])
    
    
    def test_mint(account):
        mint_nft = ERC4907.deploy({'from', account})
        mint_nft.mint(1, {'from': account})
        # 查看mint nft 之后的owner
        print('nft token_id owner/minter:', mint_nft.ownerOf(1))
    
    
    # 一定要有main()函数作为程序的入口
    def main():
        account = get_account()
        print('account=', account)
        test_mint(account)
    

此时执行brownie run scripts/depoly.py

![](https://storage.googleapis.com/papyrus_images/2c81f8946e5ac3aaa69974325897f817352eb0534447aefc5982b37b7cba0594.png)

mint之后可以看到nft的owner是我的账户

查看以下brownie自带的部署的网络，这里使用goerli，如果没有要用到的网络可以自己添加，具体操作可以查看[brownie文档](https://eth-brownie.readthedocs.io/en/latest/network-management.html#adding-a-new-network)

![](https://storage.googleapis.com/papyrus_images/c502592a251e2572962168bce071d7747b572156c189239a7e848f1a412a9bf0.png)

**部署**

**获取测试币**

部署的话需要交gas费，这样需要到goerli的水龙头获取一些测试币

把metamask网络设置成goerli测试网

![](https://storage.googleapis.com/papyrus_images/40217624dc9c4e8b2065b0f636bf87a01b6547817f4de184ea0793a50669c57f.png)

这个地址包含多种获取测试币的方式

[https://faucetlink.to/goerli](https://faucetlink.to/goerli)

这个地址是我看到的给的比较多的

[https://faucets.chain.link/](https://faucets.chain.link/)

然后将此合约部署到以太坊goerli测试网

brownie run scripts/depoly.py --network goerli

![](https://storage.googleapis.com/papyrus_images/87d0077e13d7a642bc5f87e4bae69f093c64aa94f17afecfe3404d82750884df.png)

拿着合约地址到[以太坊测试网](https://goerli.etherscan.io/)查看下

![](https://storage.googleapis.com/papyrus_images/3753eb4f46901a7323e95761c4741c08e8777fa499d92ab9bcc7c5bb2ff75563.png)

第二行记录是创建这个合约的记录

第一行mint记录是depoly.py中mint nft的记录

这样就代表合约部署成功。

---

*Originally published on [Yooma](https://paragraph.com/@yooma/brownie)*
