Skip to content

Commit 23c964d

Browse files
feat: add fee estimation nfts (#594)
* feat: add fee estimation nfts * fix: resolve PR issues * chore: changeset for NFT fee calculations
1 parent e6b7155 commit 23c964d

File tree

4 files changed

+162
-69
lines changed

4 files changed

+162
-69
lines changed

.changeset/sharp-camels-help.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
---
2+
'@chainify/client': patch
3+
'@chainify/evm': patch
4+
'@chainify/solana': patch
5+
'@chainify/bitcoin': patch
6+
'@chainify/bitcoin-ledger': patch
7+
'@chainify/errors': patch
8+
'@chainify/evm-contracts': patch
9+
'@chainify/evm-ledger': patch
10+
'@chainify/hw-ledger': patch
11+
'@chainify/logger': patch
12+
'@chainify/near': patch
13+
'@chainify/terra': patch
14+
'@chainify/types': patch
15+
'@chainify/utils': patch
16+
---
17+
18+
fee estimation for NFTs

packages/client/lib/Nft.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { UnsupportedMethodError } from '@chainify/errors';
12
import { AddressType, BigNumber, FeeType, NFTAsset, Transaction } from '@chainify/types';
23
import Wallet from './Wallet';
34

@@ -33,5 +34,23 @@ export default abstract class Nft<T, S> {
3334

3435
public abstract isApprovedForAll(contract: AddressType, operator: AddressType): Promise<boolean>;
3536

37+
public estimateTransfer(
38+
_contractAddress: AddressType,
39+
_receiver: AddressType,
40+
_tokenIDs: string[],
41+
_amounts?: number[],
42+
_data?: string
43+
): Promise<BigNumber> {
44+
throw new UnsupportedMethodError('Method not supported');
45+
}
46+
47+
public estimateApprove(_contract: AddressType, _operator: AddressType, _tokenID: number): Promise<BigNumber> {
48+
throw new UnsupportedMethodError('Method not supported');
49+
}
50+
51+
public estimateApproveAll(_contract: AddressType, _operator: AddressType, _state: boolean): Promise<BigNumber> {
52+
throw new UnsupportedMethodError('Method not supported');
53+
}
54+
3655
public abstract fetch(): Promise<NFTAsset[]>;
3756
}

packages/evm/lib/nft/EvmNftProvider.ts

Lines changed: 116 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ export abstract class EvmNftProvider extends Nft<BaseProvider, Signer> {
1818

1919
protected schemas: Record<string, NftContract>;
2020
protected cache: Record<string, NftInfo>;
21+
protected walletProvider: EvmBaseWalletProvider<BaseProvider>;
2122

2223
constructor(walletProvider: EvmBaseWalletProvider<BaseProvider>) {
2324
super(walletProvider);
@@ -36,37 +37,7 @@ export abstract class EvmNftProvider extends Nft<BaseProvider, Signer> {
3637
data = '0x',
3738
fee?: FeeType
3839
): Promise<Transaction<EthersTransactionResponse>> {
39-
const { schema, contract } = await this._cacheGet(contractAddress);
40-
const owner = (await this.walletProvider.getAddress()).toString();
41-
const to = receiver.toString();
42-
43-
let tx: EthersPopulatedTransaction;
44-
45-
switch (schema) {
46-
case NftTypes.ERC721: {
47-
if (tokenIDs.length !== 1) {
48-
throw new Error(`nft.transfer supports exactly 1 tokenID transfer for ERC721. received ${tokenIDs.join(', ')}`);
49-
}
50-
const _contract: ERC721 = contract as ERC721;
51-
tx = await _contract.populateTransaction['safeTransferFrom(address,address,uint256,bytes)'](owner, to, tokenIDs[0], data);
52-
break;
53-
}
54-
55-
case NftTypes.ERC1155: {
56-
const _contract: ERC1155 = contract as ERC1155;
57-
if (tokenIDs.length > 1) {
58-
tx = await _contract.populateTransaction.safeBatchTransferFrom(owner, to, tokenIDs, amounts, data);
59-
} else {
60-
tx = await _contract.populateTransaction.safeTransferFrom(owner, to, tokenIDs[0], amounts[0], data);
61-
}
62-
break;
63-
}
64-
65-
default: {
66-
throw new UnsupportedMethodError(`Unsupported NFT type: ${schema}`);
67-
}
68-
}
69-
40+
const tx = await this.populateTrasnfer(contractAddress, receiver, tokenIDs, amounts, data);
7041
return await this.walletProvider.sendTransaction(toEthereumTxRequest(tx, fee));
7142
}
7243

@@ -103,29 +74,17 @@ export abstract class EvmNftProvider extends Nft<BaseProvider, Signer> {
10374
tokenID: number,
10475
fee?: FeeType
10576
): Promise<Transaction<EthersTransactionResponse>> {
106-
const { schema, contract } = await this._cacheGet(contractAddress);
107-
const _operator = operator.toString();
108-
109-
let tx: EthersPopulatedTransaction;
110-
111-
switch (schema) {
112-
case NftTypes.ERC721: {
113-
const _contract: ERC721 = contract as ERC721;
114-
tx = await _contract.populateTransaction.approve(_operator, tokenID);
115-
break;
116-
}
117-
118-
case NftTypes.ERC1155: {
119-
const _contract: ERC1155 = contract as ERC1155;
120-
tx = await _contract.populateTransaction.setApprovalForAll(_operator, true);
121-
break;
122-
}
123-
124-
default: {
125-
throw new UnsupportedMethodError(`Unsupported NFT type: ${schema}`);
126-
}
127-
}
77+
const tx = await this.populateApprove(contractAddress, operator, tokenID);
78+
return this.walletProvider.sendTransaction(toEthereumTxRequest(tx, fee));
79+
}
12880

81+
public async approveAll(
82+
contractAddress: AddressType,
83+
operator: AddressType,
84+
state: boolean,
85+
fee?: FeeType
86+
): Promise<Transaction<EthersTransactionResponse>> {
87+
const tx = await this.populateApproveAll(contractAddress, operator, state);
12988
return this.walletProvider.sendTransaction(toEthereumTxRequest(tx, fee));
13089
}
13190

@@ -135,15 +94,28 @@ export abstract class EvmNftProvider extends Nft<BaseProvider, Signer> {
13594
return await contract.isApprovedForAll(owner.toString(), operator.toString());
13695
}
13796

138-
public async approveAll(
97+
public async estimateTransfer(
13998
contractAddress: AddressType,
140-
operator: AddressType,
141-
state: boolean,
142-
fee?: FeeType
143-
): Promise<Transaction<EthersTransactionResponse>> {
144-
const { contract } = await this._cacheGet(contractAddress);
145-
const tx = await contract.populateTransaction.setApprovalForAll(operator.toString(), state);
146-
return this.walletProvider.sendTransaction(toEthereumTxRequest(tx, fee));
99+
receiver: AddressType,
100+
tokenIDs: string[],
101+
amounts?: number[],
102+
data = '0x'
103+
): Promise<BigNumber> {
104+
const tx = await this.populateTrasnfer(contractAddress, receiver, tokenIDs, amounts, data);
105+
const estimation = await this.walletProvider.estimateGas(tx);
106+
return new BigNumber(estimation.toString());
107+
}
108+
109+
public async estimateApprove(contractAddress: AddressType, operator: AddressType, tokenID: number): Promise<BigNumber> {
110+
const tx = await this.populateApprove(contractAddress, operator, tokenID);
111+
const estimation = await this.walletProvider.estimateGas(tx);
112+
return new BigNumber(estimation.toString());
113+
}
114+
115+
public async estimateApproveAll(contractAddress: AddressType, operator: AddressType, state: boolean): Promise<BigNumber> {
116+
const tx = await this.populateApproveAll(contractAddress, operator, state);
117+
const estimation = await this.walletProvider.estimateGas(tx);
118+
return new BigNumber(estimation.toString());
147119
}
148120

149121
async fetch(): Promise<NFTAsset[]> {
@@ -181,4 +153,87 @@ export abstract class EvmNftProvider extends Nft<BaseProvider, Signer> {
181153

182154
throw new UnsupportedMethodError(`Cannot find the data for ${_contractAddress}`);
183155
}
156+
157+
private async populateApprove(
158+
contractAddress: AddressType,
159+
operator: AddressType,
160+
tokenID: number
161+
): Promise<EthersPopulatedTransaction> {
162+
const { schema, contract } = await this._cacheGet(contractAddress);
163+
const _operator = operator.toString();
164+
165+
let tx: EthersPopulatedTransaction;
166+
167+
switch (schema) {
168+
case NftTypes.ERC721: {
169+
const _contract: ERC721 = contract as ERC721;
170+
tx = await _contract.populateTransaction.approve(_operator, tokenID);
171+
break;
172+
}
173+
174+
case NftTypes.ERC1155: {
175+
const _contract: ERC1155 = contract as ERC1155;
176+
tx = await _contract.populateTransaction.setApprovalForAll(_operator, true);
177+
break;
178+
}
179+
180+
default: {
181+
throw new UnsupportedMethodError(`Unsupported NFT type: ${schema}`);
182+
}
183+
}
184+
185+
return tx;
186+
}
187+
188+
private async populateTrasnfer(
189+
contractAddress: AddressType,
190+
receiver: AddressType,
191+
tokenIDs: string[],
192+
amounts?: number[],
193+
data = '0x'
194+
): Promise<EthersPopulatedTransaction> {
195+
const { schema, contract } = await this._cacheGet(contractAddress);
196+
const owner = (await this.walletProvider.getAddress()).toString();
197+
const to = receiver.toString();
198+
199+
let tx: EthersPopulatedTransaction;
200+
201+
switch (schema) {
202+
case NftTypes.ERC721: {
203+
if (tokenIDs.length !== 1) {
204+
throw new Error(`nft.transfer supports exactly 1 tokenID transfer for ERC721. received ${tokenIDs.join(', ')}`);
205+
}
206+
const _contract: ERC721 = contract as ERC721;
207+
tx = await _contract.populateTransaction['safeTransferFrom(address,address,uint256,bytes)'](owner, to, tokenIDs[0], data);
208+
break;
209+
}
210+
211+
case NftTypes.ERC1155: {
212+
const _contract: ERC1155 = contract as ERC1155;
213+
if (tokenIDs.length > 1) {
214+
tx = await _contract.populateTransaction.safeBatchTransferFrom(owner, to, tokenIDs, amounts, data);
215+
} else {
216+
tx = await _contract.populateTransaction.safeTransferFrom(owner, to, tokenIDs[0], amounts[0], data);
217+
}
218+
break;
219+
}
220+
221+
default: {
222+
throw new UnsupportedMethodError(`Unsupported NFT type: ${schema}`);
223+
}
224+
}
225+
226+
return tx;
227+
}
228+
229+
private async populateApproveAll(
230+
contractAddress: AddressType,
231+
operator: AddressType,
232+
state: boolean
233+
): Promise<EthersPopulatedTransaction> {
234+
const { contract } = await this._cacheGet(contractAddress);
235+
const tx = await contract.populateTransaction.setApprovalForAll(operator.toString(), state);
236+
237+
return tx;
238+
}
184239
}

packages/solana/lib/nft/SolanaNftProvider.ts

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { HttpClient, Nft, Wallet } from '@chainify/client';
2+
import { UnsupportedMethodError } from '@chainify/errors';
23
import { AddressType, BigNumber, ChainId, NFTAsset, Transaction } from '@chainify/types';
34
import { BaseProvider } from '@ethersproject/providers';
45
import Moralis from 'moralis/node';
@@ -90,16 +91,16 @@ export class SolanaNftProvider extends Nft<BaseProvider, SolanaWalletProvider> {
9091
});
9192
}
9293

93-
balanceOf(_: AddressType, __: AddressType[], ___: number[]): Promise<BigNumber | BigNumber[]> {
94-
throw new Error('Method not implemented.');
94+
balanceOf(_contractAddress: AddressType, _owners: AddressType[], _tokenIDs: number[]): Promise<BigNumber | BigNumber[]> {
95+
throw new UnsupportedMethodError('Method not supported');
9596
}
96-
approve(_: AddressType, __: AddressType, ___: number): Promise<Transaction<any>> {
97-
throw new Error('Method not implemented.');
97+
approve(_contract: AddressType, _operator: AddressType, _tokenID: number): Promise<Transaction<any>> {
98+
throw new UnsupportedMethodError('Method not supported');
9899
}
99-
approveAll(_: AddressType, __: AddressType, ___: boolean): Promise<Transaction<any>> {
100-
throw new Error('Method not implemented.');
100+
approveAll(_contract: AddressType, _operator: AddressType, _state: boolean): Promise<Transaction<any>> {
101+
throw new UnsupportedMethodError('Method not supported');
101102
}
102-
isApprovedForAll(_: AddressType, __: AddressType): Promise<boolean> {
103-
throw new Error('Method not implemented.');
103+
isApprovedForAll(_contract: AddressType, _operator: AddressType): Promise<boolean> {
104+
throw new UnsupportedMethodError('Method not supported');
104105
}
105106
}

0 commit comments

Comments
 (0)