diff --git a/solidity/contracts/LiquidInfrastructureNFT.sol b/solidity/contracts/LiquidInfrastructureNFT.sol index 0d91bcee..1f068be2 100644 --- a/solidity/contracts/LiquidInfrastructureNFT.sol +++ b/solidity/contracts/LiquidInfrastructureNFT.sol @@ -1,5 +1,5 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.12; +//SPDX-License-Identifier: Apache-2.0 +pragma solidity 0.8.12; // Force solidity compliance import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "@openzeppelin/contracts/token/ERC721/ERC721.sol"; @@ -38,6 +38,12 @@ contract LiquidInfrastructureNFT is ERC721, OwnableApprovableERC721 { address[] private thresholdErc20s; uint256[] private thresholdAmounts; + /** + * @notice This is the current version of the contract. Every update to the contract will introduce a new + * version, regardless of anticipated compatibility. + */ + uint256 public constant Version = 1; + /** * @notice This NFT holds only 1 token in it, which is the Account token. Its Id is `1`. * This Id is used for access control via the onlyOwner/onlyOwnerOrApproved modifiers. diff --git a/solidity/contracts/OwnableApprovableERC721.sol b/solidity/contracts/OwnableApprovableERC721.sol index c972644f..1f124f42 100644 --- a/solidity/contracts/OwnableApprovableERC721.sol +++ b/solidity/contracts/OwnableApprovableERC721.sol @@ -1,4 +1,5 @@ -pragma solidity ^0.8.10; +//SPDX-License-Identifier: Apache-2.0 +pragma solidity 0.8.12; // Force solidity compliance import "@openzeppelin/contracts/utils/Context.sol"; import "@openzeppelin/contracts/token/ERC721/ERC721.sol"; diff --git a/solidity/contracts/TestERC20A.sol b/solidity/contracts/TestERC20A.sol index 41251534..7c5a36b9 100644 --- a/solidity/contracts/TestERC20A.sol +++ b/solidity/contracts/TestERC20A.sol @@ -1,5 +1,5 @@ //SPDX-License-Identifier: Apache-2.0 -pragma solidity ^0.8.10; +pragma solidity 0.8.12; // Force solidity compliance import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; // One of three testing coins diff --git a/solidity/contracts/TestERC20B.sol b/solidity/contracts/TestERC20B.sol index ebb26937..a9ec4ed7 100644 --- a/solidity/contracts/TestERC20B.sol +++ b/solidity/contracts/TestERC20B.sol @@ -1,5 +1,5 @@ //SPDX-License-Identifier: Apache-2.0 -pragma solidity ^0.8.10; +pragma solidity 0.8.12; // Force solidity compliance import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; // One of three testing coins diff --git a/solidity/contracts/TestERC20C.sol b/solidity/contracts/TestERC20C.sol index 9375807a..2236969c 100644 --- a/solidity/contracts/TestERC20C.sol +++ b/solidity/contracts/TestERC20C.sol @@ -1,5 +1,5 @@ //SPDX-License-Identifier: Apache-2.0 -pragma solidity ^0.8.10; +pragma solidity 0.8.12; // Force solidity compliance import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; // One of three testing coins diff --git a/solidity/contracts/TestERC721A.sol b/solidity/contracts/TestERC721A.sol index d3a64ae1..616654fa 100644 --- a/solidity/contracts/TestERC721A.sol +++ b/solidity/contracts/TestERC721A.sol @@ -1,5 +1,5 @@ //SPDX-License-Identifier: Apache-2.0 -pragma solidity ^0.8.10; +pragma solidity 0.8.12; // Force solidity compliance import "@openzeppelin/contracts/token/ERC721/ERC721.sol"; // Generate NFTs with token ids 1-10 and 190-195 diff --git a/x/microtx/keeper/liquid_account.go b/x/microtx/keeper/liquid_account.go index c3404468..66c59141 100644 --- a/x/microtx/keeper/liquid_account.go +++ b/x/microtx/keeper/liquid_account.go @@ -28,6 +28,8 @@ var DefaultGasLimit uint64 = 30000000 // type will cause execution failure var AccountId *big.Int = big.NewInt(1) +var CurrentNFTVersion *big.Int = big.NewInt(1) + // DoLiquify will deploy a LiquidInfrastructureNFT smart contract for the given account. // The token will then be transferred to the given account and live under its control. // Transfer to another owner requires interacting with the EVM @@ -58,6 +60,14 @@ func (k Keeper) deployLiquidInfrastructureNFTContract(ctx sdk.Context, account s return common.Address{}, sdkerrors.Wrap(err, "liquid infrastructure account contract deployment failed") } + version, err := k.queryLiquidInfrastructureContractVersion(ctx, contract) + if err != nil { + return common.Address{}, sdkerrors.Wrap(err, "could not query NFT version") + } + if version.Cmp(CurrentNFTVersion) != 0 { + return common.Address{}, sdkerrors.Wrapf(err, "expected contract with version %v, got %v", CurrentNFTVersion, version) + } + _, err = k.transferLiquidInfrastructureNFTFromModuleToAddress(ctx, contract, account) if err != nil { return common.Address{}, sdkerrors.Wrapf(err, "could not transfer nft from %v to %v", types.ModuleEVMAddress.Hex(), SDKToEVMAddress(account).Hex()) @@ -103,6 +113,17 @@ func (k Keeper) queryLiquidInfrastructureOwner(ctx sdk.Context, nftAddress commo return &owner, nil } +// queryLiquidInfrastructureContractVersion fetches the `Version()` of the LiquidInfrastructureNFT deployed at `nftAddress` +func (k Keeper) queryLiquidInfrastructureContractVersion(ctx sdk.Context, nftAddress common.Address) (*big.Int, error) { + // ABI: uint256 public constant Version + res, err := k.QueryEVM(ctx, "Version", types.LiquidInfrastructureNFT, types.ModuleEVMAddress, &nftAddress) + if err != nil { + return nil, sdkerrors.Wrap(err, "unable to call Versionw with no args") + } + version := big.NewInt(0).SetBytes(res.Ret) + return version, nil +} + // queryLiquidInfrastructureThresholds is used by the module to control liquid infrastructure account balances, it calls the // LiquidInfrastructureNFT getThresholds() function and formats the output into a useable type func (k Keeper) queryLiquidInfrastructureThresholds(ctx sdk.Context, nftAddress common.Address) ([]types.LiquidAccountThreshold, error) { diff --git a/x/microtx/types/errors.go b/x/microtx/types/errors.go index 33c0994c..961e6e64 100644 --- a/x/microtx/types/errors.go +++ b/x/microtx/types/errors.go @@ -10,4 +10,5 @@ var ( ErrNoLiquidAccount = sdkerrors.Register(ModuleName, 3, "account is not a liquid infrastructure account") ErrInvalidThresholds = sdkerrors.Register(ModuleName, 4, "invalid liquid infrastructure account thresholds") ErrInvalidMicrotx = sdkerrors.Register(ModuleName, 5, "invalid microtx") + ErrInvalidContract = sdkerrors.Register(ModuleName, 6, "invalid contract") )