diff --git a/base/baseInteractions.go b/base/baseInteractions.go index 434914c..c6522d6 100644 --- a/base/baseInteractions.go +++ b/base/baseInteractions.go @@ -59,6 +59,10 @@ func NewBaseInteractions(client simulated.Client, pk *ecdsa.PrivateKey, explorer return &BaseInteractions{ctx, client, fromAddress, pk, nil, explorer} } +func (b *BaseInteractions) BaseInteractions() *BaseInteractions { + return b +} + // SetDisperse initializes the disperse contract for multi-address fund transfers. func (b *BaseInteractions) SetDisperse(address string) error { var err error diff --git a/base/models.go b/base/models.go new file mode 100644 index 0000000..df7252c --- /dev/null +++ b/base/models.go @@ -0,0 +1,34 @@ +package base + +import ( + "github.com/Thektonic/eth-interfaces/inferences/ERC20Burnable" + "github.com/Thektonic/eth-interfaces/inferences/ERC721A" + "github.com/Thektonic/eth-interfaces/inferences/ERC721Complete" + "github.com/Thektonic/eth-interfaces/inferences/nftPositionManager" + "github.com/ethereum/go-ethereum/common" +) + +type Interactions[ + T *nftPositionManager.NftPositionManagerSession | + *ERC721A.ERC721ASession | + *ERC721Complete.ERC721CompleteSession | + *ERC20Burnable.ERC20BurnableSession, +] struct { + *BaseInteractions + Session T + Address common.Address + CallError func(string, error) *CallError +} + +// GetNFTAddress returns the NFT contract address. +func (d *Interactions[T]) GetAddress() common.Address { + return d.Address +} + +func (d *Interactions[T]) GetSession() T { + return d.Session +} + +func (d *Interactions[T]) GetBaseInteractions() *BaseInteractions { + return d.BaseInteractions +} diff --git a/build/INonfungiblePositionManager.abi b/build/INonfungiblePositionManager.abi new file mode 100644 index 0000000..c29b848 --- /dev/null +++ b/build/INonfungiblePositionManager.abi @@ -0,0 +1 @@ +[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":false,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount0","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount1","type":"uint256"}],"name":"Collect","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":false,"internalType":"uint128","name":"liquidity","type":"uint128"},{"indexed":false,"internalType":"uint256","name":"amount0","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount1","type":"uint256"}],"name":"DecreaseLiquidity","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":false,"internalType":"uint128","name":"liquidity","type":"uint128"},{"indexed":false,"internalType":"uint256","name":"amount0","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount1","type":"uint256"}],"name":"IncreaseLiquidity","type":"event"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"burn","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint128","name":"amount0Max","type":"uint128"},{"internalType":"uint128","name":"amount1Max","type":"uint128"}],"internalType":"struct INonfungiblePositionManager.CollectParams","name":"params","type":"tuple"}],"name":"collect","outputs":[{"internalType":"uint256","name":"amount0","type":"uint256"},{"internalType":"uint256","name":"amount1","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint128","name":"liquidity","type":"uint128"},{"internalType":"uint256","name":"amount0Min","type":"uint256"},{"internalType":"uint256","name":"amount1Min","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"internalType":"struct INonfungiblePositionManager.DecreaseLiquidityParams","name":"params","type":"tuple"}],"name":"decreaseLiquidity","outputs":[{"internalType":"uint256","name":"amount0","type":"uint256"},{"internalType":"uint256","name":"amount1","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"amount0Desired","type":"uint256"},{"internalType":"uint256","name":"amount1Desired","type":"uint256"},{"internalType":"uint256","name":"amount0Min","type":"uint256"},{"internalType":"uint256","name":"amount1Min","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"internalType":"struct INonfungiblePositionManager.IncreaseLiquidityParams","name":"params","type":"tuple"}],"name":"increaseLiquidity","outputs":[{"internalType":"uint128","name":"liquidity","type":"uint128"},{"internalType":"uint256","name":"amount0","type":"uint256"},{"internalType":"uint256","name":"amount1","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"token0","type":"address"},{"internalType":"address","name":"token1","type":"address"},{"internalType":"uint24","name":"fee","type":"uint24"},{"internalType":"int24","name":"tickLower","type":"int24"},{"internalType":"int24","name":"tickUpper","type":"int24"},{"internalType":"uint256","name":"amount0Desired","type":"uint256"},{"internalType":"uint256","name":"amount1Desired","type":"uint256"},{"internalType":"uint256","name":"amount0Min","type":"uint256"},{"internalType":"uint256","name":"amount1Min","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"internalType":"struct INonfungiblePositionManager.MintParams","name":"params","type":"tuple"}],"name":"mint","outputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint128","name":"liquidity","type":"uint128"},{"internalType":"uint256","name":"amount0","type":"uint256"},{"internalType":"uint256","name":"amount1","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"positions","outputs":[{"internalType":"uint96","name":"nonce","type":"uint96"},{"internalType":"address","name":"operator","type":"address"},{"internalType":"address","name":"token0","type":"address"},{"internalType":"address","name":"token1","type":"address"},{"internalType":"uint24","name":"fee","type":"uint24"},{"internalType":"int24","name":"tickLower","type":"int24"},{"internalType":"int24","name":"tickUpper","type":"int24"},{"internalType":"uint128","name":"liquidity","type":"uint128"},{"internalType":"uint256","name":"feeGrowthInside0LastX128","type":"uint256"},{"internalType":"uint256","name":"feeGrowthInside1LastX128","type":"uint256"},{"internalType":"uint128","name":"tokensOwed0","type":"uint128"},{"internalType":"uint128","name":"tokensOwed1","type":"uint128"}],"stateMutability":"view","type":"function"}] \ No newline at end of file diff --git a/contracts/INonFungiblePositionManager.sol b/contracts/INonFungiblePositionManager.sol new file mode 100644 index 0000000..3d2c147 --- /dev/null +++ b/contracts/INonFungiblePositionManager.sol @@ -0,0 +1,161 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity >=0.7.5; +pragma abicoder v2; + +interface INonfungiblePositionManager { + /// @notice Emitted when liquidity is increased for a position NFT + /// @dev Also emitted when a token is minted + /// @param tokenId The ID of the token for which liquidity was increased + /// @param liquidity The amount by which liquidity for the NFT position was increased + /// @param amount0 The amount of token0 that was paid for the increase in liquidity + /// @param amount1 The amount of token1 that was paid for the increase in liquidity + event IncreaseLiquidity(uint256 indexed tokenId, uint128 liquidity, uint256 amount0, uint256 amount1); + /// @notice Emitted when liquidity is decreased for a position NFT + /// @param tokenId The ID of the token for which liquidity was decreased + /// @param liquidity The amount by which liquidity for the NFT position was decreased + /// @param amount0 The amount of token0 that was accounted for the decrease in liquidity + /// @param amount1 The amount of token1 that was accounted for the decrease in liquidity + event DecreaseLiquidity(uint256 indexed tokenId, uint128 liquidity, uint256 amount0, uint256 amount1); + /// @notice Emitted when tokens are collected for a position NFT + /// @dev The amounts reported may not be exactly equivalent to the amounts transferred, due to rounding behavior + /// @param tokenId The ID of the token for which underlying tokens were collected + /// @param recipient The address of the account that received the collected tokens + /// @param amount0 The amount of token0 owed to the position that was collected + /// @param amount1 The amount of token1 owed to the position that was collected + event Collect(uint256 indexed tokenId, address recipient, uint256 amount0, uint256 amount1); + + /// @notice Returns the position information associated with a given token ID. + /// @dev Throws if the token ID is not valid. + /// @param tokenId The ID of the token that represents the position + /// @return nonce The nonce for permits + /// @return operator The address that is approved for spending + /// @return token0 The address of the token0 for a specific pool + /// @return token1 The address of the token1 for a specific pool + /// @return fee The fee associated with the pool + /// @return tickLower The lower end of the tick range for the position + /// @return tickUpper The higher end of the tick range for the position + /// @return liquidity The liquidity of the position + /// @return feeGrowthInside0LastX128 The fee growth of token0 as of the last action on the individual position + /// @return feeGrowthInside1LastX128 The fee growth of token1 as of the last action on the individual position + /// @return tokensOwed0 The uncollected amount of token0 owed to the position as of the last computation + /// @return tokensOwed1 The uncollected amount of token1 owed to the position as of the last computation + function positions(uint256 tokenId) + external + view + returns ( + uint96 nonce, + address operator, + address token0, + address token1, + uint24 fee, + int24 tickLower, + int24 tickUpper, + uint128 liquidity, + uint256 feeGrowthInside0LastX128, + uint256 feeGrowthInside1LastX128, + uint128 tokensOwed0, + uint128 tokensOwed1 + ); + + struct MintParams { + address token0; + address token1; + uint24 fee; + int24 tickLower; + int24 tickUpper; + uint256 amount0Desired; + uint256 amount1Desired; + uint256 amount0Min; + uint256 amount1Min; + address recipient; + uint256 deadline; + } + + /// @notice Creates a new position wrapped in a NFT + /// @dev Call this when the pool does exist and is initialized. Note that if the pool is created but not initialized + /// a method does not exist, i.e. the pool is assumed to be initialized. + /// @param params The params necessary to mint a position, encoded as `MintParams` in calldata + /// @return tokenId The ID of the token that represents the minted position + /// @return liquidity The amount of liquidity for this position + /// @return amount0 The amount of token0 + /// @return amount1 The amount of token1 + function mint(MintParams calldata params) + external + payable + returns ( + uint256 tokenId, + uint128 liquidity, + uint256 amount0, + uint256 amount1 + ); + + struct IncreaseLiquidityParams { + uint256 tokenId; + uint256 amount0Desired; + uint256 amount1Desired; + uint256 amount0Min; + uint256 amount1Min; + uint256 deadline; + } + + /// @notice Increases the amount of liquidity in a position, with tokens paid by the `msg.sender` + /// @param params tokenId The ID of the token for which liquidity is being increased, + /// amount0Desired The desired amount of token0 to be spent, + /// amount1Desired The desired amount of token1 to be spent, + /// amount0Min The minimum amount of token0 to spend, which serves as a slippage check, + /// amount1Min The minimum amount of token1 to spend, which serves as a slippage check, + /// deadline The time by which the transaction must be included to effect the change + /// @return liquidity The new liquidity amount as a result of the increase + /// @return amount0 The amount of token0 to acheive resulting liquidity + /// @return amount1 The amount of token1 to acheive resulting liquidity + function increaseLiquidity(IncreaseLiquidityParams calldata params) + external + payable + returns ( + uint128 liquidity, + uint256 amount0, + uint256 amount1 + ); + + struct DecreaseLiquidityParams { + uint256 tokenId; + uint128 liquidity; + uint256 amount0Min; + uint256 amount1Min; + uint256 deadline; + } + + /// @notice Decreases the amount of liquidity in a position and accounts it to the position + /// @param params tokenId The ID of the token for which liquidity is being decreased, + /// amount The amount by which liquidity will be decreased, + /// amount0Min The minimum amount of token0 that should be accounted for the burned liquidity, + /// amount1Min The minimum amount of token1 that should be accounted for the burned liquidity, + /// deadline The time by which the transaction must be included to effect the change + /// @return amount0 The amount of token0 accounted to the position's tokens owed + /// @return amount1 The amount of token1 accounted to the position's tokens owed + function decreaseLiquidity(DecreaseLiquidityParams calldata params) + external + payable + returns (uint256 amount0, uint256 amount1); + + struct CollectParams { + uint256 tokenId; + address recipient; + uint128 amount0Max; + uint128 amount1Max; + } + + /// @notice Collects up to a maximum amount of fees owed to a specific position to the recipient + /// @param params tokenId The ID of the NFT for which tokens are being collected, + /// recipient The account that should receive the tokens, + /// amount0Max The maximum amount of token0 to collect, + /// amount1Max The maximum amount of token1 to collect + /// @return amount0 The amount of fees collected in token0 + /// @return amount1 The amount of fees collected in token1 + function collect(CollectParams calldata params) external payable returns (uint256 amount0, uint256 amount1); + + /// @notice Burns a token ID, which deletes it from the NFT contract. The token must have 0 liquidity and all tokens + /// must be collected first. + /// @param tokenId The ID of the token that is being burned + function burn(uint256 tokenId) external payable; +} \ No newline at end of file diff --git a/dexes/uniswap/v3/base.go b/dexes/uniswap/v3/base.go new file mode 100644 index 0000000..08574f1 --- /dev/null +++ b/dexes/uniswap/v3/base.go @@ -0,0 +1,233 @@ +package nft + +// Package nft provides base functionality for interacting with NFTs using the IERC721 standard. + +// import ( +// "errors" +// "fmt" +// "math/big" +// "strings" + +// "github.com/Thektonic/eth-interfaces/base" +// "github.com/Thektonic/eth-interfaces/contractextension" +// "github.com/Thektonic/eth-interfaces/customerrors" +// "github.com/Thektonic/eth-interfaces/inferences/ERC721Complete" +// "github.com/Thektonic/eth-interfaces/inferences/nftPositionManager" +// "github.com/Thektonic/eth-interfaces/models" +// "github.com/Thektonic/eth-interfaces/utils" +// "github.com/ethereum/go-ethereum/accounts/abi/bind" +// "github.com/ethereum/go-ethereum/common" +// "github.com/ethereum/go-ethereum/core/types" +// ) + +// // ERC721Interactions wraps NFT interactions using an underlying base interaction and an ERC721A session. + +// type Interactions[T nftPositionManager.NftPositionManagerSession] struct { +// *base.BaseInteractions +// Session *T +// Address common.Address +// CallError func(string, error) *base.CallError +// } + +// type PositionManagerInteractions struct { +// *base.BaseInteractions +// positionManagerSession *nftPositionManager.NftPositionManagerSession +// positionManagerAddress common.Address +// callError func(string, error) *base.CallError +// } + +// // NewERC721Interactions creates a new instance of ERC721Interactions from a base interaction interface and an NFT contract address. +// func NewERC721Interactions( +// baseInteractions *base.BaseInteractions, +// address common.Address, +// signatures []BaseNFTSignature, +// transactOps ...*bind.TransactOpts, +// ) (*PositionManagerInteractions, error) { + +// var converted []utils.Signature +// for _, sig := range signatures { +// converted = append(converted, sig) +// } + +// err := baseInteractions.CheckSignatures(address, converted) +// if err != nil { +// return nil, customerrors.WrapinterfacingError("CheckSignatures", err) +// } + +// var txOpts *bind.TransactOpts +// if len(transactOps) == 0 { +// txOpts, err = baseInteractions.BaseTxSetup() +// if err != nil { +// return nil, customerrors.WrapinterfacingError("BaseTxSetup", err) +// } +// } else { +// txOpts = transactOps[0] +// } + +// erc721Complete, err := ERC721Complete.NewERC721Complete(address, baseInteractions.Client) +// if err != nil { +// return nil, customerrors.WrapinterfacingError("NewERC721Interactions", err) +// } +// erc721ASession := ERC721Complete.ERC721CompleteSession{ +// Contract: erc721Complete, +// CallOpts: bind.CallOpts{Pending: true, From: baseInteractions.Address}, +// TransactOpts: *txOpts, +// } + +// callError := func(field string, err error) *base.CallError { +// return baseInteractions.WrapCallError(ERC721Complete.ERC721CompleteABI, field, err) +// } + +// erc721Interactions := &ERC721Interactions{baseInteractions, +// &erc721ASession, +// address, +// callError, +// } + +// if err := contractextension.SimulateCall(baseInteractions.Ctx, ERC721Complete.ERC721CompleteABI, "name", erc721Interactions); err != nil { +// return nil, err +// } + +// return erc721Interactions, nil +// } + +// // GetNFTAddress returns the NFT contract address. +// func (d *ERC721Interactions) GetAddress() common.Address { +// return d.nftAddress +// } + +// // GetSession returns the current session used for NFT interactions. +// func (d *ERC721Interactions) GetSession() ERC721Complete.ERC721CompleteSession { +// return *d.erc721Session +// } + +// // GetBalance retrieves the balance of NFTs for the associated address. +// func (d *ERC721Interactions) GetBalance() (*big.Int, error) { +// balance, err := d.erc721Session.BalanceOf(d.Address) +// if err != nil { +// return nil, d.callError("nft.BalanceOf()", err) +// } +// return balance, nil +// } + +// // TransferTo transfers a specific token to another address after verifying ownership. +// func (d *ERC721Interactions) TransferTo(to common.Address, tokenID *big.Int) (*types.Transaction, error) { +// tx, err := d.erc721Session.TransferFrom(d.Address, to, tokenID) +// if err != nil { +// return nil, d.callError("nft.TransferFrom()", err) +// } +// return tx, nil +// } + +// // TransferFirstOwnedTo transfers the first token owned by the signer to the specified address. +// func (d *ERC721Interactions) TransferFirstOwnedTo(to common.Address) (*types.Transaction, error) { +// maxSupply, err := d.TotalSupply() +// if err != nil { +// return nil, fmt.Errorf("failed to get total supply: %w", err) +// } + +// for idx := range maxSupply.Int64() { +// tokenID := big.NewInt(idx) +// tx, err := d.TransferTo(to, tokenID) +// if err != nil { +// if strings.Contains(err.Error(), utils.ErrZeroAddress.Error()) { +// return nil, err +// } +// continue +// } +// return tx, nil +// } + +// return nil, errors.New("no nft found from signer") +// } + +// // TotalSupply returns the total number of NFTs minted. +// func (d *ERC721Interactions) TotalSupply() (*big.Int, error) { +// supply, err := d.erc721Session.TotalSupply() +// if err != nil { +// return nil, d.callError("nft.TotalSupply()", err) +// } +// return supply, nil +// } + +// // BalanceOf retrieves the NFT balance for a given owner. +// func (d *ERC721Interactions) BalanceOf(owner common.Address) (*big.Int, error) { +// balance, err := d.erc721Session.BalanceOf(owner) +// if err != nil { +// return nil, d.callError("nft.BalanceOf()", err) +// } +// return balance, nil +// } + +// // OwnerOf retrieves the owner of a specific token. +// func (d *ERC721Interactions) OwnerOf(tokenID *big.Int) (common.Address, error) { +// owner, err := d.erc721Session.OwnerOf(tokenID) +// if err != nil { +// return common.Address{}, d.callError("nft.OwnerOf()", err) +// } +// return owner, nil +// } + +// // Approve approves an address to transfer a specific token. +// func (d *ERC721Interactions) Approve(to common.Address, tokenID *big.Int) (*types.Transaction, error) { +// tx, err := d.erc721Session.Approve(to, tokenID) +// if err != nil { +// return nil, d.callError("nft.Approve()", err) +// } +// return tx, nil +// } + +// // TokenMetaInfos retrieves metadata about the specified token such as name, symbol, and URI. +// func (d *ERC721Interactions) TokenMetaInfos(tokenID *big.Int) (*models.TokenMeta, error) { +// name, err := d.Name() +// if err != nil { +// return nil, err +// } +// symbol, err := d.Symbol() +// if err != nil { +// return &models.TokenMeta{Name: name}, err +// } + +// uri, err := d.TokenURI(tokenID) +// if err != nil { +// return &models.TokenMeta{Name: name, Symbol: symbol}, err +// } + +// return &models.TokenMeta{Name: name, Symbol: symbol, URI: uri}, nil +// } + +// // Name returns the name of the NFT. +// func (d *ERC721Interactions) Name() (string, error) { +// name, err := d.erc721Session.Name() +// if err != nil { +// return "", d.callError("nft.Name()", err) +// } +// return name, nil +// } + +// // Symbol returns the symbol of the NFT. +// func (d *ERC721Interactions) Symbol() (string, error) { +// symbol, err := d.erc721Session.Symbol() +// if err != nil { +// return "", d.callError("nft.Symbol()", err) +// } +// return symbol, nil +// } + +// // TokenURI returns the URI of the NFT. +// func (d *ERC721Interactions) TokenURI(tokenID *big.Int) (string, error) { +// uri, err := d.erc721Session.TokenURI(tokenID) +// if err != nil { +// return "", d.callError("nft.TokenURI()", err) +// } +// return uri, nil +// } + +// // GetApproved returns the approved address for a specific token. +// func (d *ERC721Interactions) GetApproved(tokenID *big.Int) (common.Address, error) { +// approved, err := d.erc721Session.GetApproved(tokenID) +// if err != nil { +// return common.Address{}, d.callError("nft.GetApproved()", err) +// } +// return approved, nil +// } diff --git a/dexes/uniswap/v3/base_test.go b/dexes/uniswap/v3/base_test.go new file mode 100644 index 0000000..aac79e8 --- /dev/null +++ b/dexes/uniswap/v3/base_test.go @@ -0,0 +1,682 @@ +package nft_test + +// Package nft_test contains tests for NFT interactions defined in base.go. + +import ( + "context" + "crypto/ecdsa" + "log" + "math/big" + "testing" + + "github.com/Thektonic/eth-interfaces/base" + "github.com/Thektonic/eth-interfaces/erc20" + "github.com/Thektonic/eth-interfaces/inferences/ERC20Burnable" + "github.com/Thektonic/eth-interfaces/inferences/ERC721Complete" + "github.com/Thektonic/eth-interfaces/nft" + "github.com/Thektonic/eth-interfaces/utils" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto" + "github.com/stretchr/testify/assert" +) + +// Test_DeploySuccessfully tests if the blockchain setup and contract deployment succeed without errors. +func Test_DeploySuccessfully(t *testing.T) { + backend, _, _, _, err := utils.SetupBlockchain(t, + ERC721Complete.ERC721CompleteABI, + ERC721Complete.ERC721CompleteBin, + "MyNFT", // Arg 1: name + "MNFT", // Arg 2: symbol + ) + assert.Nil(t, err, "failed to create interactions interface, error: %w", err) + backend.Close() +} + +// Test_Instantiation verifies that the NFT interactions interface is correctly instantiated using various contracts, including a valid NFT contract, an empty contract, and an ERC20 contract. +func Test_Instantiation(t *testing.T) { + backend, auth, contractAddress, privKey, err := utils.SetupBlockchain(t, + ERC721Complete.ERC721CompleteABI, + ERC721Complete.ERC721CompleteBin, + "MyNFT", // Arg 1: name + "MNFT", // Arg 2: symbol + ) + if err != nil { + t.Fatal(err) + } + defer backend.Close() + + emptyContract, err := utils.DeployEmptyContract(auth, backend) + if err != nil { + log.Fatalf("failed to deploy empty contract: %s", err) + } + + erc20Contract, tx, _, err := utils.DeployContract( + auth, + backend.Client(), + ERC20Burnable.ERC20BurnableABI, + ERC20Burnable.ERC20BurnableBin, + ) + if err != nil { + t.Fatalf("failed to deploy ERC20 contract: %s", err) + } + backend.Commit() + receipt, err := backend.Client().TransactionReceipt(context.Background(), tx.Hash()) + if err != nil || receipt.Status != 1 { + t.Fatalf("failed to deploy ERC20 contract: %s", err) + } + + testCases := []struct { + Name string + ContractAddr common.Address + ExpectedResult string + ExpectError bool + ExpectedError string + }{ + { + Name: "OK - Successfully instantiated", + ExpectedResult: "MyNFT", + ContractAddr: *contractAddress, + }, + { + Name: "KO - Empty contract doesn't implement interface", + ExpectError: true, + ContractAddr: *emptyContract, + ExpectedError: "interface setup error function CheckSignatures, error :", + }, + { + Name: "KO - ERC20 doesn't implement the interface", + ExpectError: true, + ContractAddr: erc20Contract, + ExpectedError: "interface setup error function CheckSignatures, error :", + }, + } + + baseInteractions := base.NewBaseInteractions(backend.Client(), privKey, nil) + for _, tt := range testCases { + t.Run(tt.Name, func(t *testing.T) { + _, err := erc20.NewIERC20Interactions(baseInteractions, tt.ContractAddr, []erc20.BaseERC20Signature{erc20.Name, erc20.Symbol, erc20.TokenURI}) + if tt.ExpectError { + if err == nil { + t.Error("expected error but there's none") + return + } + assert.Contains(t, err.Error(), tt.ExpectedError) + } else { + assert.NoError(t, err, "failed to create interactions interface, error: %w", err) + } + }) + } +} + +// Test_Name verifies that the NFT contract correctly returns its name. +func Test_Name(t *testing.T) { + backend, _, contractAddress, privKey, err := utils.SetupBlockchain(t, + ERC721Complete.ERC721CompleteABI, + ERC721Complete.ERC721CompleteBin, + "MyNFT", // Arg 1: name + "MNFT", // Arg 2: symbol + ) + if err != nil { + t.Fatal(err) + } + defer backend.Close() + + testCases := []struct { + Name string + ContractAddr common.Address + ExpectedResult string + ExpectError bool + ExpectedError string + }{ + { + Name: "OK - Successfully get NFT name", + ExpectedResult: "MyNFT", + ContractAddr: *contractAddress, + }, + } + + base := base.NewBaseInteractions(backend.Client(), privKey, nil) + for _, tt := range testCases { + t.Run(tt.Name, func(t *testing.T) { + session, err := nft.NewERC721Interactions(base, tt.ContractAddr, []nft.BaseNFTSignature{nft.Name}) + if tt.ExpectError { + if err == nil { + t.Error("expected error but there's none") + return + } + assert.Equal(t, tt.ExpectedError, err.Error()) + } else { + assert.Nil(t, err, "failed to create interactions interface, error: %w", err) + name, err := session.Name() + assert.Nil(t, err) + assert.Equal(t, tt.ExpectedResult, name) + } + }) + } +} + +// Test_Symbol verifies that the NFT contract correctly returns its symbol. +func Test_Symbol(t *testing.T) { + backend, _, contractAddress, privKey, err := utils.SetupBlockchain(t, + ERC721Complete.ERC721CompleteABI, + ERC721Complete.ERC721CompleteBin, + "MyNFT", // Arg 1: name + "MNFT", // Arg 2: symbol + ) + if err != nil { + t.Fatal(err) + } + defer backend.Close() + + testCases := []struct { + Name string + ContractAddr common.Address + ExpectedResult string + ExpectError bool + ExpectedError string + }{ + { + Name: "OK - Successfully get NFT symbol", + ExpectedResult: "MNFT", + ContractAddr: *contractAddress, + }, + } + + base := base.NewBaseInteractions(backend.Client(), privKey, nil) + for _, tt := range testCases { + t.Run(tt.Name, func(t *testing.T) { + session, err := nft.NewERC721Interactions(base, tt.ContractAddr, []nft.BaseNFTSignature{nft.Symbol}) + if tt.ExpectError { + if err == nil { + t.Error("expected error but there's none") + return + } + assert.Equal(t, tt.ExpectedError, err.Error()) + } else { + assert.Nil(t, err, "failed to create interactions interface, error: %w", err) + symbol, err := session.Symbol() + assert.Nil(t, err) + assert.Equal(t, tt.ExpectedResult, symbol) + } + }) + } +} + +// Test_TotalSupply verifies that the total supply of NFTs is correctly reported by the contract. +func Test_TotalSupply(t *testing.T) { + backend, _, contractAddress, privKey, err := utils.SetupBlockchain(t, + ERC721Complete.ERC721CompleteABI, + ERC721Complete.ERC721CompleteBin, + "MyNFT", // Arg 1: name + "MNFT", // Arg 2: symbol + ) + if err != nil { + t.Fatal(err) + } + defer backend.Close() + + testCases := []struct { + Name string + ContractAddr common.Address + ExpectedResult uint64 + ExpectError bool + ExpectedError string + }{ + { + Name: "OK - Successfully get NFT total supply", + ExpectedResult: 30, + ContractAddr: *contractAddress, + }, + } + + base := base.NewBaseInteractions(backend.Client(), privKey, nil) + for _, tt := range testCases { + t.Run(tt.Name, func(t *testing.T) { + session, err := nft.NewERC721Interactions(base, tt.ContractAddr, []nft.BaseNFTSignature{nft.TotalSupply}) + if tt.ExpectError { + if err == nil { + t.Error("expected error but there's none") + return + } + assert.Equal(t, tt.ExpectedError, err.Error()) + } else { + assert.Nil(t, err, "failed to create interactions interface, error: %w", err) + supply, err := session.TotalSupply() + assert.Nil(t, err) + assert.Equal(t, tt.ExpectedResult, supply.Uint64()) + } + }) + } +} + +// Test_OwnerOf verifies that the owner of a given token is correctly identified. +func Test_OwnerOf(t *testing.T) { + backend, _, contractAddress, privKey, err := utils.SetupBlockchain(t, + ERC721Complete.ERC721CompleteABI, + ERC721Complete.ERC721CompleteBin, + "MyNFT", // Arg 1: name + "MNFT", // Arg 2: symbol + ) + if err != nil { + t.Fatal(err) + } + defer backend.Close() + + testCases := []struct { + Name string + ContractAddr common.Address + argument *big.Int + ExpectedResult common.Address + ExpectError bool + ExpectedError string + }{ + { + Name: "OK - Successfully get NFT owner", + ExpectedResult: crypto.PubkeyToAddress(privKey.PublicKey), + argument: common.Big0, + ContractAddr: *contractAddress, + }, + { + Name: "OK - Not minted, owner is zero address", + argument: big.NewInt(31), + ContractAddr: *contractAddress, + ExpectError: true, + ExpectedError: "call error on nft.OwnerOf(): OwnerQueryForNonexistentToken", + }, + } + + base := base.NewBaseInteractions(backend.Client(), privKey, nil) + for _, tt := range testCases { + t.Run(tt.Name, func(t *testing.T) { + session, err := nft.NewERC721Interactions(base, tt.ContractAddr, []nft.BaseNFTSignature{nft.OwnerOf}) + if err != nil { + t.Fatal("setting up should not fail") + } + owner, err := session.OwnerOf(tt.argument) + if tt.ExpectError { + if err == nil { + t.Error("expected error but there's none") + return + } + assert.Equal(t, tt.ExpectedError, err.Error()) + } else { + assert.Nil(t, err) + assert.Equal(t, tt.ExpectedResult, owner) + } + }) + } +} + +// Test_Transfer tests the transfer functionality and ensures that the token transfer behaves as expected. +func Test_Transfer(t *testing.T) { + backend, _, contractAddress, privKey, err := utils.SetupBlockchain(t, + ERC721Complete.ERC721CompleteABI, + ERC721Complete.ERC721CompleteBin, + "MyNFT", // Arg 1: name + "MNFT", // Arg 2: symbol + ) + if err != nil { + t.Fatal(err) + } + + type transferArgs struct { + pk *ecdsa.PrivateKey + To common.Address + TokenID *big.Int + } + + testCases := []struct { + Name string + ContractAddr common.Address + args transferArgs + ExpectError bool + ExpectedError string + }{ + { + Name: "OK - Successfully get transfer NFT", + args: transferArgs{ + To: common.HexToAddress("1"), + TokenID: big.NewInt(10), + }, + ContractAddr: *contractAddress, + }, + { + Name: "OK - Burn NFT", + args: transferArgs{ + To: common.HexToAddress("0"), + TokenID: big.NewInt(1), + }, + ContractAddr: *contractAddress, + }, + { + Name: "KO - Incorrect owner/Unallowed", + args: transferArgs{ + pk: func() *ecdsa.PrivateKey { + key, _ := crypto.GenerateKey() + return key + }(), + To: crypto.PubkeyToAddress(privKey.PublicKey), + TokenID: common.Big0, + }, + ContractAddr: *contractAddress, + ExpectError: true, + ExpectedError: "call error on nft.TransferFrom(): TransferFromIncorrectOwner", + }, + } + + for _, tt := range testCases { + t.Run(tt.Name, func(t *testing.T) { + baseInteractions := base.NewBaseInteractions(backend.Client(), privKey, nil) + if tt.args.pk != nil { + pk := tt.args.pk + _, err := baseInteractions.TransferETH(crypto.PubkeyToAddress(pk.PublicKey), big.NewInt(1e18)) + if err != nil { + t.Fatal(err) + } + + backend.Commit() + baseInteractions = base.NewBaseInteractions(backend.Client(), pk, nil) + } + session, err := nft.NewERC721Interactions(baseInteractions, tt.ContractAddr, []nft.BaseNFTSignature{nft.TransferFrom}) + if err != nil { + t.Fatal("setting up should not fail") + } + _, err = session.TransferTo(tt.args.To, tt.args.TokenID) + backend.Commit() + if tt.ExpectError { + if err == nil { + t.Error("expected error but there's none") + return + } + assert.Contains(t, err.Error(), tt.ExpectedError) + } else { + assert.Nil(t, err) + owner, err := session.OwnerOf(tt.args.TokenID) + if err != nil { + t.Fatal("failed to get owner") + } + assert.Equal(t, tt.args.To, owner) + } + }) + } +} + +// Test_GetBalance verifies that the NFT balance is correctly returned for an address. +func Test_GetBalance(t *testing.T) { + backend, auth, contractAddress, privKey, err := utils.SetupBlockchain(t, + ERC721Complete.ERC721CompleteABI, + ERC721Complete.ERC721CompleteBin, + "MyNFT", + "MNFT", + ) + if err != nil { + t.Fatal(err) + } + defer backend.Close() + + base := base.NewBaseInteractions(backend.Client(), privKey, nil) + nft, err := nft.NewERC721Interactions(base, *contractAddress, []nft.BaseNFTSignature{nft.BalanceOf}, auth) + assert.Nil(t, err) + + balance, err := nft.GetBalance() + assert.Nil(t, err) + assert.Equal(t, balance.Uint64(), uint64(30)) +} + +// Test_TransferFirstOwnedTo tests transferring the first owned token to a specified address. +func Test_TransferFirstOwnedTo(t *testing.T) { + backend, auth, contractAddress, privKey, err := utils.SetupBlockchain(t, + ERC721Complete.ERC721CompleteABI, + ERC721Complete.ERC721CompleteBin, + "MyNFT", + "MNFT", + ) + if err != nil { + t.Fatal(err) + } + defer backend.Close() + + type transferArgs struct { + pk *ecdsa.PrivateKey + To common.Address + } + + tests := []struct { + name string + args transferArgs + expectError bool + errorContains string + }{ + { + name: "OK -Successful transfer", + args: transferArgs{ + To: common.HexToAddress("10"), + }, + expectError: false, + }, + { + name: "OK - Burn to zero address", + args: transferArgs{ + To: common.HexToAddress("0"), + }, + }, + { + name: "NOK - No NFTs owned", + args: transferArgs{ + To: common.HexToAddress("1"), + pk: func() *ecdsa.PrivateKey { + key, _ := crypto.GenerateKey() + return key + }(), + }, + expectError: true, + errorContains: "no nft found from signer", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + var nftInterface *nft.ERC721Interactions + baseInteractions := base.NewBaseInteractions(backend.Client(), privKey, nil) + if tt.args.pk != nil { + pk := tt.args.pk + _, err := baseInteractions.TransferETH(crypto.PubkeyToAddress(pk.PublicKey), big.NewInt(1e18)) + if err != nil { + t.Fatal(err) + } + backend.Commit() + baseInteractions = base.NewBaseInteractions(backend.Client(), pk, nil) + if err != nil { + t.Fatal(err) + } + } else { + baseInteractions = base.NewBaseInteractions(backend.Client(), privKey, nil) + } + nftInterface, err = nft.NewERC721Interactions( + baseInteractions, + *contractAddress, + []nft.BaseNFTSignature{nft.TransferFrom, nft.OwnerOf}, + auth, + ) + assert.Nil(t, err) + + _, err = nftInterface.TransferFirstOwnedTo(tt.args.To) + backend.Commit() + if tt.expectError { + assert.Error(t, err) + assert.Contains(t, err.Error(), tt.errorContains) + } else { + assert.Nil(t, err) + } + }) + } +} + +// Test_BalanceOf verifies the BalanceOf function for different addresses. +func Test_BalanceOf(t *testing.T) { + backend, auth, contractAddress, privKey, err := utils.SetupBlockchain(t, + ERC721Complete.ERC721CompleteABI, + ERC721Complete.ERC721CompleteBin, + "MyNFT", + "MNFT", + ) + if err != nil { + t.Fatal(err) + } + defer backend.Close() + + base := base.NewBaseInteractions(backend.Client(), privKey, nil) + nft, err := nft.NewERC721Interactions(base, *contractAddress, []nft.BaseNFTSignature{nft.BalanceOf}) + assert.Nil(t, err) + + testCases := []struct { + Name string + Owner common.Address + ExpectedResult *uint64 + ExpectError bool + ExpectedError string + }{ + { + Name: "NOK - Zero address", + Owner: common.Address{}, + ExpectedResult: nil, + ExpectError: true, + ExpectedError: "call error on nft.BalanceOf(): BalanceQueryForZeroAddress", + }, + { + Name: "OK - non empty balance", + Owner: auth.From, + ExpectedResult: func() *uint64 { val := uint64(30); return &val }(), + }, + { + Name: "OK - empty balance", + Owner: common.HexToAddress("1"), + ExpectedResult: func() *uint64 { val := uint64(0); return &val }(), + }, + } + + for _, tt := range testCases { + t.Run(tt.Name, func(t *testing.T) { + balance, err := nft.BalanceOf(tt.Owner) + if tt.ExpectError { + if err == nil { + t.Error("expected error but there's none") + return + } + assert.Contains(t, err.Error(), tt.ExpectedError) + } else { + assert.Nil(t, err) + if tt.ExpectedResult != nil { + assert.Equal(t, *tt.ExpectedResult, balance.Uint64()) + } + } + }) + } +} + +// Test_Approve tests the approval functionality for token transfers. +func Test_Approve(t *testing.T) { + backend, _, contractAddress, privKey, err := utils.SetupBlockchain(t, + ERC721Complete.ERC721CompleteABI, + ERC721Complete.ERC721CompleteBin, + "MyNFT", + "MNFT", + ) + if err != nil { + t.Fatal(err) + } + defer backend.Close() + + type approveArgs struct { + pk *ecdsa.PrivateKey + To common.Address + TokenID *big.Int + } + + tests := []struct { + name string + expectError bool + args approveArgs + errorContains string + }{ + { + name: "OK -Successful approval", + args: approveArgs{ + To: common.HexToAddress("1"), + TokenID: big.NewInt(1), + }, + expectError: false, + }, + { + name: "NOK - Not owner", + args: approveArgs{ + To: common.HexToAddress("10"), + pk: func() *ecdsa.PrivateKey { + key, _ := crypto.GenerateKey() + return key + }(), + TokenID: big.NewInt(10), + }, + expectError: true, + errorContains: "call error on nft.Approve(): ApprovalCallerNotOwnerNorApproved", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + baseInteractions := base.NewBaseInteractions(backend.Client(), privKey, nil) + if tt.args.pk != nil { + pk := tt.args.pk + _, err := baseInteractions.TransferETH(crypto.PubkeyToAddress(pk.PublicKey), big.NewInt(1e18)) + if err != nil { + t.Fatal(err) + } + backend.Commit() + baseInteractions = base.NewBaseInteractions(backend.Client(), pk, nil) + } + + nft, err := nft.NewERC721Interactions(baseInteractions, *contractAddress, []nft.BaseNFTSignature{nft.Approve, nft.GetApproved}) + if err != nil { + t.Fatal(err) + } + + _, err = nft.Approve(tt.args.To, tt.args.TokenID) + backend.Commit() + + if tt.expectError { + assert.Error(t, err) + assert.Contains(t, err.Error(), tt.errorContains) + } else { + assert.Nil(t, err) + approved, err := nft.GetApproved(tt.args.TokenID) + assert.Nil(t, err) + assert.Equal(t, tt.args.To.Hex(), approved.Hex()) + } + }) + } +} + +// Test_TokenMetaInfos verifies that the metadata (name, symbol, and URI) for a token is correctly retrieved. +func Test_TokenMetaInfos(t *testing.T) { + backend, _, contractAddress, privKey, err := utils.SetupBlockchain(t, + ERC721Complete.ERC721CompleteABI, + ERC721Complete.ERC721CompleteBin, + "MyNFT", + "MNFT", + ) + if err != nil { + t.Fatal(err) + } + defer backend.Close() + + base := base.NewBaseInteractions(backend.Client(), privKey, nil) + nft, err := erc20.NewIERC20Interactions(base, *contractAddress, []erc20.BaseERC20Signature{erc20.Name, erc20.Symbol, erc20.TokenURI}) + assert.Nil(t, err) + + // Test meta infos for token + nftInfo, err := nft.TokenMetaInfos() + assert.Nil(t, err) + assert.Equal(t, "MyNFT", nftInfo.Name) + assert.Equal(t, "MNFT", nftInfo.Symbol) + assert.Empty(t, nftInfo.URI) +} diff --git a/dexes/uniswap/v3/signatures.go b/dexes/uniswap/v3/signatures.go new file mode 100644 index 0000000..95a76ff --- /dev/null +++ b/dexes/uniswap/v3/signatures.go @@ -0,0 +1,29 @@ +package nft + +import ( + "encoding/hex" + + "github.com/ethereum/go-ethereum/crypto" +) + +type BaseNFTSignature string + +const ( + Name BaseNFTSignature = "name()" + Symbol BaseNFTSignature = "symbol()" + BalanceOf BaseNFTSignature = "balanceOf(address)" + TotalSupply BaseNFTSignature = "totalSupply()" + OwnerOf BaseNFTSignature = "ownerOf(uint256)" + TokenURI BaseNFTSignature = "tokenURI(uint256)" + Approve BaseNFTSignature = "approve(address,uint256)" + GetApproved BaseNFTSignature = "getApproved(uint256)" + TransferFrom BaseNFTSignature = "transferFrom(address,address,uint256)" + SafeTransferFrom BaseNFTSignature = "safeTransferFrom(address,address,uint256)" +) + +func (s BaseNFTSignature) GetHex() string { + hash := crypto.NewKeccakState() + hash.Write([]byte(s)) + selector := hash.Sum(nil)[:4] + return hex.EncodeToString(selector) +} diff --git a/erc20/base.go b/erc20/base.go index 9e6010f..625b473 100644 --- a/erc20/base.go +++ b/erc20/base.go @@ -21,10 +21,14 @@ import ( // IERC20AInteractions wraps NFT interactions using an underlying base interaction and an ERC20 session. type ERC20Interactions struct { - *base.BaseInteractions - ierc20Session *ERC20Burnable.ERC20BurnableSession - nftAddress common.Address - callError func(string, error) *base.CallError + *base.Interactions[*ERC20Burnable.ERC20BurnableSession] +} + +type IERC20 interface { + GetAddress() common.Address + CheckSignatures(address common.Address, signatures []utils.Signature) error + GetSession() ERC20Burnable.ERC20BurnableSession + GetBaseInteractions() *base.BaseInteractions } // NewIERC20Interactions creates a new instance of IERC20AInteractions from a base interaction interface and an NFT contract address. @@ -69,10 +73,13 @@ func NewIERC20Interactions( return (baseInteractions.WrapCallError(ERC20Burnable.ERC20BurnableABI, field, err)) } - ierc20Asession := &ERC20Interactions{baseInteractions, - &ierc20Session, - address, - callError, + ierc20Asession := &ERC20Interactions{ + &base.Interactions[*ERC20Burnable.ERC20BurnableSession]{ + BaseInteractions: baseInteractions, + Session: &ierc20Session, + Address: address, + CallError: callError, + }, } if err := contractextension.SimulateCall(baseInteractions.Ctx, ERC20Burnable.ERC20BurnableABI, "name", ierc20Asession); err != nil { @@ -84,55 +91,55 @@ func NewIERC20Interactions( // GetNFTAddress returns the NFT contract address. func (d *ERC20Interactions) GetAddress() common.Address { - return d.nftAddress + return d.Address } // GetSession returns the current session used for NFT interactions. func (d *ERC20Interactions) GetSession() ERC20Burnable.ERC20BurnableSession { - return *d.ierc20Session + return *d.Session } // GetBalance retrieves the balance of NFTs for the associated address. func (d *ERC20Interactions) GetBalance() (*big.Int, error) { - balance, err := d.ierc20Session.BalanceOf(d.Address) + balance, err := d.Session.BalanceOf(d.Address) if err != nil { - return nil, d.callError("erc20.BalanceOf()", err) + return nil, d.CallError("erc20.BalanceOf()", err) } return balance, nil } // TransferTo transfers a specific token to another address after verifying ownership. func (d *ERC20Interactions) TransferTo(to common.Address, amount *big.Int) (*types.Transaction, error) { - tx, err := d.ierc20Session.Transfer(to, amount) + tx, err := d.Session.Transfer(to, amount) if err != nil { - return nil, d.callError("erc20.Transfer()", err) + return nil, d.CallError("erc20.Transfer()", err) } return tx, nil } // TotalSupply returns the total number of NFTs minted. func (d *ERC20Interactions) TotalSupply() (*big.Int, error) { - supply, err := d.ierc20Session.TotalSupply() + supply, err := d.Session.TotalSupply() if err != nil { - return nil, d.callError("erc20.TotalSupply()", err) + return nil, d.CallError("erc20.TotalSupply()", err) } return supply, nil } // BalanceOf retrieves the NFT balance for a given owner. func (d *ERC20Interactions) BalanceOf(owner common.Address) (*big.Int, error) { - balance, err := d.ierc20Session.BalanceOf(owner) + balance, err := d.Session.BalanceOf(owner) if err != nil { - return nil, d.callError("erc20.BalanceOf()", err) + return nil, d.CallError("erc20.BalanceOf()", err) } return balance, nil } // Approve approves an address to transfer a specific token. func (d *ERC20Interactions) Approve(to common.Address, tokenID *big.Int) (*types.Transaction, error) { - tx, err := d.ierc20Session.Approve(to, tokenID) + tx, err := d.Session.Approve(to, tokenID) if err != nil { - return nil, d.callError("erc20.Approve()", err) + return nil, d.CallError("erc20.Approve()", err) } return tx, nil } @@ -152,26 +159,26 @@ func (d *ERC20Interactions) TokenMetaInfos() (*models.TokenMeta, error) { // Name returns the name of the NFT. func (d *ERC20Interactions) Name() (string, error) { - name, err := d.ierc20Session.Name() + name, err := d.Session.Name() if err != nil { - return "", d.callError("erc20.Name()", err) + return "", d.CallError("erc20.Name()", err) } return name, nil } // Symbol returns the symbol of the NFT. func (d *ERC20Interactions) Symbol() (string, error) { - symbol, err := d.ierc20Session.Symbol() + symbol, err := d.Session.Symbol() if err != nil { - return "", d.callError("erc20.Symbol()", err) + return "", d.CallError("erc20.Symbol()", err) } return symbol, nil } func (d *ERC20Interactions) Allowance(owner, spender common.Address) (*big.Int, error) { - allowance, err := d.ierc20Session.Allowance(owner, spender) + allowance, err := d.Session.Allowance(owner, spender) if err != nil { - return nil, d.callError("erc20.Allowance()", err) + return nil, d.CallError("erc20.Allowance()", err) } return allowance, nil } diff --git a/erc20/burnable/burnable.go b/erc20/burnable/burnable.go index a47fa05..17b9a77 100644 --- a/erc20/burnable/burnable.go +++ b/erc20/burnable/burnable.go @@ -16,14 +16,12 @@ import ( // IERC20Burnable wraps interactions with an IERC20Burnable contract, extending basic NFT interactions. type IERC20BurnableInteractions struct { - *erc20.ERC20Interactions - erc20Burnable *ERC20Burnable.ERC20BurnableSession - callError func(string, error) *base.CallError + *base.Interactions[*ERC20Burnable.ERC20BurnableSession] } // NewIERC20Burnable creates a new enumerable interaction instance using the provided base NFT interactions. -func NewIERC20Burnable(baseIERC20 *erc20.ERC20Interactions, signatures []ERC20BurnableSignatures) (*IERC20BurnableInteractions, error) { - erc20Burnable, err := ERC20Burnable.NewERC20Burnable(baseIERC20.GetAddress(), baseIERC20.Client) +func NewIERC20Burnable(baseIERC20 erc20.IERC20, signatures []ERC20BurnableSignatures) (*IERC20BurnableInteractions, error) { + erc20Burnable, err := ERC20Burnable.NewERC20Burnable(baseIERC20.GetAddress(), baseIERC20.GetBaseInteractions().Client) if err != nil { return nil, customerrors.WrapinterfacingError("ierc20Burnable", err) } @@ -44,26 +42,33 @@ func NewIERC20Burnable(baseIERC20 *erc20.ERC20Interactions, signatures []ERC20Bu } callError := func(field string, err error) *base.CallError { - return baseIERC20.WrapCallError(ERC20Burnable.ERC20BurnableABI, field, err) + return baseIERC20.GetBaseInteractions().WrapCallError(ERC20Burnable.ERC20BurnableABI, field, err) } - return &IERC20BurnableInteractions{baseIERC20, &session, callError}, nil + return &IERC20BurnableInteractions{ + &base.Interactions[*ERC20Burnable.ERC20BurnableSession]{ + BaseInteractions: baseIERC20.GetBaseInteractions(), + Session: &session, + Address: baseIERC20.GetAddress(), + CallError: callError, + }, + }, nil } // Burn destroys the specified token from the owner's balance. func (e *IERC20BurnableInteractions) Burn(qty *big.Int) (*types.Transaction, error) { - tx, err := e.erc20Burnable.Burn(qty) + tx, err := e.Session.Burn(qty) if err != nil { - return nil, e.callError("erc20.Burn()", err) + return nil, e.CallError("erc20.Burn()", err) } return tx, nil } // BurnFrom is a wrapper for Burn that calls the token's burnFrom function instead. func (e *IERC20BurnableInteractions) BurnFrom(from common.Address, qty *big.Int) (*types.Transaction, error) { - tx, err := e.erc20Burnable.BurnFrom(from, qty) + tx, err := e.Session.BurnFrom(from, qty) if err != nil { - return nil, e.callError("nft.BurnFrom()", err) + return nil, e.CallError("nft.BurnFrom()", err) } return tx, nil } diff --git a/inferences/nftPositionManager/nftPositionManager.go b/inferences/nftPositionManager/nftPositionManager.go new file mode 100644 index 0000000..65db739 --- /dev/null +++ b/inferences/nftPositionManager/nftPositionManager.go @@ -0,0 +1,864 @@ +// Code generated - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package nftPositionManager + +import ( + "errors" + "math/big" + "strings" + + ethereum "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/event" +) + +// Reference imports to suppress errors if they are not otherwise used. +var ( + _ = errors.New + _ = big.NewInt + _ = strings.NewReader + _ = ethereum.NotFound + _ = bind.Bind + _ = common.Big1 + _ = types.BloomLookup + _ = event.NewSubscription + _ = abi.ConvertType +) + +// INonfungiblePositionManagerCollectParams is an auto generated low-level Go binding around an user-defined struct. +type INonfungiblePositionManagerCollectParams struct { + TokenId *big.Int + Recipient common.Address + Amount0Max *big.Int + Amount1Max *big.Int +} + +// INonfungiblePositionManagerDecreaseLiquidityParams is an auto generated low-level Go binding around an user-defined struct. +type INonfungiblePositionManagerDecreaseLiquidityParams struct { + TokenId *big.Int + Liquidity *big.Int + Amount0Min *big.Int + Amount1Min *big.Int + Deadline *big.Int +} + +// INonfungiblePositionManagerIncreaseLiquidityParams is an auto generated low-level Go binding around an user-defined struct. +type INonfungiblePositionManagerIncreaseLiquidityParams struct { + TokenId *big.Int + Amount0Desired *big.Int + Amount1Desired *big.Int + Amount0Min *big.Int + Amount1Min *big.Int + Deadline *big.Int +} + +// INonfungiblePositionManagerMintParams is an auto generated low-level Go binding around an user-defined struct. +type INonfungiblePositionManagerMintParams struct { + Token0 common.Address + Token1 common.Address + Fee *big.Int + TickLower *big.Int + TickUpper *big.Int + Amount0Desired *big.Int + Amount1Desired *big.Int + Amount0Min *big.Int + Amount1Min *big.Int + Recipient common.Address + Deadline *big.Int +} + +// NftPositionManagerMetaData contains all meta data concerning the NftPositionManager contract. +var NftPositionManagerMetaData = &bind.MetaData{ + ABI: "[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount0\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount1\",\"type\":\"uint256\"}],\"name\":\"Collect\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint128\",\"name\":\"liquidity\",\"type\":\"uint128\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount0\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount1\",\"type\":\"uint256\"}],\"name\":\"DecreaseLiquidity\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint128\",\"name\":\"liquidity\",\"type\":\"uint128\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount0\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount1\",\"type\":\"uint256\"}],\"name\":\"IncreaseLiquidity\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"burn\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"uint128\",\"name\":\"amount0Max\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"amount1Max\",\"type\":\"uint128\"}],\"internalType\":\"structINonfungiblePositionManager.CollectParams\",\"name\":\"params\",\"type\":\"tuple\"}],\"name\":\"collect\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"amount0\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"amount1\",\"type\":\"uint256\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"},{\"internalType\":\"uint128\",\"name\":\"liquidity\",\"type\":\"uint128\"},{\"internalType\":\"uint256\",\"name\":\"amount0Min\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"amount1Min\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"}],\"internalType\":\"structINonfungiblePositionManager.DecreaseLiquidityParams\",\"name\":\"params\",\"type\":\"tuple\"}],\"name\":\"decreaseLiquidity\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"amount0\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"amount1\",\"type\":\"uint256\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"amount0Desired\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"amount1Desired\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"amount0Min\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"amount1Min\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"}],\"internalType\":\"structINonfungiblePositionManager.IncreaseLiquidityParams\",\"name\":\"params\",\"type\":\"tuple\"}],\"name\":\"increaseLiquidity\",\"outputs\":[{\"internalType\":\"uint128\",\"name\":\"liquidity\",\"type\":\"uint128\"},{\"internalType\":\"uint256\",\"name\":\"amount0\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"amount1\",\"type\":\"uint256\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"token0\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"token1\",\"type\":\"address\"},{\"internalType\":\"uint24\",\"name\":\"fee\",\"type\":\"uint24\"},{\"internalType\":\"int24\",\"name\":\"tickLower\",\"type\":\"int24\"},{\"internalType\":\"int24\",\"name\":\"tickUpper\",\"type\":\"int24\"},{\"internalType\":\"uint256\",\"name\":\"amount0Desired\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"amount1Desired\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"amount0Min\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"amount1Min\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"}],\"internalType\":\"structINonfungiblePositionManager.MintParams\",\"name\":\"params\",\"type\":\"tuple\"}],\"name\":\"mint\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"},{\"internalType\":\"uint128\",\"name\":\"liquidity\",\"type\":\"uint128\"},{\"internalType\":\"uint256\",\"name\":\"amount0\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"amount1\",\"type\":\"uint256\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"positions\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"nonce\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"token0\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"token1\",\"type\":\"address\"},{\"internalType\":\"uint24\",\"name\":\"fee\",\"type\":\"uint24\"},{\"internalType\":\"int24\",\"name\":\"tickLower\",\"type\":\"int24\"},{\"internalType\":\"int24\",\"name\":\"tickUpper\",\"type\":\"int24\"},{\"internalType\":\"uint128\",\"name\":\"liquidity\",\"type\":\"uint128\"},{\"internalType\":\"uint256\",\"name\":\"feeGrowthInside0LastX128\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"feeGrowthInside1LastX128\",\"type\":\"uint256\"},{\"internalType\":\"uint128\",\"name\":\"tokensOwed0\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"tokensOwed1\",\"type\":\"uint128\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]", +} + +// NftPositionManagerABI is the input ABI used to generate the binding from. +// Deprecated: Use NftPositionManagerMetaData.ABI instead. +var NftPositionManagerABI = NftPositionManagerMetaData.ABI + +// NftPositionManager is an auto generated Go binding around an Ethereum contract. +type NftPositionManager struct { + NftPositionManagerCaller // Read-only binding to the contract + NftPositionManagerTransactor // Write-only binding to the contract + NftPositionManagerFilterer // Log filterer for contract events +} + +// NftPositionManagerCaller is an auto generated read-only Go binding around an Ethereum contract. +type NftPositionManagerCaller struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// NftPositionManagerTransactor is an auto generated write-only Go binding around an Ethereum contract. +type NftPositionManagerTransactor struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// NftPositionManagerFilterer is an auto generated log filtering Go binding around an Ethereum contract events. +type NftPositionManagerFilterer struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// NftPositionManagerSession is an auto generated Go binding around an Ethereum contract, +// with pre-set call and transact options. +type NftPositionManagerSession struct { + Contract *NftPositionManager // Generic contract binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// NftPositionManagerCallerSession is an auto generated read-only Go binding around an Ethereum contract, +// with pre-set call options. +type NftPositionManagerCallerSession struct { + Contract *NftPositionManagerCaller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session +} + +// NftPositionManagerTransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// with pre-set transact options. +type NftPositionManagerTransactorSession struct { + Contract *NftPositionManagerTransactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// NftPositionManagerRaw is an auto generated low-level Go binding around an Ethereum contract. +type NftPositionManagerRaw struct { + Contract *NftPositionManager // Generic contract binding to access the raw methods on +} + +// NftPositionManagerCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type NftPositionManagerCallerRaw struct { + Contract *NftPositionManagerCaller // Generic read-only contract binding to access the raw methods on +} + +// NftPositionManagerTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type NftPositionManagerTransactorRaw struct { + Contract *NftPositionManagerTransactor // Generic write-only contract binding to access the raw methods on +} + +// NewNftPositionManager creates a new instance of NftPositionManager, bound to a specific deployed contract. +func NewNftPositionManager(address common.Address, backend bind.ContractBackend) (*NftPositionManager, error) { + contract, err := bindNftPositionManager(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &NftPositionManager{NftPositionManagerCaller: NftPositionManagerCaller{contract: contract}, NftPositionManagerTransactor: NftPositionManagerTransactor{contract: contract}, NftPositionManagerFilterer: NftPositionManagerFilterer{contract: contract}}, nil +} + +// NewNftPositionManagerCaller creates a new read-only instance of NftPositionManager, bound to a specific deployed contract. +func NewNftPositionManagerCaller(address common.Address, caller bind.ContractCaller) (*NftPositionManagerCaller, error) { + contract, err := bindNftPositionManager(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &NftPositionManagerCaller{contract: contract}, nil +} + +// NewNftPositionManagerTransactor creates a new write-only instance of NftPositionManager, bound to a specific deployed contract. +func NewNftPositionManagerTransactor(address common.Address, transactor bind.ContractTransactor) (*NftPositionManagerTransactor, error) { + contract, err := bindNftPositionManager(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &NftPositionManagerTransactor{contract: contract}, nil +} + +// NewNftPositionManagerFilterer creates a new log filterer instance of NftPositionManager, bound to a specific deployed contract. +func NewNftPositionManagerFilterer(address common.Address, filterer bind.ContractFilterer) (*NftPositionManagerFilterer, error) { + contract, err := bindNftPositionManager(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &NftPositionManagerFilterer{contract: contract}, nil +} + +// bindNftPositionManager binds a generic wrapper to an already deployed contract. +func bindNftPositionManager(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := NftPositionManagerMetaData.GetAbi() + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_NftPositionManager *NftPositionManagerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _NftPositionManager.Contract.NftPositionManagerCaller.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_NftPositionManager *NftPositionManagerRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _NftPositionManager.Contract.NftPositionManagerTransactor.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_NftPositionManager *NftPositionManagerRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _NftPositionManager.Contract.NftPositionManagerTransactor.contract.Transact(opts, method, params...) +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_NftPositionManager *NftPositionManagerCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _NftPositionManager.Contract.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_NftPositionManager *NftPositionManagerTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _NftPositionManager.Contract.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_NftPositionManager *NftPositionManagerTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _NftPositionManager.Contract.contract.Transact(opts, method, params...) +} + +// Positions is a free data retrieval call binding the contract method 0x99fbab88. +// +// Solidity: function positions(uint256 tokenId) view returns(uint96 nonce, address operator, address token0, address token1, uint24 fee, int24 tickLower, int24 tickUpper, uint128 liquidity, uint256 feeGrowthInside0LastX128, uint256 feeGrowthInside1LastX128, uint128 tokensOwed0, uint128 tokensOwed1) +func (_NftPositionManager *NftPositionManagerCaller) Positions(opts *bind.CallOpts, tokenId *big.Int) (struct { + Nonce *big.Int + Operator common.Address + Token0 common.Address + Token1 common.Address + Fee *big.Int + TickLower *big.Int + TickUpper *big.Int + Liquidity *big.Int + FeeGrowthInside0LastX128 *big.Int + FeeGrowthInside1LastX128 *big.Int + TokensOwed0 *big.Int + TokensOwed1 *big.Int +}, error) { + var out []interface{} + err := _NftPositionManager.contract.Call(opts, &out, "positions", tokenId) + + outstruct := new(struct { + Nonce *big.Int + Operator common.Address + Token0 common.Address + Token1 common.Address + Fee *big.Int + TickLower *big.Int + TickUpper *big.Int + Liquidity *big.Int + FeeGrowthInside0LastX128 *big.Int + FeeGrowthInside1LastX128 *big.Int + TokensOwed0 *big.Int + TokensOwed1 *big.Int + }) + if err != nil { + return *outstruct, err + } + + outstruct.Nonce = *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + outstruct.Operator = *abi.ConvertType(out[1], new(common.Address)).(*common.Address) + outstruct.Token0 = *abi.ConvertType(out[2], new(common.Address)).(*common.Address) + outstruct.Token1 = *abi.ConvertType(out[3], new(common.Address)).(*common.Address) + outstruct.Fee = *abi.ConvertType(out[4], new(*big.Int)).(**big.Int) + outstruct.TickLower = *abi.ConvertType(out[5], new(*big.Int)).(**big.Int) + outstruct.TickUpper = *abi.ConvertType(out[6], new(*big.Int)).(**big.Int) + outstruct.Liquidity = *abi.ConvertType(out[7], new(*big.Int)).(**big.Int) + outstruct.FeeGrowthInside0LastX128 = *abi.ConvertType(out[8], new(*big.Int)).(**big.Int) + outstruct.FeeGrowthInside1LastX128 = *abi.ConvertType(out[9], new(*big.Int)).(**big.Int) + outstruct.TokensOwed0 = *abi.ConvertType(out[10], new(*big.Int)).(**big.Int) + outstruct.TokensOwed1 = *abi.ConvertType(out[11], new(*big.Int)).(**big.Int) + + return *outstruct, err + +} + +// Positions is a free data retrieval call binding the contract method 0x99fbab88. +// +// Solidity: function positions(uint256 tokenId) view returns(uint96 nonce, address operator, address token0, address token1, uint24 fee, int24 tickLower, int24 tickUpper, uint128 liquidity, uint256 feeGrowthInside0LastX128, uint256 feeGrowthInside1LastX128, uint128 tokensOwed0, uint128 tokensOwed1) +func (_NftPositionManager *NftPositionManagerSession) Positions(tokenId *big.Int) (struct { + Nonce *big.Int + Operator common.Address + Token0 common.Address + Token1 common.Address + Fee *big.Int + TickLower *big.Int + TickUpper *big.Int + Liquidity *big.Int + FeeGrowthInside0LastX128 *big.Int + FeeGrowthInside1LastX128 *big.Int + TokensOwed0 *big.Int + TokensOwed1 *big.Int +}, error) { + return _NftPositionManager.Contract.Positions(&_NftPositionManager.CallOpts, tokenId) +} + +// Positions is a free data retrieval call binding the contract method 0x99fbab88. +// +// Solidity: function positions(uint256 tokenId) view returns(uint96 nonce, address operator, address token0, address token1, uint24 fee, int24 tickLower, int24 tickUpper, uint128 liquidity, uint256 feeGrowthInside0LastX128, uint256 feeGrowthInside1LastX128, uint128 tokensOwed0, uint128 tokensOwed1) +func (_NftPositionManager *NftPositionManagerCallerSession) Positions(tokenId *big.Int) (struct { + Nonce *big.Int + Operator common.Address + Token0 common.Address + Token1 common.Address + Fee *big.Int + TickLower *big.Int + TickUpper *big.Int + Liquidity *big.Int + FeeGrowthInside0LastX128 *big.Int + FeeGrowthInside1LastX128 *big.Int + TokensOwed0 *big.Int + TokensOwed1 *big.Int +}, error) { + return _NftPositionManager.Contract.Positions(&_NftPositionManager.CallOpts, tokenId) +} + +// Burn is a paid mutator transaction binding the contract method 0x42966c68. +// +// Solidity: function burn(uint256 tokenId) payable returns() +func (_NftPositionManager *NftPositionManagerTransactor) Burn(opts *bind.TransactOpts, tokenId *big.Int) (*types.Transaction, error) { + return _NftPositionManager.contract.Transact(opts, "burn", tokenId) +} + +// Burn is a paid mutator transaction binding the contract method 0x42966c68. +// +// Solidity: function burn(uint256 tokenId) payable returns() +func (_NftPositionManager *NftPositionManagerSession) Burn(tokenId *big.Int) (*types.Transaction, error) { + return _NftPositionManager.Contract.Burn(&_NftPositionManager.TransactOpts, tokenId) +} + +// Burn is a paid mutator transaction binding the contract method 0x42966c68. +// +// Solidity: function burn(uint256 tokenId) payable returns() +func (_NftPositionManager *NftPositionManagerTransactorSession) Burn(tokenId *big.Int) (*types.Transaction, error) { + return _NftPositionManager.Contract.Burn(&_NftPositionManager.TransactOpts, tokenId) +} + +// Collect is a paid mutator transaction binding the contract method 0xfc6f7865. +// +// Solidity: function collect((uint256,address,uint128,uint128) params) payable returns(uint256 amount0, uint256 amount1) +func (_NftPositionManager *NftPositionManagerTransactor) Collect(opts *bind.TransactOpts, params INonfungiblePositionManagerCollectParams) (*types.Transaction, error) { + return _NftPositionManager.contract.Transact(opts, "collect", params) +} + +// Collect is a paid mutator transaction binding the contract method 0xfc6f7865. +// +// Solidity: function collect((uint256,address,uint128,uint128) params) payable returns(uint256 amount0, uint256 amount1) +func (_NftPositionManager *NftPositionManagerSession) Collect(params INonfungiblePositionManagerCollectParams) (*types.Transaction, error) { + return _NftPositionManager.Contract.Collect(&_NftPositionManager.TransactOpts, params) +} + +// Collect is a paid mutator transaction binding the contract method 0xfc6f7865. +// +// Solidity: function collect((uint256,address,uint128,uint128) params) payable returns(uint256 amount0, uint256 amount1) +func (_NftPositionManager *NftPositionManagerTransactorSession) Collect(params INonfungiblePositionManagerCollectParams) (*types.Transaction, error) { + return _NftPositionManager.Contract.Collect(&_NftPositionManager.TransactOpts, params) +} + +// DecreaseLiquidity is a paid mutator transaction binding the contract method 0x0c49ccbe. +// +// Solidity: function decreaseLiquidity((uint256,uint128,uint256,uint256,uint256) params) payable returns(uint256 amount0, uint256 amount1) +func (_NftPositionManager *NftPositionManagerTransactor) DecreaseLiquidity(opts *bind.TransactOpts, params INonfungiblePositionManagerDecreaseLiquidityParams) (*types.Transaction, error) { + return _NftPositionManager.contract.Transact(opts, "decreaseLiquidity", params) +} + +// DecreaseLiquidity is a paid mutator transaction binding the contract method 0x0c49ccbe. +// +// Solidity: function decreaseLiquidity((uint256,uint128,uint256,uint256,uint256) params) payable returns(uint256 amount0, uint256 amount1) +func (_NftPositionManager *NftPositionManagerSession) DecreaseLiquidity(params INonfungiblePositionManagerDecreaseLiquidityParams) (*types.Transaction, error) { + return _NftPositionManager.Contract.DecreaseLiquidity(&_NftPositionManager.TransactOpts, params) +} + +// DecreaseLiquidity is a paid mutator transaction binding the contract method 0x0c49ccbe. +// +// Solidity: function decreaseLiquidity((uint256,uint128,uint256,uint256,uint256) params) payable returns(uint256 amount0, uint256 amount1) +func (_NftPositionManager *NftPositionManagerTransactorSession) DecreaseLiquidity(params INonfungiblePositionManagerDecreaseLiquidityParams) (*types.Transaction, error) { + return _NftPositionManager.Contract.DecreaseLiquidity(&_NftPositionManager.TransactOpts, params) +} + +// IncreaseLiquidity is a paid mutator transaction binding the contract method 0x219f5d17. +// +// Solidity: function increaseLiquidity((uint256,uint256,uint256,uint256,uint256,uint256) params) payable returns(uint128 liquidity, uint256 amount0, uint256 amount1) +func (_NftPositionManager *NftPositionManagerTransactor) IncreaseLiquidity(opts *bind.TransactOpts, params INonfungiblePositionManagerIncreaseLiquidityParams) (*types.Transaction, error) { + return _NftPositionManager.contract.Transact(opts, "increaseLiquidity", params) +} + +// IncreaseLiquidity is a paid mutator transaction binding the contract method 0x219f5d17. +// +// Solidity: function increaseLiquidity((uint256,uint256,uint256,uint256,uint256,uint256) params) payable returns(uint128 liquidity, uint256 amount0, uint256 amount1) +func (_NftPositionManager *NftPositionManagerSession) IncreaseLiquidity(params INonfungiblePositionManagerIncreaseLiquidityParams) (*types.Transaction, error) { + return _NftPositionManager.Contract.IncreaseLiquidity(&_NftPositionManager.TransactOpts, params) +} + +// IncreaseLiquidity is a paid mutator transaction binding the contract method 0x219f5d17. +// +// Solidity: function increaseLiquidity((uint256,uint256,uint256,uint256,uint256,uint256) params) payable returns(uint128 liquidity, uint256 amount0, uint256 amount1) +func (_NftPositionManager *NftPositionManagerTransactorSession) IncreaseLiquidity(params INonfungiblePositionManagerIncreaseLiquidityParams) (*types.Transaction, error) { + return _NftPositionManager.Contract.IncreaseLiquidity(&_NftPositionManager.TransactOpts, params) +} + +// Mint is a paid mutator transaction binding the contract method 0x88316456. +// +// Solidity: function mint((address,address,uint24,int24,int24,uint256,uint256,uint256,uint256,address,uint256) params) payable returns(uint256 tokenId, uint128 liquidity, uint256 amount0, uint256 amount1) +func (_NftPositionManager *NftPositionManagerTransactor) Mint(opts *bind.TransactOpts, params INonfungiblePositionManagerMintParams) (*types.Transaction, error) { + return _NftPositionManager.contract.Transact(opts, "mint", params) +} + +// Mint is a paid mutator transaction binding the contract method 0x88316456. +// +// Solidity: function mint((address,address,uint24,int24,int24,uint256,uint256,uint256,uint256,address,uint256) params) payable returns(uint256 tokenId, uint128 liquidity, uint256 amount0, uint256 amount1) +func (_NftPositionManager *NftPositionManagerSession) Mint(params INonfungiblePositionManagerMintParams) (*types.Transaction, error) { + return _NftPositionManager.Contract.Mint(&_NftPositionManager.TransactOpts, params) +} + +// Mint is a paid mutator transaction binding the contract method 0x88316456. +// +// Solidity: function mint((address,address,uint24,int24,int24,uint256,uint256,uint256,uint256,address,uint256) params) payable returns(uint256 tokenId, uint128 liquidity, uint256 amount0, uint256 amount1) +func (_NftPositionManager *NftPositionManagerTransactorSession) Mint(params INonfungiblePositionManagerMintParams) (*types.Transaction, error) { + return _NftPositionManager.Contract.Mint(&_NftPositionManager.TransactOpts, params) +} + +// NftPositionManagerCollectIterator is returned from FilterCollect and is used to iterate over the raw logs and unpacked data for Collect events raised by the NftPositionManager contract. +type NftPositionManagerCollectIterator struct { + Event *NftPositionManagerCollect // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *NftPositionManagerCollectIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(NftPositionManagerCollect) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(NftPositionManagerCollect) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *NftPositionManagerCollectIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *NftPositionManagerCollectIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// NftPositionManagerCollect represents a Collect event raised by the NftPositionManager contract. +type NftPositionManagerCollect struct { + TokenId *big.Int + Recipient common.Address + Amount0 *big.Int + Amount1 *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterCollect is a free log retrieval operation binding the contract event 0x40d0efd1a53d60ecbf40971b9daf7dc90178c3aadc7aab1765632738fa8b8f01. +// +// Solidity: event Collect(uint256 indexed tokenId, address recipient, uint256 amount0, uint256 amount1) +func (_NftPositionManager *NftPositionManagerFilterer) FilterCollect(opts *bind.FilterOpts, tokenId []*big.Int) (*NftPositionManagerCollectIterator, error) { + + var tokenIdRule []interface{} + for _, tokenIdItem := range tokenId { + tokenIdRule = append(tokenIdRule, tokenIdItem) + } + + logs, sub, err := _NftPositionManager.contract.FilterLogs(opts, "Collect", tokenIdRule) + if err != nil { + return nil, err + } + return &NftPositionManagerCollectIterator{contract: _NftPositionManager.contract, event: "Collect", logs: logs, sub: sub}, nil +} + +// WatchCollect is a free log subscription operation binding the contract event 0x40d0efd1a53d60ecbf40971b9daf7dc90178c3aadc7aab1765632738fa8b8f01. +// +// Solidity: event Collect(uint256 indexed tokenId, address recipient, uint256 amount0, uint256 amount1) +func (_NftPositionManager *NftPositionManagerFilterer) WatchCollect(opts *bind.WatchOpts, sink chan<- *NftPositionManagerCollect, tokenId []*big.Int) (event.Subscription, error) { + + var tokenIdRule []interface{} + for _, tokenIdItem := range tokenId { + tokenIdRule = append(tokenIdRule, tokenIdItem) + } + + logs, sub, err := _NftPositionManager.contract.WatchLogs(opts, "Collect", tokenIdRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(NftPositionManagerCollect) + if err := _NftPositionManager.contract.UnpackLog(event, "Collect", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseCollect is a log parse operation binding the contract event 0x40d0efd1a53d60ecbf40971b9daf7dc90178c3aadc7aab1765632738fa8b8f01. +// +// Solidity: event Collect(uint256 indexed tokenId, address recipient, uint256 amount0, uint256 amount1) +func (_NftPositionManager *NftPositionManagerFilterer) ParseCollect(log types.Log) (*NftPositionManagerCollect, error) { + event := new(NftPositionManagerCollect) + if err := _NftPositionManager.contract.UnpackLog(event, "Collect", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// NftPositionManagerDecreaseLiquidityIterator is returned from FilterDecreaseLiquidity and is used to iterate over the raw logs and unpacked data for DecreaseLiquidity events raised by the NftPositionManager contract. +type NftPositionManagerDecreaseLiquidityIterator struct { + Event *NftPositionManagerDecreaseLiquidity // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *NftPositionManagerDecreaseLiquidityIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(NftPositionManagerDecreaseLiquidity) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(NftPositionManagerDecreaseLiquidity) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *NftPositionManagerDecreaseLiquidityIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *NftPositionManagerDecreaseLiquidityIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// NftPositionManagerDecreaseLiquidity represents a DecreaseLiquidity event raised by the NftPositionManager contract. +type NftPositionManagerDecreaseLiquidity struct { + TokenId *big.Int + Liquidity *big.Int + Amount0 *big.Int + Amount1 *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterDecreaseLiquidity is a free log retrieval operation binding the contract event 0x26f6a048ee9138f2c0ce266f322cb99228e8d619ae2bff30c67f8dcf9d2377b4. +// +// Solidity: event DecreaseLiquidity(uint256 indexed tokenId, uint128 liquidity, uint256 amount0, uint256 amount1) +func (_NftPositionManager *NftPositionManagerFilterer) FilterDecreaseLiquidity(opts *bind.FilterOpts, tokenId []*big.Int) (*NftPositionManagerDecreaseLiquidityIterator, error) { + + var tokenIdRule []interface{} + for _, tokenIdItem := range tokenId { + tokenIdRule = append(tokenIdRule, tokenIdItem) + } + + logs, sub, err := _NftPositionManager.contract.FilterLogs(opts, "DecreaseLiquidity", tokenIdRule) + if err != nil { + return nil, err + } + return &NftPositionManagerDecreaseLiquidityIterator{contract: _NftPositionManager.contract, event: "DecreaseLiquidity", logs: logs, sub: sub}, nil +} + +// WatchDecreaseLiquidity is a free log subscription operation binding the contract event 0x26f6a048ee9138f2c0ce266f322cb99228e8d619ae2bff30c67f8dcf9d2377b4. +// +// Solidity: event DecreaseLiquidity(uint256 indexed tokenId, uint128 liquidity, uint256 amount0, uint256 amount1) +func (_NftPositionManager *NftPositionManagerFilterer) WatchDecreaseLiquidity(opts *bind.WatchOpts, sink chan<- *NftPositionManagerDecreaseLiquidity, tokenId []*big.Int) (event.Subscription, error) { + + var tokenIdRule []interface{} + for _, tokenIdItem := range tokenId { + tokenIdRule = append(tokenIdRule, tokenIdItem) + } + + logs, sub, err := _NftPositionManager.contract.WatchLogs(opts, "DecreaseLiquidity", tokenIdRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(NftPositionManagerDecreaseLiquidity) + if err := _NftPositionManager.contract.UnpackLog(event, "DecreaseLiquidity", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseDecreaseLiquidity is a log parse operation binding the contract event 0x26f6a048ee9138f2c0ce266f322cb99228e8d619ae2bff30c67f8dcf9d2377b4. +// +// Solidity: event DecreaseLiquidity(uint256 indexed tokenId, uint128 liquidity, uint256 amount0, uint256 amount1) +func (_NftPositionManager *NftPositionManagerFilterer) ParseDecreaseLiquidity(log types.Log) (*NftPositionManagerDecreaseLiquidity, error) { + event := new(NftPositionManagerDecreaseLiquidity) + if err := _NftPositionManager.contract.UnpackLog(event, "DecreaseLiquidity", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// NftPositionManagerIncreaseLiquidityIterator is returned from FilterIncreaseLiquidity and is used to iterate over the raw logs and unpacked data for IncreaseLiquidity events raised by the NftPositionManager contract. +type NftPositionManagerIncreaseLiquidityIterator struct { + Event *NftPositionManagerIncreaseLiquidity // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *NftPositionManagerIncreaseLiquidityIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(NftPositionManagerIncreaseLiquidity) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(NftPositionManagerIncreaseLiquidity) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *NftPositionManagerIncreaseLiquidityIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *NftPositionManagerIncreaseLiquidityIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// NftPositionManagerIncreaseLiquidity represents a IncreaseLiquidity event raised by the NftPositionManager contract. +type NftPositionManagerIncreaseLiquidity struct { + TokenId *big.Int + Liquidity *big.Int + Amount0 *big.Int + Amount1 *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterIncreaseLiquidity is a free log retrieval operation binding the contract event 0x3067048beee31b25b2f1681f88dac838c8bba36af25bfb2b7cf7473a5847e35f. +// +// Solidity: event IncreaseLiquidity(uint256 indexed tokenId, uint128 liquidity, uint256 amount0, uint256 amount1) +func (_NftPositionManager *NftPositionManagerFilterer) FilterIncreaseLiquidity(opts *bind.FilterOpts, tokenId []*big.Int) (*NftPositionManagerIncreaseLiquidityIterator, error) { + + var tokenIdRule []interface{} + for _, tokenIdItem := range tokenId { + tokenIdRule = append(tokenIdRule, tokenIdItem) + } + + logs, sub, err := _NftPositionManager.contract.FilterLogs(opts, "IncreaseLiquidity", tokenIdRule) + if err != nil { + return nil, err + } + return &NftPositionManagerIncreaseLiquidityIterator{contract: _NftPositionManager.contract, event: "IncreaseLiquidity", logs: logs, sub: sub}, nil +} + +// WatchIncreaseLiquidity is a free log subscription operation binding the contract event 0x3067048beee31b25b2f1681f88dac838c8bba36af25bfb2b7cf7473a5847e35f. +// +// Solidity: event IncreaseLiquidity(uint256 indexed tokenId, uint128 liquidity, uint256 amount0, uint256 amount1) +func (_NftPositionManager *NftPositionManagerFilterer) WatchIncreaseLiquidity(opts *bind.WatchOpts, sink chan<- *NftPositionManagerIncreaseLiquidity, tokenId []*big.Int) (event.Subscription, error) { + + var tokenIdRule []interface{} + for _, tokenIdItem := range tokenId { + tokenIdRule = append(tokenIdRule, tokenIdItem) + } + + logs, sub, err := _NftPositionManager.contract.WatchLogs(opts, "IncreaseLiquidity", tokenIdRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(NftPositionManagerIncreaseLiquidity) + if err := _NftPositionManager.contract.UnpackLog(event, "IncreaseLiquidity", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseIncreaseLiquidity is a log parse operation binding the contract event 0x3067048beee31b25b2f1681f88dac838c8bba36af25bfb2b7cf7473a5847e35f. +// +// Solidity: event IncreaseLiquidity(uint256 indexed tokenId, uint128 liquidity, uint256 amount0, uint256 amount1) +func (_NftPositionManager *NftPositionManagerFilterer) ParseIncreaseLiquidity(log types.Log) (*NftPositionManagerIncreaseLiquidity, error) { + event := new(NftPositionManagerIncreaseLiquidity) + if err := _NftPositionManager.contract.UnpackLog(event, "IncreaseLiquidity", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} diff --git a/nft/base.go b/nft/base.go index 5bb8b21..ad9f7e9 100644 --- a/nft/base.go +++ b/nft/base.go @@ -22,10 +22,14 @@ import ( // ERC721Interactions wraps NFT interactions using an underlying base interaction and an ERC721A session. type ERC721Interactions struct { - *base.BaseInteractions - erc721Session *ERC721Complete.ERC721CompleteSession - nftAddress common.Address - callError func(string, error) *base.CallError + *base.Interactions[*ERC721Complete.ERC721CompleteSession] +} + +type INFT interface { + GetAddress() common.Address + CheckSignatures(address common.Address, signatures []utils.Signature) error + GetSession() ERC721Complete.ERC721CompleteSession + GetBaseInteractions() *base.BaseInteractions } // NewERC721Interactions creates a new instance of ERC721Interactions from a base interaction interface and an NFT contract address. @@ -70,43 +74,42 @@ func NewERC721Interactions( return baseInteractions.WrapCallError(ERC721Complete.ERC721CompleteABI, field, err) } - erc721Interactions := &ERC721Interactions{baseInteractions, - &erc721ASession, - address, - callError, + erc721Interactions := &ERC721Interactions{ + &base.Interactions[*ERC721Complete.ERC721CompleteSession]{ + BaseInteractions: baseInteractions, + Session: &erc721ASession, + Address: address, + CallError: callError, + }, } - - if err := contractextension.SimulateCall(baseInteractions.Ctx, ERC721Complete.ERC721CompleteABI, "name", erc721Interactions); err != nil { - return nil, err + if len(signatures) > 0 { + if err := contractextension.SimulateCall(baseInteractions.Ctx, ERC721Complete.ERC721CompleteABI, string(signatures[0]), erc721Interactions); err != nil { + return nil, err + } } return erc721Interactions, nil } -// GetNFTAddress returns the NFT contract address. -func (d *ERC721Interactions) GetAddress() common.Address { - return d.nftAddress -} - // GetSession returns the current session used for NFT interactions. func (d *ERC721Interactions) GetSession() ERC721Complete.ERC721CompleteSession { - return *d.erc721Session + return *d.Session } // GetBalance retrieves the balance of NFTs for the associated address. func (d *ERC721Interactions) GetBalance() (*big.Int, error) { - balance, err := d.erc721Session.BalanceOf(d.Address) + balance, err := d.Session.BalanceOf(d.Address) if err != nil { - return nil, d.callError("nft.BalanceOf()", err) + return nil, d.CallError("nft.BalanceOf()", err) } return balance, nil } // TransferTo transfers a specific token to another address after verifying ownership. func (d *ERC721Interactions) TransferTo(to common.Address, tokenID *big.Int) (*types.Transaction, error) { - tx, err := d.erc721Session.TransferFrom(d.Address, to, tokenID) + tx, err := d.Session.TransferFrom(d.Address, to, tokenID) if err != nil { - return nil, d.callError("nft.TransferFrom()", err) + return nil, d.CallError("nft.TransferFrom()", err) } return tx, nil } @@ -135,36 +138,36 @@ func (d *ERC721Interactions) TransferFirstOwnedTo(to common.Address) (*types.Tra // TotalSupply returns the total number of NFTs minted. func (d *ERC721Interactions) TotalSupply() (*big.Int, error) { - supply, err := d.erc721Session.TotalSupply() + supply, err := d.Session.TotalSupply() if err != nil { - return nil, d.callError("nft.TotalSupply()", err) + return nil, d.CallError("nft.TotalSupply()", err) } return supply, nil } // BalanceOf retrieves the NFT balance for a given owner. func (d *ERC721Interactions) BalanceOf(owner common.Address) (*big.Int, error) { - balance, err := d.erc721Session.BalanceOf(owner) + balance, err := d.Session.BalanceOf(owner) if err != nil { - return nil, d.callError("nft.BalanceOf()", err) + return nil, d.CallError("nft.BalanceOf()", err) } return balance, nil } // OwnerOf retrieves the owner of a specific token. func (d *ERC721Interactions) OwnerOf(tokenID *big.Int) (common.Address, error) { - owner, err := d.erc721Session.OwnerOf(tokenID) + owner, err := d.Session.OwnerOf(tokenID) if err != nil { - return common.Address{}, d.callError("nft.OwnerOf()", err) + return common.Address{}, d.CallError("nft.OwnerOf()", err) } return owner, nil } // Approve approves an address to transfer a specific token. func (d *ERC721Interactions) Approve(to common.Address, tokenID *big.Int) (*types.Transaction, error) { - tx, err := d.erc721Session.Approve(to, tokenID) + tx, err := d.Session.Approve(to, tokenID) if err != nil { - return nil, d.callError("nft.Approve()", err) + return nil, d.CallError("nft.Approve()", err) } return tx, nil } @@ -190,36 +193,36 @@ func (d *ERC721Interactions) TokenMetaInfos(tokenID *big.Int) (*models.TokenMeta // Name returns the name of the NFT. func (d *ERC721Interactions) Name() (string, error) { - name, err := d.erc721Session.Name() + name, err := d.Session.Name() if err != nil { - return "", d.callError("nft.Name()", err) + return "", d.CallError("nft.Name()", err) } return name, nil } // Symbol returns the symbol of the NFT. func (d *ERC721Interactions) Symbol() (string, error) { - symbol, err := d.erc721Session.Symbol() + symbol, err := d.Session.Symbol() if err != nil { - return "", d.callError("nft.Symbol()", err) + return "", d.CallError("nft.Symbol()", err) } return symbol, nil } // TokenURI returns the URI of the NFT. func (d *ERC721Interactions) TokenURI(tokenID *big.Int) (string, error) { - uri, err := d.erc721Session.TokenURI(tokenID) + uri, err := d.Session.TokenURI(tokenID) if err != nil { - return "", d.callError("nft.TokenURI()", err) + return "", d.CallError("nft.TokenURI()", err) } return uri, nil } // GetApproved returns the approved address for a specific token. func (d *ERC721Interactions) GetApproved(tokenID *big.Int) (common.Address, error) { - approved, err := d.erc721Session.GetApproved(tokenID) + approved, err := d.Session.GetApproved(tokenID) if err != nil { - return common.Address{}, d.callError("nft.GetApproved()", err) + return common.Address{}, d.CallError("nft.GetApproved()", err) } return approved, nil } diff --git a/nft/enumerable/enumerable.go b/nft/enumerable/enumerable.go index 1e8e924..3e0872d 100644 --- a/nft/enumerable/enumerable.go +++ b/nft/enumerable/enumerable.go @@ -15,14 +15,12 @@ import ( // ERC721EnumerableInteractions wraps interactions with an ERC721Enumerable contract, extending basic NFT interactions. type ERC721EnumerableInteractions struct { - *nft.ERC721Interactions - ierc721Enumerable *ERC721Complete.ERC721CompleteSession - callError func(string, error) *base.CallError + *base.Interactions[*ERC721Complete.ERC721CompleteSession] } // NewERC721EnumerableInteractions creates a new enumerable interaction instance using the provided base NFT interactions. -func NewERC721EnumerableInteractions(baseIERC721 *nft.ERC721Interactions, signatures []IERC721EnumerableSignature) (*ERC721EnumerableInteractions, error) { - ierc721Enumerable, err := ERC721Complete.NewERC721Complete(baseIERC721.GetAddress(), baseIERC721.Client) +func NewERC721EnumerableInteractions(baseIERC721 nft.INFT, signatures []IERC721EnumerableSignature) (*ERC721EnumerableInteractions, error) { + ierc721Enumerable, err := ERC721Complete.NewERC721Complete(baseIERC721.GetAddress(), baseIERC721.GetBaseInteractions().Client) if err != nil { return nil, customerrors.WrapinterfacingError("erc721Enumerable", err) } @@ -38,7 +36,7 @@ func NewERC721EnumerableInteractions(baseIERC721 *nft.ERC721Interactions, signat } callError := func(field string, err error) *base.CallError { - return baseIERC721.WrapCallError(ERC721Complete.ERC721CompleteABI, field, err) + return baseIERC721.GetBaseInteractions().WrapCallError(ERC721Complete.ERC721CompleteABI, field, err) } err = baseIERC721.CheckSignatures(baseIERC721.GetAddress(), converted) @@ -46,12 +44,19 @@ func NewERC721EnumerableInteractions(baseIERC721 *nft.ERC721Interactions, signat return nil, customerrors.WrapinterfacingError("erc721Enumerable", err) } - return &ERC721EnumerableInteractions{baseIERC721, &session, callError}, nil + return &ERC721EnumerableInteractions{ + &base.Interactions[*ERC721Complete.ERC721CompleteSession]{ + BaseInteractions: baseIERC721.GetBaseInteractions(), + Session: &session, + Address: baseIERC721.GetAddress(), + CallError: callError, + }, + }, nil } // GetAddressOwnedTokens returns a slice of token IDs owned by the specified address. func (e *ERC721EnumerableInteractions) GetAddressOwnedTokens(to common.Address) ([]*big.Int, error) { - balance, err := e.BalanceOf(to) + balance, err := e.Session.BalanceOf(to) if err != nil { return nil, err } @@ -59,7 +64,7 @@ func (e *ERC721EnumerableInteractions) GetAddressOwnedTokens(to common.Address) for i := range balance.Int64() { tokenID, err := e.TokenOfOwnerByIndex(to, big.NewInt(i)) if err != nil { - return nil, e.callError("nft.TokenOfOwnerByIndex()", err) + return nil, e.CallError("nft.TokenOfOwnerByIndex()", err) } tokenIDs = append(tokenIDs, tokenID) } @@ -68,7 +73,7 @@ func (e *ERC721EnumerableInteractions) GetAddressOwnedTokens(to common.Address) // GetAllTokenIDs returns all token IDs available in the contract. func (e *ERC721EnumerableInteractions) GetAllTokenIDs() ([]*big.Int, error) { - supply, err := e.TotalSupply() + supply, err := e.Session.TotalSupply() if err != nil { return nil, err } @@ -76,7 +81,7 @@ func (e *ERC721EnumerableInteractions) GetAllTokenIDs() ([]*big.Int, error) { for i := range supply.Int64() { tokenID, err := e.TokenByIndex(big.NewInt(i)) if err != nil { - return nil, e.callError("nft.TokenByIndex()", err) + return nil, e.CallError("nft.TokenByIndex()", err) } tokenIDs = append(tokenIDs, tokenID) } @@ -85,18 +90,18 @@ func (e *ERC721EnumerableInteractions) GetAllTokenIDs() ([]*big.Int, error) { // TokenOfOwnerByIndex returns the token ID belonging to a specified address at a given index. func (e *ERC721EnumerableInteractions) TokenOfOwnerByIndex(to common.Address, index *big.Int) (*big.Int, error) { - tokenID, err := e.ierc721Enumerable.TokenOfOwnerByIndex(to, index) + tokenID, err := e.Session.TokenOfOwnerByIndex(to, index) if err != nil { - return nil, e.callError("nft.TokenOfOwnerByIndex()", err) + return nil, e.CallError("nft.TokenOfOwnerByIndex()", err) } return tokenID, nil } // TokenByIndex returns the token ID at a specific index in the contract. func (e *ERC721EnumerableInteractions) TokenByIndex(index *big.Int) (*big.Int, error) { - tokenID, err := e.ierc721Enumerable.TokenByIndex(index) + tokenID, err := e.Session.TokenByIndex(index) if err != nil { - return nil, e.callError("nft.TokenByIndex()", err) + return nil, e.CallError("nft.TokenByIndex()", err) } return tokenID, nil } diff --git a/nft/royalties/royalties.go b/nft/royalties/royalties.go index 7f4667c..d94f15b 100644 --- a/nft/royalties/royalties.go +++ b/nft/royalties/royalties.go @@ -15,9 +15,7 @@ import ( // IERC721RoyaltiesInteractions wraps interactions with the IERC721Royalties contract. type IERC721RoyaltiesInteractions struct { - *nft.ERC721Interactions - ierc721Royalties *ERC721Complete.ERC721CompleteSession - callError func(string, error) *base.CallError + *base.Interactions[*ERC721Complete.ERC721CompleteSession] } // RoyaltyInfos holds the royalty receiver and amount for a token sale. @@ -27,8 +25,8 @@ type RoyaltyInfos struct { } // NewIERC721RoyaltiesInteractions creates a new instance of IERC721RoyaltiesInteractions. -func NewERC721RoyaltiesInteractions(baseIERC721 *nft.ERC721Interactions, signatures []IERC721RoyaltiesSignature) (*IERC721RoyaltiesInteractions, error) { - ierc721Royalties, err := ERC721Complete.NewERC721Complete(baseIERC721.GetAddress(), baseIERC721.Client) +func NewERC721RoyaltiesInteractions(baseIERC721 nft.INFT, signatures []IERC721RoyaltiesSignature) (*IERC721RoyaltiesInteractions, error) { + ierc721Royalties, err := ERC721Complete.NewERC721Complete(baseIERC721.GetAddress(), baseIERC721.GetBaseInteractions().Client) session := ERC721Complete.ERC721CompleteSession{ Contract: ierc721Royalties, CallOpts: baseIERC721.GetSession().CallOpts, @@ -49,17 +47,24 @@ func NewERC721RoyaltiesInteractions(baseIERC721 *nft.ERC721Interactions, signatu } callError := func(field string, err error) *base.CallError { - return baseIERC721.WrapCallError(ERC721Complete.ERC721CompleteABI, "nft.RoyaltyInfo()", err) + return baseIERC721.GetBaseInteractions().WrapCallError(ERC721Complete.ERC721CompleteABI, "nft.RoyaltyInfo()", err) } - return &IERC721RoyaltiesInteractions{baseIERC721, &session, callError}, nil + return &IERC721RoyaltiesInteractions{ + &base.Interactions[*ERC721Complete.ERC721CompleteSession]{ + BaseInteractions: baseIERC721.GetBaseInteractions(), + Session: &session, + Address: baseIERC721.GetAddress(), + CallError: callError, + }, + }, nil } // RoyaltiesInfos retrieves the royalty information for a given token and sale price. func (e *IERC721RoyaltiesInteractions) RoyaltiesInfos(tokenID *big.Int, salePrice *big.Int) (RoyaltyInfos, error) { - rInfos, err := e.ierc721Royalties.RoyaltyInfo(tokenID, salePrice) + rInfos, err := e.Session.RoyaltyInfo(tokenID, salePrice) if err != nil { - return RoyaltyInfos{}, e.callError("nft.RoyaltyInfo()", err) + return RoyaltyInfos{}, e.CallError("nft.RoyaltyInfo()", err) } return rInfos, nil }