Skip to content

Commit

Permalink
Revert "Revert "Revert "Revert "Feat/transak bump (#639)" (#643)" (#645
Browse files Browse the repository at this point in the history
…)" (#648)" (#649)

This reverts commit ae0a055.
  • Loading branch information
juanmahidalgo authored Nov 15, 2024
1 parent ae0a055 commit 611f3d0
Show file tree
Hide file tree
Showing 10 changed files with 298 additions and 420 deletions.
399 changes: 62 additions & 337 deletions package-lock.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
"@dcl/schemas": "^14.0.0",
"@dcl/single-sign-on-client": "^0.1.0",
"@dcl/ui-env": "^1.5.0",
"@transak/transak-sdk": "^1.0.31",
"@transak/transak-sdk": "^3.1.3",
"@types/flat": "0.0.28",
"@types/segment-analytics": "^0.0.38",
"@well-known-components/fetch-component": "^2.0.1",
Expand Down
14 changes: 14 additions & 0 deletions src/lib/marketplaceApi.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { AuthIdentity } from 'decentraland-crypto-fetch'
import { WertMessageWithTarget } from '../modules/gateway/types'
import { OrderResponse } from '../modules/gateway/transak/types'
import { BaseClient } from './BaseClient'

export class MarketplaceAPI extends BaseClient {
Expand All @@ -21,4 +22,17 @@ export class MarketplaceAPI extends BaseClient {
throw new Error((error as Error).message)
}
}
/**
* Given the order id, returns relevant data related to status changes (status & tx hash).
*
* @param orderId - Transak Order ID.
*/
async getOrder(
orderId: string,
identity: AuthIdentity
): Promise<OrderResponse> {
return await this.fetch<OrderResponse>(`/v1/transak/orders/${orderId}`, {
identity
})
}
}
85 changes: 63 additions & 22 deletions src/modules/gateway/sagas.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ import {
} from './types'
import { getPendingManaPurchase, getPendingPurchases } from './selectors'
import { OrderResponse, TransakOrderStatus } from './transak/types'
import { generateIdentityFailure } from '../identity'

jest.mock('@wert-io/widget-initializer')
jest.mock('../../lib/marketplaceApi')
Expand Down Expand Up @@ -788,27 +789,65 @@ describe('when handling the action signaling the load of the local storage into
.mockResolvedValue(mockTransakOrderResponse)
})

