Skip to content

Commit

Permalink
feat: support native polygon transactions (decentraland#414)
Browse files Browse the repository at this point in the history
* feat: use sendTransaction helper

* feat: disalbe parts of the UI when network is not supported

* chore: update decentraland-dapps

* fix: package-lock

* fix: added TRANSACTION_API_URL

* fix: convert decimal to wei
  • Loading branch information
cazala authored Sep 6, 2021
1 parent 78283e8 commit d108165
Show file tree
Hide file tree
Showing 17 changed files with 615 additions and 795 deletions.
1,072 changes: 530 additions & 542 deletions webapp/package-lock.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion webapp/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
"classnames": "^2.3.1",
"connected-react-router": "^6.9.1",
"date-fns": "^2.23.0",
"decentraland-dapps": "^12.17.1",
"decentraland-dapps": "^12.24.0",
"decentraland-transactions": "^1.22.2",
"decentraland-ui": "^3.9.0",
"dotenv": "^10.0.0",
Expand Down
6 changes: 4 additions & 2 deletions webapp/src/components/BidPage/BidModal/BidModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
AuthorizationType
} from 'decentraland-dapps/dist/modules/authorization/types'
import { hasAuthorization } from 'decentraland-dapps/dist/modules/authorization/utils'
import { ChainButton } from 'decentraland-dapps/dist/containers'
import { getAssetName, isOwnedBy } from '../../../modules/asset/utils'
import { toMANA, fromMANA } from '../../../lib/mana'
import { AssetAction } from '../../AssetAction'
Expand Down Expand Up @@ -132,7 +133,7 @@ const BidModal = (props: Props) => {
>
{t('global.cancel')}
</Button>
<Button
<ChainButton
type="submit"
primary
loading={isPlacingBid}
Expand All @@ -144,9 +145,10 @@ const BidModal = (props: Props) => {
isLoading ||
isPlacingBid
}
chainId={nft.chainId}
>
{t('bid_page.submit')}
</Button>
</ChainButton>
</div>
</Form>
<AuthorizationModal
Expand Down
6 changes: 4 additions & 2 deletions webapp/src/components/BuyPage/BuyItemModal/BuyItemModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
} from 'decentraland-dapps/dist/modules/authorization/types'
import { ContractName } from 'decentraland-transactions'
import { hasAuthorization } from 'decentraland-dapps/dist/modules/authorization/utils'
import { ChainButton } from 'decentraland-dapps/dist/containers'
import { locations } from '../../../modules/routing/locations'
import { AssetAction } from '../../AssetAction'
import { Name } from '../Name'
Expand Down Expand Up @@ -120,14 +121,15 @@ const BuyItemModal = (props: Props) => {
{t('global.cancel')}
</Button>

<Button
<ChainButton
primary
disabled={isDisabled || isLoading}
onClick={handleSubmit}
loading={isLoading}
chainId={item.chainId}
>
{t('buy_page.buy')}
</Button>
</ChainButton>
</div>
<AuthorizationModal
isLoading={isLoading}
Expand Down
10 changes: 6 additions & 4 deletions webapp/src/components/BuyPage/BuyNFTModal/BuyNFTModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
AuthorizationType
} from 'decentraland-dapps/dist/modules/authorization/types'
import { hasAuthorization } from 'decentraland-dapps/dist/modules/authorization/utils'
import { ChainButton } from 'decentraland-dapps/dist/containers'
import { NFTCategory } from '@dcl/schemas'
import { ContractName } from 'decentraland-transactions'
import { locations } from '../../../modules/routing/locations'
Expand Down Expand Up @@ -177,16 +178,17 @@ const BuyNFTModal = (props: Props) => {
</Button>

{isDisabled ||
!isAboveMaxPercentage ||
(isAboveMaxPercentage && wantsToProceed) ? (
<Button
!isAboveMaxPercentage ||
(isAboveMaxPercentage && wantsToProceed) ? (
<ChainButton
primary
disabled={isDisabled || isLoading}
onClick={handleSubmit}
loading={isLoading}
chainId={nft.chainId}
>
{t('buy_page.buy')}
</Button>
</ChainButton>
) : (
<Button
primary
Expand Down
6 changes: 4 additions & 2 deletions webapp/src/components/CancelSalePage/CancelSalePage.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import React from 'react'
import { t, T } from 'decentraland-dapps/dist/modules/translation/utils'
import { ChainButton } from 'decentraland-dapps/dist/containers'
import { Page, Header, Button } from 'decentraland-ui'

import { AssetType } from '../../modules/asset/types'
Expand Down Expand Up @@ -74,14 +75,15 @@ const CancelSalePage = (props: Props) => {
>
{t('global.cancel')}
</Button>
<Button
<ChainButton
primary
loading={isLoading}
disabled={isDisabled || isLoading}
onClick={() => onCancelOrder(order!, nft)}
chainId={nft.chainId}
>
{t('cancel_sale_page.submit')}
</Button>
</ChainButton>
</div>
</AssetAction>
)
Expand Down
6 changes: 4 additions & 2 deletions webapp/src/components/SellPage/SellModal/SellModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
} from 'decentraland-dapps/dist/modules/authorization/types'
import { hasAuthorization } from 'decentraland-dapps/dist/modules/authorization/utils'
import { t, T } from 'decentraland-dapps/dist/modules/translation/utils'
import { ChainButton } from 'decentraland-dapps/dist/containers'
import { Header, Form, Field, Button, Modal } from 'decentraland-ui'
import { ContractName } from 'decentraland-transactions'
import { toMANA, fromMANA } from '../../../lib/mana'
Expand Down Expand Up @@ -153,14 +154,15 @@ const SellModal = (props: Props) => {
>
{t('global.cancel')}
</Button>
<Button
<ChainButton
type="submit"
primary
disabled={isDisabled || isLoading}
loading={isLoading}
chainId={nft.chainId}
>
{t(isUpdate ? 'sell_page.update_submit' : 'sell_page.submit')}
</Button>
</ChainButton>
</div>
</Form>

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React, { useCallback } from 'react'
import { Link } from 'react-router-dom'
import { t, T } from 'decentraland-dapps/dist/modules/translation/utils'
import { TransactionLink } from 'decentraland-dapps/dist/containers'
import { ChainCheck, TransactionLink } from 'decentraland-dapps/dist/containers'
import { getChainConfiguration } from 'decentraland-dapps/dist/lib/chainConfiguration'
import { Form, Radio, Loader, Popup, RadioProps } from 'decentraland-ui'
import { locations } from '../../../modules/routing/locations'
Expand Down Expand Up @@ -41,11 +41,14 @@ const Authorization = (props: Props) => {
</Link>
}
/>
<Radio
checked={isAuthorized(authorization, authorizations)}
label={token.name}
onClick={(_, props: RadioProps) => handleOnChange(!!props.checked)}
/>
<ChainCheck chainId={authorization.chainId}>
{isEnabled => <Radio
checked={isAuthorized(authorization, authorizations)}
label={token.name}
disabled={!isEnabled}
onClick={(_, props: RadioProps) => handleOnChange(!!props.checked)}
/>}
</ChainCheck>
<div className="radio-description secondary-text">
<T
id="authorization.authorize"
Expand Down
6 changes: 4 additions & 2 deletions webapp/src/components/TransferPage/TransferPage.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import React, { useState } from 'react'
import { Page, Header, Form, Field, Button } from 'decentraland-ui'
import { ChainButton } from 'decentraland-dapps/dist/containers'
import { t, T } from 'decentraland-dapps/dist/modules/translation/utils'
import { Navbar } from '../Navbar'
import { Footer } from '../Footer'
Expand Down Expand Up @@ -109,14 +110,15 @@ const TransferPage = (props: Props) => {
>
{t('global.cancel')}
</Button>
<Button
<ChainButton
type="submit"
primary
loading={isTransfering}
disabled={isDisabled}
chainId={nft.chainId}
>
{t('transfer_page.submit')}
</Button>
</ChainButton>
</div>
</Form>
</AssetAction>
Expand Down
3 changes: 2 additions & 1 deletion webapp/src/components/UserMenu/UserMenu.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import React from 'react'
import { UserMenu as BaseUserMenu } from 'decentraland-dapps/dist/containers'
import { IntroPopup } from '../IntroPopup'
import { Props } from './UserMenu.types'

export default class UserMenu extends React.PureComponent {
export default class UserMenu extends React.PureComponent<Props> {
render() {
return (
<>
Expand Down
66 changes: 4 additions & 62 deletions webapp/src/modules/item/sagas.spec.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,8 @@
import { expectSaga } from 'redux-saga-test-plan'
import { Address } from 'web3x-es/address'
import { getWallet } from '../wallet/selectors'
import * as matchers from 'redux-saga-test-plan/matchers'
import { ChainId, Item } from '@dcl/schemas'
import { call, select } from 'redux-saga/effects'
import { ContractName, getContract } from 'decentraland-transactions'
import { CollectionStore } from '../../contracts/CollectionStore'
import { ContractFactory } from '../contract/ContractFactory'
import { sendTransaction } from '../wallet/utils'
import { sendTransaction } from 'decentraland-dapps/dist/modules/wallet/utils'
import {
buyItemRequest,
buyItemFailure,
Expand All @@ -19,10 +14,10 @@ import {
fetchItemRequest,
fetchItemFailure
} from './actions'
import { itemSaga } from './sagas'
import { TxSend } from 'web3x-es/contract'
import { getWallet } from '../wallet/selectors'
import { View } from '../ui/types'
import { itemAPI } from '../vendor/decentraland/item/api'
import { itemSaga } from './sagas'

const item = {
itemId: 'anItemId',
Expand All @@ -35,15 +30,6 @@ const wallet = {
address: '0x32be343b94f860124dc4fee278fdcbd38c102d88'
}

const collectionStoreContractConfig = getContract(
ContractName.CollectionStore,
item.chainId
)
const collectionStoreContract = new CollectionStore(
jest.fn() as any,
Address.fromString(collectionStoreContractConfig.address)
)

const txHash =
'0x9fc518261399c1bd236997706347f8b117a061cef5518073b1c3eefd5efbff84'

Expand All @@ -66,28 +52,11 @@ describe('when handling the buy items request action', () => {
})
})

describe("when there's an error while building the store contract", () => {
it('should dispatch an action signaling the failure of the action handling', () => {
return expectSaga(itemSaga)
.provide([
[select(getWallet), wallet],
[matchers.call.fn(ContractFactory.build), Promise.reject(anError)]
])
.put(buyItemFailure(anError.message))
.dispatch(buyItemRequest(item))
.run({ silenceTimeout: true })
})
})

describe('when sending the meta transaction fails', () => {
it('should dispatch an action signaling the failure of the action handling', () => {
return expectSaga(itemSaga)
.provide([
[select(getWallet), wallet],
[
matchers.call.fn(ContractFactory.build),
Promise.resolve(collectionStoreContract)
],
[matchers.call.fn(sendTransaction), Promise.reject(anError)]
])
.put(buyItemFailure(anError.message))
Expand All @@ -97,38 +66,11 @@ describe('when handling the buy items request action', () => {
})

describe('when the meta transaction is sent succesfully', () => {
const buyTransactionParameters = [
{
collection: Address.fromString(item.contractAddress),
ids: [item.itemId],
prices: [item.price],
beneficiaries: [Address.fromString(wallet.address)]
}
]

const txBuy = {} as TxSend

it('should send a meta transaction to the collection store contract living in the chain provided by the item and dispatch the success action', () => {
return expectSaga(itemSaga)
.provide([
[select(getWallet), wallet],
[
matchers.call.fn(ContractFactory.build),
Promise.resolve(collectionStoreContract)
],
[
call(collectionStoreContract.methods.buy, buyTransactionParameters),
txBuy
],
[
call(
sendTransaction,
txBuy,
collectionStoreContractConfig,
Address.fromString(wallet.address)
),
Promise.resolve(txHash)
]
[matchers.call.fn(sendTransaction), Promise.resolve(txHash)]
])
.put(buyItemSuccess(item.chainId, txHash, item))
.dispatch(buyItemRequest(item))
Expand Down
47 changes: 9 additions & 38 deletions webapp/src/modules/item/sagas.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,9 @@
import { Item } from '@dcl/schemas'
import { put, takeEvery } from '@redux-saga/core/effects'
import {
ContractData,
ContractName,
getContract
} from 'decentraland-transactions'
import { ContractName, getContract } from 'decentraland-transactions'
import { sendTransaction } from 'decentraland-dapps/dist/modules/wallet/utils'
import { call, select } from 'redux-saga/effects'
import {
CollectionStore,
CollectionStoreTransactionReceipt
} from '../../contracts/CollectionStore'
import { ContractFactory } from '../contract/ContractFactory'
import { push } from 'connected-react-router'
import { itemAPI } from '../vendor/decentraland/item/api'
import { getWallet } from '../wallet/selectors'
import {
Expand All @@ -28,10 +21,6 @@ import {
FETCH_ITEM_REQUEST,
BUY_ITEM_SUCCESS
} from './actions'
import { Address } from 'web3x-es/address'
import { sendTransaction } from '../wallet/utils'
import { TxSend } from 'web3x-es/contract'
import { push } from 'connected-react-router'
import { locations } from '../routing/locations'

export function* itemSaga() {
Expand Down Expand Up @@ -79,33 +68,15 @@ function* handleBuyItem(action: BuyItemRequestAction) {
throw new Error('A defined wallet is required to buy an item')
}

const collectionStoreContractConfig: ContractData = getContract(
ContractName.CollectionStore,
item.chainId
)
const collectionStoreContract: CollectionStore = yield call(
[ContractFactory, 'build'],
CollectionStore,
collectionStoreContractConfig.address
)

const txBuy: TxSend<CollectionStoreTransactionReceipt> = yield call(
collectionStoreContract.methods.buy,
[
{
collection: Address.fromString(item.contractAddress),
ids: [item.itemId],
prices: [item.price],
beneficiaries: [Address.fromString(wallet.address)]
}
]
)
const contract = getContract(ContractName.CollectionStore, item.chainId)

const txHash: string = yield call(
sendTransaction,
txBuy,
collectionStoreContractConfig,
Address.fromString(wallet.address)
contract,
collectionStore =>
collectionStore.buy([
[item.contractAddress, [item.itemId], [item.price], [wallet.address]]
])
)

yield put(buyItemSuccess(item.chainId, txHash, item))
Expand Down
Loading

0 comments on commit d108165

Please sign in to comment.