Line data Source code
1 : import 'dart:typed_data';
2 :
3 : import 'package:walletkit_dart/src/utils/keccak.dart';
4 : import 'package:walletkit_dart/walletkit_dart.dart';
5 :
6 3 : final ensRegistryAbi = ContractABI.fromAbi(
7 : '''[{"inputs":[{"internalType":"contract ENS","name":"_old","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","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":"bytes32","name":"node","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"label","type":"bytes32"},{"indexed":false,"internalType":"address","name":"owner","type":"address"}],"name":"NewOwner","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"node","type":"bytes32"},{"indexed":false,"internalType":"address","name":"resolver","type":"address"}],"name":"NewResolver","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"node","type":"bytes32"},{"indexed":false,"internalType":"uint64","name":"ttl","type":"uint64"}],"name":"NewTTL","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"node","type":"bytes32"},{"indexed":false,"internalType":"address","name":"owner","type":"address"}],"name":"Transfer","type":"event"},{"constant":true,"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"old","outputs":[{"internalType":"contract ENS","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"}],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"}],"name":"recordExists","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"}],"name":"resolver","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"address","name":"owner","type":"address"}],"name":"setOwner","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"resolver","type":"address"},{"internalType":"uint64","name":"ttl","type":"uint64"}],"name":"setRecord","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"address","name":"resolver","type":"address"}],"name":"setResolver","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"bytes32","name":"label","type":"bytes32"},{"internalType":"address","name":"owner","type":"address"}],"name":"setSubnodeOwner","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"bytes32","name":"label","type":"bytes32"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"resolver","type":"address"},{"internalType":"uint64","name":"ttl","type":"uint64"}],"name":"setSubnodeRecord","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"uint64","name":"ttl","type":"uint64"}],"name":"setTTL","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"}],"name":"ttl","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"payable":false,"stateMutability":"view","type":"function"}]''');
8 :
9 : const ensRegistryMainnetContractAddress = "0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e";
10 :
11 : const znsRegistryContractAddress = "0xa0446c88240bCA2A8E0f68C93aa365d25B198aA4";
12 :
13 : class EnsRegistryContract extends InternalContract {
14 1 : EnsRegistryContract({
15 : required super.contractAddress,
16 : required super.rpc,
17 1 : }) : super(
18 1 : abi: ensRegistryAbi,
19 : );
20 :
21 1 : factory EnsRegistryContract.mainnet({required EvmRpcInterface rpc}) {
22 1 : return EnsRegistryContract(
23 : contractAddress: ensRegistryMainnetContractAddress,
24 : rpc: rpc,
25 : );
26 : }
27 :
28 0 : factory EnsRegistryContract.smartchain({required EvmRpcInterface rpc}) {
29 0 : return EnsRegistryContract(
30 : contractAddress: znsRegistryContractAddress,
31 : rpc: rpc,
32 : );
33 : }
34 :
35 1 : Future<String?> resolver({required String name}) async {
36 2 : final function = abi.getFunction('resolver')!;
37 :
38 1 : final node = namehash(name);
39 :
40 : try {
41 1 : final result = await readSafe(
42 2 : function: function.addValues(values: [node]),
43 : );
44 :
45 3 : final resolver = result.outputs.first.value as String;
46 1 : if (resolver == nullAddress) {
47 : return null;
48 : }
49 : return resolver;
50 1 : } on RangeError {
51 : return null;
52 : }
53 : }
54 : }
55 :
56 1 : Uint8List namehash(String name) {
57 1 : if (name.isEmpty) {
58 0 : return Uint8List(32);
59 : }
60 :
61 : List<int> node;
62 1 : if (name.contains('.')) {
63 1 : var labels = name.split('.');
64 3 : node = namehash(labels.sublist(1).join('.'));
65 : } else {
66 1 : node = Uint8List(32);
67 : }
68 :
69 2 : var label = name.split('.')[0];
70 3 : var labelHash = keccak256(Uint8List.fromList(label.codeUnits));
71 :
72 4 : return keccak256(Uint8List.fromList([...node, ...labelHash]));
73 : }
|