Skip to content

Commit

Permalink
ens setAddress support (#6834)
Browse files Browse the repository at this point in the history
* set address in resolver

* set addr in ens class

* resolver abi update

* tests

* updated setAddr without cointype

* removed unused import

* changelog updates

* updated doc and changlog

* linter fix
  • Loading branch information
jdevcs committed Feb 28, 2024
1 parent 86447cd commit 35cb1b8
Show file tree
Hide file tree
Showing 7 changed files with 100 additions and 1 deletion.
4 changes: 4 additions & 0 deletions packages/web3-eth-ens/CHANGELOG.md
Expand Up @@ -142,3 +142,7 @@ Documentation:
- Dependencies updated

## [Unreleased]

### Added

- Added function `setAddress` in ENS and Resolver classes (#5956)
18 changes: 18 additions & 0 deletions packages/web3-eth-ens/src/abi/ens/PublicResolver.ts
Expand Up @@ -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;
23 changes: 22 additions & 1 deletion packages/web3-eth-ens/src/ens.ts
Expand Up @@ -16,15 +16,18 @@ along with web3.js. If not, see <http://www.gnu.org/licenses/>.
*/

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';
Expand Down Expand Up @@ -258,4 +261,22 @@ export class ENS extends Web3Context<EthExecutionAPI & Web3NetAPI> {
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<TransactionReceipt | RevertInstructionError> {
return this._resolver.setAddress(name, address, txConfig);
}
}
15 changes: 15 additions & 0 deletions packages/web3-eth-ens/src/resolver.ts
Expand Up @@ -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

Expand Down Expand Up @@ -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);
}
}
2 changes: 2 additions & 0 deletions packages/web3-eth-ens/test/unit/constructor.test.ts
Expand Up @@ -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();
Expand All @@ -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();
Expand Down
16 changes: 16 additions & 0 deletions packages/web3-eth-ens/test/unit/ens.test.ts
Expand Up @@ -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<any, any>);

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');
Expand Down
23 changes: 23 additions & 0 deletions packages/web3-eth-ens/test/unit/resolver.test.ts
Expand Up @@ -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<any, any>);

jest.spyOn(contract.methods, 'supportsInterface').mockReturnValue({
call: jest.fn().mockReturnValue(true),
} as unknown as NonPayableMethodObject<any, any>);

// 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')
Expand Down

1 comment on commit 35cb1b8

@github-actions
Copy link

Choose a reason for hiding this comment

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

Benchmark

Benchmark suite Current: 35cb1b8 Previous: 6c075db Ratio
processingTx 9498 ops/sec (±4.91%) 9301 ops/sec (±4.81%) 0.98
processingContractDeploy 35860 ops/sec (±7.16%) 39129 ops/sec (±7.62%) 1.09
processingContractMethodSend 18834 ops/sec (±7.08%) 19443 ops/sec (±5.19%) 1.03
processingContractMethodCall 37420 ops/sec (±4.95%) 38971 ops/sec (±6.34%) 1.04
abiEncode 44136 ops/sec (±6.67%) 44252 ops/sec (±6.92%) 1.00
abiDecode 29272 ops/sec (±7.36%) 30419 ops/sec (±8.89%) 1.04
sign 1623 ops/sec (±0.94%) 1656 ops/sec (±4.08%) 1.02
verify 374 ops/sec (±0.38%) 373 ops/sec (±0.78%) 1.00

This comment was automatically generated by workflow using github-action-benchmark.

Please sign in to comment.