helpers.ts
1 import { SagaIterator } from 'redux-saga'; 2 import { select, apply, call } from 'redux-saga/effects'; 3 import ethUtil from 'ethereumjs-util'; 4 5 import networkConfigs from 'libs/ens/networkConfigs'; 6 import { INode } from 'libs/nodes/INode'; 7 import ENS from 'libs/ens/contracts'; 8 import { IDomainData, NameState, getNameHash, IBaseDomainRequest } from 'libs/ens'; 9 import * as configNodesSelectors from 'features/config/nodes/selectors'; 10 11 //#region Make & Decode 12 interface Params { 13 to: any; 14 data: any; 15 decoder: any; 16 } 17 18 export function* makeEthCallAndDecode({ to, data, decoder }: Params): SagaIterator { 19 const node: INode = yield select(configNodesSelectors.getNodeLib); 20 const result: string = yield apply(node, node.sendCallRequest, [{ data, to }]); 21 const decodedResult = yield call(decoder, result); 22 return decodedResult; 23 } 24 //#endregion Make & Decode 25 26 //#region Mode Map 27 const { main } = networkConfigs; 28 29 function* nameStateOwned({ deedAddress }: IDomainData<NameState.Owned>, nameHash: string) { 30 // Return the owner's address, and the resolved address if it exists 31 const { ownerAddress }: typeof ENS.deed.owner.outputType = yield call(makeEthCallAndDecode, { 32 to: deedAddress, 33 data: ENS.deed.owner.encodeInput(), 34 decoder: ENS.deed.owner.decodeOutput 35 }); 36 37 const { resolverAddress }: typeof ENS.registry.resolver.outputType = yield call( 38 makeEthCallAndDecode, 39 { 40 to: main.registry, 41 decoder: ENS.registry.resolver.decodeOutput, 42 data: ENS.registry.resolver.encodeInput({ 43 node: nameHash 44 }) 45 } 46 ); 47 48 let resolvedAddress = '0x0'; 49 50 if (resolverAddress !== '0x0') { 51 const result: typeof ENS.resolver.addr.outputType = yield call(makeEthCallAndDecode, { 52 to: resolverAddress, 53 data: ENS.resolver.addr.encodeInput({ node: nameHash }), 54 decoder: ENS.resolver.addr.decodeOutput 55 }); 56 57 resolvedAddress = result.ret; 58 } 59 60 return { ownerAddress, resolvedAddress }; 61 } 62 63 function* nameStateReveal({ deedAddress }: IDomainData<NameState.Reveal>): SagaIterator { 64 const { ownerAddress }: typeof ENS.deed.owner.outputType = yield call(makeEthCallAndDecode, { 65 to: deedAddress, 66 data: ENS.deed.owner.encodeInput(), 67 decoder: ENS.deed.owner.decodeOutput 68 }); 69 return { ownerAddress }; 70 } 71 72 interface IModeMap { 73 [x: string]: ( 74 domainData: IDomainData<NameState>, 75 nameHash?: string, 76 hash?: Buffer 77 ) => 78 | {} 79 | { ownerAddress: string; resolvedAddress: string } 80 | { auctionCloseTime: string; revealBidTime: string }; 81 } 82 83 const modeMap: IModeMap = { 84 [NameState.Open]: (_: IDomainData<NameState.Open>) => ({}), 85 [NameState.Auction]: (_: IDomainData<NameState.Auction>) => ({}), 86 [NameState.Owned]: nameStateOwned, 87 [NameState.Forbidden]: (_: IDomainData<NameState.Forbidden>) => ({}), 88 [NameState.Reveal]: nameStateReveal, 89 [NameState.NotYetAvailable]: (_: IDomainData<NameState.NotYetAvailable>) => ({}) 90 }; 91 92 export function* resolveDomainRequest(name: string): SagaIterator { 93 const hash = ethUtil.sha3(name); 94 const nameHash = getNameHash(`${name}.eth`); 95 96 const domainData: typeof ENS.auction.entries.outputType = yield call(makeEthCallAndDecode, { 97 to: main.public.ethAuction, 98 data: ENS.auction.entries.encodeInput({ _hash: hash }), 99 decoder: ENS.auction.entries.decodeOutput 100 }); 101 const nameStateHandler = modeMap[domainData.mode]; 102 const result = yield call(nameStateHandler, domainData, nameHash); 103 104 const returnValue: IBaseDomainRequest = { 105 name, 106 ...domainData, 107 ...result, 108 labelHash: ethUtil.addHexPrefix(hash.toString('hex')), 109 nameHash 110 }; 111 return returnValue; 112 } 113 //#endregion Mode Map