diff --git a/packages/web3-eth-ens/CHANGELOG.md b/packages/web3-eth-ens/CHANGELOG.md
index c1fb717c2a8..54253823dfc 100644
--- a/packages/web3-eth-ens/CHANGELOG.md
+++ b/packages/web3-eth-ens/CHANGELOG.md
@@ -142,3 +142,7 @@ Documentation:
- Dependencies updated
## [Unreleased]
+
+### Added
+
+- Added function `setAddress` in ENS and Resolver classes (#5956)
\ No newline at end of file
diff --git a/packages/web3-eth-ens/src/abi/ens/PublicResolver.ts b/packages/web3-eth-ens/src/abi/ens/PublicResolver.ts
index 83b927bfb69..b9dba8a249c 100644
--- a/packages/web3-eth-ens/src/abi/ens/PublicResolver.ts
+++ b/packages/web3-eth-ens/src/abi/ens/PublicResolver.ts
@@ -590,4 +590,22 @@ export const PublicResolverAbi = [
stateMutability: 'view',
type: 'function',
},
+ {
+ inputs: [
+ {
+ internalType: 'bytes32',
+ name: 'node',
+ type: 'bytes32',
+ },
+ {
+ internalType: 'address',
+ name: 'a',
+ type: 'address',
+ },
+ ],
+ name: 'setAddr',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
] as const;
diff --git a/packages/web3-eth-ens/src/ens.ts b/packages/web3-eth-ens/src/ens.ts
index e62fd36c617..822dcab2b41 100644
--- a/packages/web3-eth-ens/src/ens.ts
+++ b/packages/web3-eth-ens/src/ens.ts
@@ -16,15 +16,18 @@ along with web3.js. If not, see .
*/
import { Web3Context, Web3ContextObject } from 'web3-core';
-import { ENSNetworkNotSyncedError, ENSUnsupportedNetworkError } from 'web3-errors';
+import { ENSNetworkNotSyncedError, ENSUnsupportedNetworkError, RevertInstructionError } from 'web3-errors';
import { isSyncing } from 'web3-eth';
import { Contract } from 'web3-eth-contract';
import { getId } from 'web3-net';
import {
+ Address,
DEFAULT_RETURN_FORMAT,
EthExecutionAPI,
FMT_NUMBER,
+ PayableCallOptions,
SupportedProviders,
+ TransactionReceipt,
Web3NetAPI,
} from 'web3-types';
import { PublicResolverAbi } from './abi/ens/PublicResolver.js';
@@ -258,4 +261,22 @@ export class ENS extends Web3Context {
public get events() {
return this._registry.events;
}
+
+ /**
+ * Sets the address of an ENS name in his resolver.
+ * @param name - The ENS name
+ * @param address - The address to set
+ * @param txConfig - (Optional) The transaction config
+ * @returns - The transaction receipt
+ * ```ts
+ * const receipt = await ens.setAddress('web3js.eth','0xe2597eb05cf9a87eb1309e86750c903ec38e527e');
+ *```
+ */
+ public async setAddress(
+ name: string,
+ address: Address,
+ txConfig: PayableCallOptions
+ ): Promise {
+ return this._resolver.setAddress(name, address, txConfig);
+ }
}
diff --git a/packages/web3-eth-ens/src/resolver.ts b/packages/web3-eth-ens/src/resolver.ts
index 3540455f3d5..9f99eae8955 100644
--- a/packages/web3-eth-ens/src/resolver.ts
+++ b/packages/web3-eth-ens/src/resolver.ts
@@ -19,11 +19,13 @@ import { ResolverMethodMissingError } from 'web3-errors';
import { Contract } from 'web3-eth-contract';
import { isNullish, sha3 } from 'web3-utils';
import { isHexStrict } from 'web3-validator';
+import { Address, PayableCallOptions } from 'web3-types';
import { PublicResolverAbi } from './abi/ens/PublicResolver.js';
import { interfaceIds, methodsInInterface } from './config.js';
import { Registry } from './registry.js';
import { namehash } from './utils.js';
+
// Default public resolver
// https://github.com/ensdomains/resolvers/blob/master/contracts/PublicResolver.sol
@@ -102,4 +104,17 @@ export class Resolver {
return resolverContract.methods.contenthash(namehash(ENSName)).call();
}
+
+ public async setAddress(
+ ENSName: string,
+ address: Address,
+ txConfig: PayableCallOptions,
+ ) {
+ const resolverContract = await this.getResolverContractAdapter(ENSName);
+ await this.checkInterfaceSupport(resolverContract, methodsInInterface.setAddr);
+
+ return resolverContract.methods
+ .setAddr(namehash(ENSName), address)
+ .send(txConfig);
+ }
}
diff --git a/packages/web3-eth-ens/test/unit/constructor.test.ts b/packages/web3-eth-ens/test/unit/constructor.test.ts
index 8bb4ec2230d..06836c024d9 100644
--- a/packages/web3-eth-ens/test/unit/constructor.test.ts
+++ b/packages/web3-eth-ens/test/unit/constructor.test.ts
@@ -41,6 +41,7 @@ describe('ens', () => {
const registry = new Registry(object);
const resolver = new Resolver(registry);
+ expect(resolver.setAddress).toBeDefined();
expect(resolver.getAddress).toBeDefined();
expect(resolver.checkInterfaceSupport).toBeDefined();
expect(resolver.supportsInterface).toBeDefined();
@@ -52,6 +53,7 @@ describe('ens', () => {
const ens = new ENS(registryAddresses.main, 'http://127.0.0.1:8545');
expect(ens.getResolver).toBeDefined();
+ expect(ens.setAddress).toBeDefined();
expect(ens.recordExists).toBeDefined();
expect(ens.getTTL).toBeDefined();
expect(ens.getOwner).toBeDefined();
diff --git a/packages/web3-eth-ens/test/unit/ens.test.ts b/packages/web3-eth-ens/test/unit/ens.test.ts
index 9f6f4dd7efe..1c860d72c38 100644
--- a/packages/web3-eth-ens/test/unit/ens.test.ts
+++ b/packages/web3-eth-ens/test/unit/ens.test.ts
@@ -110,6 +110,22 @@ describe('ens', () => {
});
describe('addr', () => {
+ it('setAddr valid', async () => {
+ // eslint-disable-next-line @typescript-eslint/no-empty-function
+ const send = jest.spyOn({ send: () => {} }, 'send');
+
+ const setAddressMock = jest.spyOn(ens['_resolver'], 'setAddress').mockReturnValue({
+ send,
+ } as unknown as Web3PromiEvent);
+
+ const sendOptions = { from: mockAddress };
+ await ens.setAddress(ENS_NAME, mockAddress, sendOptions);
+ expect(setAddressMock).toHaveBeenCalledWith(
+ ENS_NAME,
+ mockAddress,
+ sendOptions,
+ );
+ });
it('getAddress', async () => {
// eslint-disable-next-line @typescript-eslint/no-empty-function
const call = jest.spyOn({ call: () => {} }, 'call');
diff --git a/packages/web3-eth-ens/test/unit/resolver.test.ts b/packages/web3-eth-ens/test/unit/resolver.test.ts
index 97cf6e2d0b3..a771082b959 100644
--- a/packages/web3-eth-ens/test/unit/resolver.test.ts
+++ b/packages/web3-eth-ens/test/unit/resolver.test.ts
@@ -105,6 +105,29 @@ describe('resolver', () => {
);
});
describe('addr', () => {
+ it('setAddr valid', async () => {
+ const checkInteraface = jest.spyOn(resolver, 'checkInterfaceSupport');
+
+ const setAddrMock = jest.spyOn(contract.methods, 'setAddr').mockReturnValue({
+ send: jest.fn(),
+ } as unknown as NonPayableMethodObject);
+
+ jest.spyOn(contract.methods, 'supportsInterface').mockReturnValue({
+ call: jest.fn().mockReturnValue(true),
+ } as unknown as NonPayableMethodObject);
+
+ // todo when moving this mock in beforeAll, jest calls the actual implementation, how to fix that
+ // I use this in many places
+ jest.spyOn(registry, 'getResolver').mockImplementation(async () => {
+ return new Promise(resolve => {
+ resolve(contract);
+ });
+ });
+
+ await resolver.setAddress(ENS_NAME, mockAddress, { from: mockAddress });
+ expect(checkInteraface).toHaveBeenCalled();
+ expect(setAddrMock).toHaveBeenCalledWith(namehash(ENS_NAME), mockAddress);
+ });
it('getAddress', async () => {
const supportsInterfaceMock = jest
.spyOn(contract.methods, 'supportsInterface')