Skip to content
Permalink

Comparing changes

This is a direct comparison between two commits made in this repository or its related repositories. View the default comparison for this range or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: decentraland/builder
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 7d79943bc926755ace969f081cc510a1cb3d3a3b
Choose a base ref
..
head repository: decentraland/builder
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: f569dec62a5b02db5f5ffff95f1fa83203e420a6
Choose a head ref
1 change: 1 addition & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -8,3 +8,4 @@ PUBLIC_URL=/
; value here. 1 means enabled, anything else disabled. If the variable is empty it will look the value remotelly.
REACT_APP_FF_BUILDER_MAINTENANCE=
REACT_APP_FF_BUILDER_RENTALS=
REACT_APP_FF_BUILDER_DCL_CONTROLLER_V2=
4 changes: 3 additions & 1 deletion src/components/ClaimENSPage/ClaimENSPage.container.ts
Original file line number Diff line number Diff line change
@@ -6,6 +6,7 @@ import { RootState } from 'modules/common/types'
import { openModal } from 'modules/modal/actions'
import { allowClaimManaRequest, claimNameRequest, ALLOW_CLAIM_MANA_REQUEST } from 'modules/ens/actions'
import { getLoading, isWaitingTxAllowMana, getAuthorizationByWallet } from 'modules/ens/selectors'
import { getIsDCLControllerV2Enabled } from 'modules/features/selectors'
import { MapStateProps, MapDispatchProps, MapDispatch } from './ClaimENSPage.types'
import ClaimENSPage from './ClaimENSPage'

@@ -16,7 +17,8 @@ const mapState = (state: RootState): MapStateProps => {
wallet: getWallet(state),
mana: getMana(state)!,
allowance: authorization ? authorization.allowance : '0',
isLoading: !authorization || isLoadingType(getLoading(state), ALLOW_CLAIM_MANA_REQUEST) || isWaitingTxAllowMana(state)
isLoading: !authorization || isLoadingType(getLoading(state), ALLOW_CLAIM_MANA_REQUEST) || isWaitingTxAllowMana(state),
isDCLControllerV2Enabled: getIsDCLControllerV2Enabled(state)
}
}

9 changes: 4 additions & 5 deletions src/components/ClaimENSPage/ClaimENSPage.tsx
Original file line number Diff line number Diff line change
@@ -8,9 +8,8 @@ import Back from 'components/Back'
import LoggedInDetailPage from 'components/LoggedInDetailPage'
import { locations } from 'routing/locations'
import { MAX_NAME_SIZE, PRICE, isNameValid, isNameAvailable, hasNameMinLength, isEnoughClaimMana } from 'modules/ens/utils'
import { CONTROLLER_ADDRESS } from 'modules/common/contracts'
import { CONTROLLER_ADDRESS, CONTROLLER_V2_ADDRESS } from 'modules/common/contracts'
import { Props, State } from './ClaimENSPage.types'

import './ClaimENSPage.css'