it('should put the action signaling the start pof the purchase status polling request', async () => {
const transakPurchase = {
...mockPurchase,
id: mockTransakOrderResponse.data.id,
gateway: NetworkGatewayType.TRANSAK
}
describe("and there is no identity and it's generate function failed", () => {
it('should put the action signaling the failure of the poll purchase status request', async () => {
const transakPurchase = {
...mockPurchase,
id: mockTransakOrderResponse.data.id,
gateway: NetworkGatewayType.TRANSAK
}

return expectSaga(gatewaySaga)
.provide([[select(getPendingPurchases), [transakPurchase]]])
.dispatch(load({}))
.put(pollPurchaseStatusRequest(transakPurchase))
.put(
setPurchase({
...transakPurchase,
status: PurchaseStatus.COMPLETE,
txHash: mockTransakOrderResponse.data.transactionHash!,
failureReason: null
})
)
.put(pollPurchaseStatusSuccess())
.silentRun()
return expectSaga(gatewaySaga)
.provide([[select(getPendingPurchases), [transakPurchase]]])
.dispatch(load({}))
.dispatch(generateIdentityFailure('', ''))
.put(pollPurchaseStatusRequest(transakPurchase))

.not.put(
setPurchase({
...transakPurchase,
status: PurchaseStatus.COMPLETE,
txHash: mockTransakOrderResponse.data.transactionHash!,
failureReason: null
})
)
.put(pollPurchaseStatusFailure(NO_IDENTITY_ERROR))
.silentRun()
})
})

describe('and there is identity', () => {
beforeEach(() => {
jest
.spyOn(MarketplaceAPI.prototype, 'getOrder')
.mockResolvedValue(mockTransakOrderResponse)
})
it('should put the action signaling the start pof the purchase status polling request', async () => {
const transakPurchase = {
...mockPurchase,
id: mockTransakOrderResponse.data.id,
gateway: NetworkGatewayType.TRANSAK
}

return expectSaga(gatewaySaga)
.provide([
[select(getPendingPurchases), [transakPurchase]],
[call(getIdentityOrRedirect), {}]
])
.dispatch(load({}))
.dispatch(generateIdentityFailure('', ''))
.put(pollPurchaseStatusRequest(transakPurchase))
.put(
setPurchase({
...transakPurchase,
status: PurchaseStatus.COMPLETE,
txHash: mockTransakOrderResponse.data.transactionHash!,
failureReason: null
})
)
.put(pollPurchaseStatusSuccess())
.silentRun()
})
})
})
})
Expand All @@ -825,12 +864,13 @@ describe('when handling the action signaling the load of the local storage into
describe('when it is possible to get the order from Transak API', () => {
beforeEach(() => {
jest
.spyOn(Transak.prototype, 'getOrder')
.spyOn(MarketplaceAPI.prototype, 'getOrder')
.mockResolvedValue(mockTransakOrderResponse)
})

it('should get the order, put the action signaling the set of updated purchase, and the action signaling the success of the poll purchase status request', async () => {
return expectSaga(gatewaySaga)
.provide([[call(getIdentityOrRedirect), {}]])
.put(
setPurchase({
...transakPurchase,
Expand All @@ -848,12 +888,13 @@ describe('when handling the action signaling the load of the local storage into
describe('when it is not possible to get the order from Transak API because the request fails', () => {
beforeEach(() => {
jest
.spyOn(Transak.prototype, 'getOrder')
.spyOn(MarketplaceAPI.prototype, 'getOrder')
.mockRejectedValue(new Error(error))
})

it('should get the order, put the action signaling the set of updated purchase, and the action signaling the success of the poll purchase status request', async () => {
return expectSaga(gatewaySaga)
.provide([[call(getIdentityOrRedirect), {}]])
.put(pollPurchaseStatusFailure(error))
.dispatch(pollPurchaseStatusRequest(transakPurchase))
.silentRun()
Expand Down
33 changes: 31 additions & 2 deletions src/modules/gateway/sagas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ import {
delay,
ForkEffect,
put,
race,
select,
take,
takeEvery,
takeLatest
} from 'redux-saga/effects'
Expand Down Expand Up @@ -65,6 +67,11 @@ import {
import { isManaPurchase, purchaseEventsChannel } from './utils'
import { Wallet } from '../wallet/types'
import { isErrorWithMessage } from '../../lib/error'
import {
GENERATE_IDENTITY_FAILURE,
GENERATE_IDENTITY_SUCCESS,
GenerateIdentitySuccessAction
} from '../identity'

const DEFAULT_POLLING_DELAY = 3000
const BUY_MANA_WITH_FIAT_FEEDBACK_MODAL_NAME = 'BuyManaWithFiatFeedbackModal'
Expand Down Expand Up @@ -322,13 +329,35 @@ export function createGatewaySaga(config: GatewaySagasConfig) {
throw new Error('Transak config not found')
}

const transak = new Transak(transakConfig)
let identity: AuthIdentity | null = yield call(getIdentityOrRedirect)

if (!identity) {
const { success } = (yield race({
success: take(GENERATE_IDENTITY_SUCCESS),
failure: take(GENERATE_IDENTITY_FAILURE)
})) as { success: GenerateIdentitySuccessAction }

if (success) {
identity = (yield call(getIdentityOrRedirect)) as AuthIdentity
} else {
throw new Error(NO_IDENTITY_ERROR)
}
}

const marketplaceAPI = new MarketplaceAPI(
transakConfig.marketplaceServerURL
)
const transak = new Transak(transakConfig, {}, identity)
let statusHasChanged = false

while (!statusHasChanged) {
const {
data: { status, transactionHash, errorMessage }
}: OrderResponse = yield call([transak, transak.getOrder], id)
}: OrderResponse = yield call(
[marketplaceAPI, 'getOrder'],
id,
identity
)
const newStatus: PurchaseStatus = yield call(
[transak, transak.getPurchaseStatus],
status
Expand Down
70 changes: 57 additions & 13 deletions src/modules/gateway/transak/Transak.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { select } from 'redux-saga/effects'
import { expectSaga } from 'redux-saga-test-plan'
import transakSDK from '@transak/transak-sdk'
import { ChainId } from '@dcl/schemas/dist/dapps/chain-id'
import { Network } from '@dcl/schemas/dist/dapps/network'
import { NetworkGatewayType } from 'decentraland-ui'
Expand All @@ -21,6 +20,21 @@ import { OrderData, TradeType, TransakOrderStatus } from './types'

jest.mock('../../../lib/eth')

let initMock
jest.mock('@transak/transak-sdk', () => {
const actualTransakSDK = jest.requireActual('@transak/transak-sdk')

return {
__esModule: true,
...actualTransakSDK,
Transak: jest.fn().mockImplementation(config => {
return {
init: initMock
}
})
}
})

const mockGetChainIdByNetwork = getChainIdByNetwork as jest.MockedFunction<
typeof getChainIdByNetwork
>
Expand All @@ -37,6 +51,7 @@ const mockConfig: GatewaySagasConfig = {
pollingDelay: 50
},
[NetworkGatewayType.TRANSAK]: {
marketplaceServerURL: 'https://marketplace-server.decentraland.zone',
apiBaseUrl: 'http://transak-base.url.xyz',
key: 'transak-key',
env: 'TEST',
Expand Down Expand Up @@ -85,8 +100,8 @@ const mockOrderDataWithNftAssetInfo = {
...mockOrderData.status,
isNFTOrder: true,
nftAssetInfo: {
contractAddress: 'contractAddress',
tokenId: 'anId',
collection: 'contractAddress',
tokenId: '123',
tradeType: TradeType.PRIMARY
}
}
Expand All @@ -108,9 +123,9 @@ const mockNftPurchase: NFTPurchase = {
...mockManaPurchase,
nft: {
contractAddress: 'contractAddress',
itemId: 'anId',
tokenId: undefined,
tradeType: TradeType.PRIMARY,
tokenId: '123',
itemId: null,
tradeType: TradeType.SECONDARY,
cryptoAmount: 10
}
}
Expand Down Expand Up @@ -163,26 +178,55 @@ describe('when interacting with Transak', () => {
})

describe('when purchasing an NFT', () => {
let originalHref
beforeEach(() => {
jest.clearAllMocks()
originalHref = window.location.href
Object.defineProperty(window, 'location', {
writable: true, // Allow href to be writable
value: {
href: originalHref
}
})
})
describe('when it belongs to the primary market', () => {
beforeEach(() => {
Object.defineProperty(window, 'location', {
value: {
href:
'https://decentraland.zone/contracts/contractAddress/tokens/123'
}
})
})

it('should put a new message in the channel signaling the set of the purchase with the nft info and the item id', () => {
transak.emitPurchaseEvent(
mockOrderDataWithNftAssetInfo.status,
Network.ETHEREUM
)

return expectSaga(gatewaySaga)
.put(setPurchase({ ...mockNftPurchase, amount: 1 }))
.silentRun()
})
})

describe('when it belongs to the primary market', () => {
beforeEach(() => {
Object.defineProperty(window, 'location', {
value: {
href:
'https://decentraland.zone/contracts/contractAddress/items/234'
}
})
})
it('should put a new message in the channel signaling the set of the purchase with the nft info and the item id', () => {
transak.emitPurchaseEvent(
{
...mockOrderDataWithNftAssetInfo.status,
nftAssetInfo: {
...mockOrderDataWithNftAssetInfo.status.nftAssetInfo,
tradeType: TradeType.SECONDARY
tradeType: TradeType.PRIMARY
}
},
Network.ETHEREUM
Expand All @@ -194,9 +238,9 @@ describe('when interacting with Transak', () => {
amount: 1,
nft: {
...mockNftPurchase.nft,
tradeType: TradeType.SECONDARY,
itemId: undefined,
tokenId: 'anId'
tokenId: null,
itemId: '234',
tradeType: TradeType.PRIMARY
}
})
)
Expand All @@ -206,14 +250,14 @@ describe('when interacting with Transak', () => {
})
})

describe('when opnening the widget', () => {
describe('when opening the widget', () => {
beforeEach(() => {
jest.spyOn(transakSDK.prototype, 'init').mockImplementation(() => {})
initMock = jest.fn()
})

it('should call the method init from the Transak SDK', () => {
transak.openWidget(mockAddress, Network.ETHEREUM)
return expect(transakSDK.prototype.init).toHaveBeenCalled()
expect(initMock).toHaveBeenCalled()
})
})
})
Loading

0 comments on commit 611f3d0

Please sign in to comment.