Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
385 changes: 385 additions & 0 deletions lib/src/crypto/evm/entities/abi/erc/erc1155.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,385 @@
import 'dart:typed_data';

import 'package:walletkit_dart/walletkit_dart.dart';

final contractAbiErc1155 = ContractABI.fromAbi('''[
{
"inputs": [
{
"internalType": "address",
"name": "account",
"type": "address"
},
{
"internalType": "uint256",
"name": "id",
"type": "uint256"
}
],
"name": "balanceOf",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address[]",
"name": "accounts",
"type": "address[]"
},
{
"internalType": "uint256[]",
"name": "ids",
"type": "uint256[]"
}
],
"name": "balanceOfBatch",
"outputs": [
{
"internalType": "uint256[]",
"name": "",
"type": "uint256[]"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "account",
"type": "address"
},
{
"internalType": "address",
"name": "operator",
"type": "address"
}
],
"name": "isApprovedForAll",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "from",
"type": "address"
},
{
"internalType": "address",
"name": "to",
"type": "address"
},
{
"internalType": "uint256[]",
"name": "ids",
"type": "uint256[]"
},
{
"internalType": "uint256[]",
"name": "amounts",
"type": "uint256[]"
},
{
"internalType": "bytes",
"name": "data",
"type": "bytes"
}
],
"name": "safeBatchTransferFrom",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "from",
"type": "address"
},
{
"internalType": "address",
"name": "to",
"type": "address"
},
{
"internalType": "uint256",
"name": "id",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
},
{
"internalType": "bytes",
"name": "data",
"type": "bytes"
}
],
"name": "safeTransferFrom",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "operator",
"type": "address"
},
{
"internalType": "bool",
"name": "approved",
"type": "bool"
}
],
"name": "setApprovalForAll",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "bytes4",
"name": "interfaceId",
"type": "bytes4"
}
],
"name": "supportsInterface",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "id",
"type": "uint256"
}
],
"name": "uri",
"outputs": [
{
"internalType": "string",
"name": "",
"type": "string"
}
],
"stateMutability": "view",
"type": "function"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "account",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "operator",
"type": "address"
},
{
"indexed": false,
"internalType": "bool",
"name": "approved",
"type": "bool"
}
],
"name": "ApprovalForAll",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "operator",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "from",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "to",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256[]",
"name": "ids",
"type": "uint256[]"
},
{
"indexed": false,
"internalType": "uint256[]",
"name": "values",
"type": "uint256[]"
}
],
"name": "TransferBatch",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "operator",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "from",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "to",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "id",
"type": "uint256"
},
{
"indexed": false,
"internalType": "uint256",
"name": "value",
"type": "uint256"
}
],
"name": "TransferSingle",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "string",
"name": "value",
"type": "string"
},
{
"indexed": true,
"internalType": "uint256",
"name": "id",
"type": "uint256"
}
],
"name": "URI",
"type": "event"
}
]

''');