export default class ClaimENSPage extends React.PureComponent<Props, State> {
@@ -71,7 +70,7 @@ export default class ClaimENSPage extends React.PureComponent<Props, State> {
}

render() {
const { wallet, mana, allowance, onBack } = this.props
const { wallet, mana, allowance, isDCLControllerV2Enabled, onBack } = this.props
const { name, isError, isAvailable } = this.state

const isLoading = this.props.isLoading || this.state.isLoading
@@ -154,8 +153,8 @@ export default class ClaimENSPage extends React.PureComponent<Props, State> {
id="claim_ens_page.need_mana_message"
values={{
contract_link: (
<TransactionLink address={CONTROLLER_ADDRESS} txHash="">
DCLController
<TransactionLink address={isDCLControllerV2Enabled ? CONTROLLER_V2_ADDRESS : CONTROLLER_ADDRESS} txHash="">
{isDCLControllerV2Enabled ? 'DCLControllerV2' : 'DCLController'}
</TransactionLink>
)
}}
3 changes: 2 additions & 1 deletion src/components/ClaimENSPage/ClaimENSPage.types.ts
Original file line number Diff line number Diff line change
@@ -9,6 +9,7 @@ export type Props = {
mana: number
allowance: string
isLoading: boolean
isDCLControllerV2Enabled: boolean
onOpenModal: typeof openModal
onAllowMana: typeof allowClaimManaRequest
onClaim: typeof claimNameRequest
@@ -23,6 +24,6 @@ export type State = {
isError: boolean
}

export type MapStateProps = Pick<Props, 'wallet' | 'mana' | 'allowance' | 'isLoading'>
export type MapStateProps = Pick<Props, 'wallet' | 'mana' | 'allowance' | 'isLoading' | 'isDCLControllerV2Enabled'>
export type MapDispatchProps = Pick<Props, 'onOpenModal' | 'onAllowMana' | 'onClaim' | 'onNavigate' | 'onBack'>
export type MapDispatch = Dispatch<CallHistoryMethodAction | OpenModalAction | AllowClaimManaRequestAction | ClaimNameRequestAction>
2 changes: 2 additions & 0 deletions src/components/HomePage/HomePage.tsx
Original file line number Diff line number Diff line change
@@ -8,6 +8,7 @@ import Navbar from 'components/Navbar'
import LoadingPage from 'components/LoadingPage'
import SyncToast from 'components/SyncToast'
import Navigation from 'components/Navigation'
import EventBannerContainer from 'components/EventBanner/EventBanner.container'
import { NavigationTab } from 'components/Navigation/Navigation.types'
import { locations } from 'routing/locations'
import { Props } from './HomePage.types'
@@ -74,6 +75,7 @@ export const HomePage: React.FC<Props> = props => {
<Navigation activeTab={NavigationTab.OVERVIEW}>
<SyncToast />
</Navigation>
<EventBannerContainer />
<Container>
<h1 className="title">{t('home_page.title')}</h1>
<Card.Group itemsPerRow={4} centered>
1 change: 1 addition & 0 deletions src/config/env/dev.json
Original file line number Diff line number Diff line change
@@ -22,6 +22,7 @@
"ENS_GATEWAY": "limo",
"RESOLVER_CONTRACT_ADDRESS": "0x4B1488B7a6B320d2D721406204aBc3eeAa9AD329",
"CONTROLLER_CONTRACT_ADDRESS": "0x6ff05b6271bbed8f16a46e6073d27ad94224e0ac",
"CONTROLLER_V2_CONTRACT_ADDRESS": "0x055a4d2c8f044bc9aac260c9194fd177654329cd",
"REGISTRAR_CONTRACT_ADDRESS": "0x6b8da2752827cf926215b43bb8e46fd7b9ddac35",
"RENTALS_CONTRACT_ADDRESS": "0x92159c78f0f4523b9c60382bb888f30f10a46b3b",
"IPFS_URL": "https://ipfs.infura.io:5001/api/v0/add?pin=false",
1 change: 1 addition & 0 deletions src/config/env/prod.json
Original file line number Diff line number Diff line change
@@ -22,6 +22,7 @@
"ENS_GATEWAY": "limo",
"RESOLVER_CONTRACT_ADDRESS": "0x4976fb03c32e5b8cfe2b6ccb31c09ba78ebaba41",
"CONTROLLER_CONTRACT_ADDRESS": "0x6843291bd86857d97f0d269e698939fb10d60772",
"CONTROLLER_V2_CONTRACT_ADDRESS": "0x055a4d2c8f044bc9aac260c9194fd177654329cd",
"REGISTRAR_CONTRACT_ADDRESS": "0x2a187453064356c898cae034eaed119e1663acb8",
"RENTALS_CONTRACT_ADDRESS": "0x3a1469499d0be105d4f77045ca403a5f6dc2f3f5",
"IPFS_URL": "https://ipfs.infura.io:5001/api/v0/add?pin=false",
1 change: 1 addition & 0 deletions src/config/env/stg.json
Original file line number Diff line number Diff line change
@@ -22,6 +22,7 @@
"ENS_GATEWAY": "limo",
"RESOLVER_CONTRACT_ADDRESS": "0x4976fb03c32e5b8cfe2b6ccb31c09ba78ebaba41",
"CONTROLLER_CONTRACT_ADDRESS": "0x6843291bd86857d97f0d269e698939fb10d60772",
"CONTROLLER_V2_CONTRACT_ADDRESS": "0x055a4d2c8f044bc9aac260c9194fd177654329cd",
"REGISTRAR_CONTRACT_ADDRESS": "0x2a187453064356c898cae034eaed119e1663acb8",
"RENTALS_CONTRACT_ADDRESS": "0x3a1469499d0be105d4f77045ca403a5f6dc2f3f5",
"IPFS_URL": "https://ipfs.infura.io:5001/api/v0/add?pin=false",
1 change: 1 addition & 0 deletions src/modules/common/contracts.ts
Original file line number Diff line number Diff line change
@@ -6,5 +6,6 @@ export const ESTATE_REGISTRY_ADDRESS = config.get('ESTATE_REGISTRY_CONTRACT_ADDR
export const ENS_ADDRESS = config.get('ENS_CONTRACT_ADDRESS', '')
export const ENS_RESOLVER_ADDRESS = config.get('RESOLVER_CONTRACT_ADDRESS', '')
export const CONTROLLER_ADDRESS = config.get('CONTROLLER_CONTRACT_ADDRESS', '')
export const CONTROLLER_V2_ADDRESS = config.get('CONTROLLER_V2_CONTRACT_ADDRESS', '')
export const REGISTRAR_ADDRESS = config.get('REGISTRAR_CONTRACT_ADDRESS', '')
export const RENTALS_ADDRESS = config.get('RENTALS_CONTRACT_ADDRESS', '')
155 changes: 155 additions & 0 deletions src/modules/ens/sagas.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
import { BuilderClient } from '@dcl/builder-client'
import { ChainId, Network } from '@dcl/schemas'
import { ERC20__factory, ERC20, DCLController__factory } from 'contracts'
import { getChainIdByNetwork, getSigner } from 'decentraland-dapps/dist/lib/eth'
import { getAddress } from 'decentraland-dapps/dist/modules/wallet/selectors'
import { ethers } from 'ethers'
import { CONTROLLER_ADDRESS, CONTROLLER_V2_ADDRESS, MANA_ADDRESS } from 'modules/common/contracts'
import { getIsDCLControllerV2Enabled } from 'modules/features/selectors'
import { getWallet } from 'modules/wallet/utils'
import { expectSaga } from 'redux-saga-test-plan'
import { call, select } from 'redux-saga/effects'
import { allowClaimManaRequest, claimNameRequest, fetchENSAuthorizationRequest } from './actions'
import { ensSaga } from './sagas'

jest.mock('@dcl/builder-client')

const MockBuilderClient = BuilderClient as jest.MockedClass<typeof BuilderClient>

let builderClient: BuilderClient
let manaContract: ERC20

beforeEach(() => {
builderClient = new MockBuilderClient(
'url',
{
authChain: [],
ephemeralIdentity: { address: 'address', privateKey: 'prikey', publicKey: 'pubkey' },
expiration: new Date()
},
'address'
)

manaContract = {
approve: jest.fn(),
allowance: jest.fn()
} as unknown as ERC20
})

describe('when handling the approve claim mana request', () => {
describe('and the dcl controller v2 feature flag is enabled', () => {
it('should call the manaContract approve function with the dcl controller v2 address', async () => {
const allowance = '100'
const signer = {} as ethers.Signer

await expectSaga(ensSaga, builderClient)
.provide([
[call(getWallet), { address: 'address', chainId: ChainId.ETHEREUM_GOERLI }],
[call(getSigner), signer],
[call([ERC20__factory, 'connect'], MANA_ADDRESS, signer), manaContract],
[select(getIsDCLControllerV2Enabled), true]
])
.call([manaContract, 'approve'], CONTROLLER_V2_ADDRESS, allowance)
.dispatch(allowClaimManaRequest(allowance))
.silentRun()
})
})

describe('and the dcl controller v2 feature flag is disabled', () => {
it('should call the manaContract approve function with the dcl controller address', async () => {
const allowance = '100'
const signer = {} as ethers.Signer

await expectSaga(ensSaga, builderClient)
.provide([
[call(getWallet), { address: 'address', chainId: ChainId.ETHEREUM_GOERLI }],
[call(getSigner), signer],
[call([ERC20__factory, 'connect'], MANA_ADDRESS, signer), manaContract],
[select(getIsDCLControllerV2Enabled), false]
])
.call([manaContract, 'approve'], CONTROLLER_ADDRESS, allowance)
.dispatch(allowClaimManaRequest(allowance))
.silentRun()
})
})
})

describe('when handling the fetch of authorizations request', () => {
afterEach(() => {
jest.restoreAllMocks()
})

describe('and the dcl controller v2 feature flag is enabled', () => {
it('should call mana.allowance with the dcl controller v2 address', async () => {
const from = 'address'

jest.spyOn(ethers, 'Contract').mockReturnValueOnce(manaContract)

await expectSaga(ensSaga, builderClient)
.provide([
[select(getAddress), from],
[call(getChainIdByNetwork, Network.ETHEREUM), ChainId.ETHEREUM_GOERLI],
[select(getIsDCLControllerV2Enabled), true]
])
.call(manaContract.allowance, from, CONTROLLER_V2_ADDRESS)
.dispatch(fetchENSAuthorizationRequest())
.silentRun()
})
})

describe('and the dcl controller v2 feature flag is disabled', () => {
it('should call mana.allowance with the dcl controller address', async () => {
const from = 'address'

jest.spyOn(ethers, 'Contract').mockReturnValueOnce(manaContract)

await expectSaga(ensSaga, builderClient)
.provide([
[select(getAddress), from],
[call(getChainIdByNetwork, Network.ETHEREUM), ChainId.ETHEREUM_GOERLI],
[select(getIsDCLControllerV2Enabled), false]
])
.call(manaContract.allowance, from, CONTROLLER_ADDRESS)
.dispatch(fetchENSAuthorizationRequest())
.silentRun()
})
})
})

describe('when handling the claim name request', () => {
afterEach(() => {
jest.restoreAllMocks()
})

describe('and the dcl controller v2 feature flag is enabled', () => {
it('should call DCLController__factory.connect with the dcl controller v2 address', async () => {
const signer = {} as ethers.Signer

await expectSaga(ensSaga, builderClient)
.provide([
[call(getWallet), { address: 'address' }],
[call(getSigner), signer],
[select(getIsDCLControllerV2Enabled), true]
])
.call([DCLController__factory, 'connect'], CONTROLLER_V2_ADDRESS, signer)
.dispatch(claimNameRequest('name'))
.silentRun()
})
})

describe('and the dcl controller v2 feature flag is disabled', () => {
it('should call DCLController__factory.connect with the dcl controller address', async () => {
const signer = {} as ethers.Signer

await expectSaga(ensSaga, builderClient)
.provide([
[call(getWallet), { address: 'address' }],
[call(getSigner), signer],
[select(getIsDCLControllerV2Enabled), false]
])
.call([DCLController__factory, 'connect'], CONTROLLER_ADDRESS, signer)
.dispatch(claimNameRequest('name'))
.silentRun()
})
})
})
39 changes: 26 additions & 13 deletions src/modules/ens/sagas.ts
Original file line number Diff line number Diff line change
@@ -2,22 +2,30 @@ import { BigNumber, ethers } from 'ethers'
import { namehash } from '@ethersproject/hash'
import PQueue from 'p-queue'
import { all, call, put, select, takeEvery, takeLatest } from 'redux-saga/effects'
import { Network } from '@dcl/schemas'
import { ChainId, Network } from '@dcl/schemas'
import { BuilderClient, LandCoords, LandHashes } from '@dcl/builder-client'
import { ContractName, getContract } from 'decentraland-transactions'
import { getChainIdByNetwork, getNetworkProvider, getSigner } from 'decentraland-dapps/dist/lib/eth'
import { getAddress } from 'decentraland-dapps/dist/modules/wallet/selectors'
import { Wallet } from 'decentraland-dapps/dist/modules/wallet/types'
import { getCurrentLocale } from 'decentraland-dapps/dist/modules/translation/utils'
import { waitForTx } from 'decentraland-dapps/dist/modules/transaction/utils'

import { DCLController } from 'contracts'
import { ENS__factory } from 'contracts/factories/ENS__factory'
import { ENSResolver__factory } from 'contracts/factories/ENSResolver__factory'
import { DCLRegistrar__factory } from 'contracts/factories/DCLRegistrar__factory'
import { DCLController__factory } from 'contracts/factories/DCLController__factory'
import { ERC20__factory } from 'contracts/factories/ERC20__factory'
import { ENS_ADDRESS, ENS_RESOLVER_ADDRESS, CONTROLLER_ADDRESS, MANA_ADDRESS, REGISTRAR_ADDRESS } from 'modules/common/contracts'
import {
ENS_ADDRESS,
ENS_RESOLVER_ADDRESS,
CONTROLLER_ADDRESS,
CONTROLLER_V2_ADDRESS,
MANA_ADDRESS,
REGISTRAR_ADDRESS
} from 'modules/common/contracts'
import { getWallet } from 'modules/wallet/utils'
import { getIsDCLControllerV2Enabled } from 'modules/features/selectors'
import { getCenter, getSelection } from 'modules/land/utils'
import { marketplace } from 'lib/api/marketplace'
import { getLands } from 'modules/land/selectors'
@@ -238,11 +246,13 @@ export function* ensSaga(builderClient: BuilderClient) {
function* handleFetchAuthorizationRequest(_action: FetchENSAuthorizationRequestAction) {
try {
const from: string = yield select(getAddress)
const chainId = getChainIdByNetwork(Network.ETHEREUM)
const chainId: ChainId = yield call(getChainIdByNetwork, Network.ETHEREUM)
const contract = getContract(ContractName.MANAToken, chainId)
const provider: Awaited<ReturnType<typeof getNetworkProvider>> = yield call(getNetworkProvider, chainId)
const mana = new ethers.Contract(contract.address, contract.abi, new ethers.providers.Web3Provider(provider))
const allowance: string = yield call(mana.allowance, from, CONTROLLER_ADDRESS)
const isDCLControllerV2Enabled: boolean = yield select(getIsDCLControllerV2Enabled)
const controllerAddress = isDCLControllerV2Enabled ? CONTROLLER_V2_ADDRESS : CONTROLLER_ADDRESS
const allowance: string = yield call(mana.allowance, from, controllerAddress)
const authorization: Authorization = { allowance }

yield put(fetchENSAuthorizationSuccess(authorization, from.toString()))
@@ -337,11 +347,13 @@ export function* ensSaga(builderClient: BuilderClient) {
function* handleClaimNameRequest(action: ClaimNameRequestAction) {
const { name } = action.payload
try {
const wallet: Wallet = yield getWallet()
const signer: ethers.Signer = yield getSigner()
const wallet: Wallet = yield call(getWallet)
const signer: ethers.Signer = yield call(getSigner)
const from = wallet.address

const controllerContract = DCLController__factory.connect(CONTROLLER_ADDRESS, signer)
const isDCLControllerV2Enabled: boolean = yield select(getIsDCLControllerV2Enabled)
const controllerAddress = isDCLControllerV2Enabled ? CONTROLLER_V2_ADDRESS : CONTROLLER_ADDRESS
const controllerContract: DCLController = yield call([DCLController__factory, 'connect'], controllerAddress, signer)
const dclRegistrarContract = DCLRegistrar__factory.connect(REGISTRAR_ADDRESS, signer)
const transaction: ethers.ContractTransaction = yield call([controllerContract, 'register'], name, from)
yield put(claimNameTransactionSubmitted(name, wallet.address, wallet.chainId, transaction.hash))
@@ -381,12 +393,13 @@ export function* ensSaga(builderClient: BuilderClient) {
function* handleApproveClaimManaRequest(action: AllowClaimManaRequestAction) {
const { allowance } = action.payload
try {
const wallet: Wallet = yield getWallet()
const signer: ethers.Signer = yield getSigner()
const wallet: Wallet = yield call(getWallet)
const signer: ethers.Signer = yield call(getSigner)
const from = wallet.address
const manaContract = ERC20__factory.connect(MANA_ADDRESS, signer)

const transaction: ethers.ContractTransaction = yield call(() => manaContract.approve(CONTROLLER_ADDRESS, allowance))
const manaContract: ReturnType<typeof ERC20__factory['connect']> = yield call([ERC20__factory, 'connect'], MANA_ADDRESS, signer)
const isDCLControllerV2Enabled: boolean = yield select(getIsDCLControllerV2Enabled)
const controllerAddress = isDCLControllerV2Enabled ? CONTROLLER_V2_ADDRESS : CONTROLLER_ADDRESS
const transaction: ethers.ContractTransaction = yield call([manaContract, 'approve'], controllerAddress, allowance)

yield put(allowClaimManaSuccess(allowance, from.toString(), wallet.chainId, transaction.hash))
} catch (error) {
Loading