class ERC1155Contract extends InternalContract {
ERC1155Contract({
required super.contractAddress,
required super.rpc,
}) : super(
abi: contractAbiErc1155,
);

Future<BigInt> balanceOf({
required String address,
required BigInt tokenID,
}) async {
final function = abi.functions[0];
final response = await readSafe(
function: function.addValues(values: [address, tokenID]),
);
return response.outputs.first.castValue<BigInt>();
}

Future<List<BigInt>> balanceOfBatch({
required List<String> accounts,
required List<BigInt> tokenIDs,
}) async {
if (accounts.length != tokenIDs.length) {
throw ArgumentError('accounts and tokenIDs must have the same length');
}
final function = abi.functions[1];
final response = await readSafe(
function: function.addValues(values: [accounts, tokenIDs]),
);
return response.outputs.first.castValue<List<BigInt>>();
}

Future<String> getUri({
required BigInt tokenID,
}) async {
final function = abi.functions[7];
final response = await readSafe(
function: function.addValues(values: [tokenID]),
);
return response.outputs.first.castValue<String>();
}

Future<String> safeTransferFrom({
required String sender,
required String to,
required BigInt tokenID,
required BigInt amount,
required Uint8List seed,
Uint8List? data,
EvmFeeInformation? feeInfo,
List<AccessListItem>? accessList,
}) async {
final function = abi.functions[4];
return await interact(
function: function.addValues(
values: [sender, to, tokenID, amount, data ?? Uint8List(0)]),
sender: sender,
seed: seed,
feeInfo: feeInfo,
accessList: accessList,
);
}
Comment on lines +365 to +384
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Add comprehensive input validation for safe transfer.

The method uses a magic number for function index and lacks important input validations.

Apply this diff to improve the implementation:

+  static const _SAFE_TRANSFER_FROM_INDEX = 4;
+  static const _ZERO_ADDRESS = "0x0000000000000000000000000000000000000000";
+
   Future<String> safeTransferFrom({
     required String sender,
     required String to,
     required BigInt tokenID,
     required BigInt amount,
     required Uint8List seed,
     Uint8List? data,
     EvmFeeInformation? feeInfo,
     List<AccessListItem>? accessList,
   }) async {
+    if (!isValidAddress(sender) || !isValidAddress(to)) {
+      throw ArgumentError('Invalid address format');
+    }
+    if (to == _ZERO_ADDRESS) {
+      throw ArgumentError('Cannot transfer to zero address');
+    }
+    if (tokenID < BigInt.zero) {
+      throw ArgumentError('Token ID must be non-negative');
+    }
+    if (amount <= BigInt.zero) {
+      throw ArgumentError('Amount must be positive');
+    }
+    if (seed.isEmpty) {
+      throw ArgumentError('Seed cannot be empty');
+    }
-    final function = abi.functions[4];
+    final function = abi.functions[_SAFE_TRANSFER_FROM_INDEX];
     return await interact(
       function: function.addValues(
           values: [sender, to, tokenID, amount, data ?? Uint8List(0)]),
       sender: sender,
       seed: seed,
       feeInfo: feeInfo,
       accessList: accessList,
     );
   }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
Future<String> safeTransferFrom({
required String sender,
required String to,
required BigInt tokenID,
required BigInt amount,
required Uint8List seed,
Uint8List? data,
EvmFeeInformation? feeInfo,
List<AccessListItem>? accessList,
}) async {
final function = abi.functions[4];
return await interact(
function: function.addValues(
values: [sender, to, tokenID, amount, data ?? Uint8List(0)]),
sender: sender,
seed: seed,
feeInfo: feeInfo,
accessList: accessList,
);
}
static const _SAFE_TRANSFER_FROM_INDEX = 4;
static const _ZERO_ADDRESS = "0x0000000000000000000000000000000000000000";
Future<String> safeTransferFrom({
required String sender,
required String to,
required BigInt tokenID,
required BigInt amount,
required Uint8List seed,
Uint8List? data,
EvmFeeInformation? feeInfo,
List<AccessListItem>? accessList,
}) async {
if (!isValidAddress(sender) || !isValidAddress(to)) {
throw ArgumentError('Invalid address format');
}
if (to == _ZERO_ADDRESS) {
throw ArgumentError('Cannot transfer to zero address');
}
if (tokenID < BigInt.zero) {
throw ArgumentError('Token ID must be non-negative');
}
if (amount <= BigInt.zero) {
throw ArgumentError('Amount must be positive');
}
if (seed.isEmpty) {
throw ArgumentError('Seed cannot be empty');
}
final function = abi.functions[_SAFE_TRANSFER_FROM_INDEX];
return await interact(
function: function.addValues(
values: [sender, to, tokenID, amount, data ?? Uint8List(0)]),
sender: sender,
seed: seed,
feeInfo: feeInfo,
accessList: accessList,
);
}

}
Loading
Loading