Skip to content

Commit

Permalink
Merge branch 'master' into feat/rename-jump-in-and-navbar-items
Browse files Browse the repository at this point in the history
Signed-off-by: Kevin Szuchet <[email protected]>
  • Loading branch information
kevinszuchet authored Oct 18, 2024
2 parents 32cb82d + adbafa7 commit ec36e07
Show file tree
Hide file tree
Showing 16 changed files with 1,489 additions and 790 deletions.
1,336 changes: 632 additions & 704 deletions package-lock.json

Large diffs are not rendered by default.

8 changes: 4 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,20 @@
"@0xsequence/multicall": "^0.25.1",
"@0xsequence/relayer": "^0.25.1",
"@dcl/crypto": "^3.3.1",
"@dcl/schemas": "^13.9.0",
"@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",
"@wert-io/widget-initializer": "^6.1.1",
"axios": "^0.21.1",
"date-fns": "^1.29.0",
"dcl-catalyst-client": "^21.1.0",
"decentraland-connect": "^7.0.0",
"decentraland-connect": "^7.2.0",
"decentraland-crypto-fetch": "^2.0.1",
"decentraland-transactions": "^2.6.0",
"decentraland-transactions": "^2.15.0",
"decentraland-ui": "^6.10.0",
"ethers": "^5.6.8",
"events": "^3.3.0",
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
})
}
}
3 changes: 3 additions & 0 deletions src/lib/time.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export function fromMillisecondsToSeconds(timeInMilliseconds: number): number {
return Math.floor(timeInMilliseconds / 1000)
}
289 changes: 289 additions & 0 deletions src/lib/trades.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,289 @@
import { TypedDataDomain, ethers } from 'ethers'
import { ChainId, Network, TradeAssetType } from '@dcl/schemas'
import {
CollectionItemTradeAsset,
ERC20TradeAsset,
ERC721TradeAsset,
Trade,
TradeAsset,
TradeCreation,
TradeType
} from '@dcl/schemas/dist/dapps/trade'
import * as ethUtils from './eth'
import {
ContractData,
ContractName,
getContract
} from 'decentraland-transactions'
import { fromMillisecondsToSeconds } from '../lib/time'
import {
OFFCHAIN_MARKETPLACE_TYPES,
getTradeSignature,
getOnChainTrade,
getValueForTradeAsset
} from './trades'

jest.mock('./eth', () => {
const module = jest.requireActual('./eth')
return {
...module,
getSigner: jest.fn(() => {
const wallet = ethers.Wallet.createRandom()
wallet.connect(ethers.providers.getDefaultProvider())
return Promise.resolve(wallet)
})
} as unknown
})

describe('when getting the value for a trade asset', () => {
let asset: TradeAsset

describe('and the asset is an ERC20', () => {
beforeEach(() => {
asset = {
assetType: TradeAssetType.ERC20,
amount: '100'
} as ERC20TradeAsset
})

it('should return the amount', () => {
expect(getValueForTradeAsset(asset)).toBe(
(asset as ERC20TradeAsset).amount
)
})
})

describe('and the asset is an ERC721', () => {
beforeEach(() => {
asset = {
assetType: TradeAssetType.ERC721,
tokenId: 'token-id'
} as ERC721TradeAsset
})

it('should return the token id', () => {
expect(getValueForTradeAsset(asset)).toBe(
(asset as ERC721TradeAsset).tokenId
)
})
})

describe('and the asset is a COLLECTION ITEM', () => {
beforeEach(() => {
asset = {
assetType: TradeAssetType.COLLECTION_ITEM,
itemId: 'item-id'
} as CollectionItemTradeAsset
})

it('should return the item id', () => {
expect(getValueForTradeAsset(asset)).toBe(
(asset as CollectionItemTradeAsset).itemId
)
})
})
})

describe('when getting the trade signature', () => {
let trade: Omit<TradeCreation, 'signature'>

describe('when the contract does not exist for that chainId', () => {
beforeEach(() => {
trade = {
chainId: ChainId.ARBITRUM_MAINNET
} as Omit<TradeCreation, 'signature'>
})

it('should throw an error', async () => {
await expect(getTradeSignature(trade)).rejects.toThrowError(
'Could not get a valid contract for OffChainMarketplace using chain 42161'
)
})
})

describe('when the contract exists for that chainId', () => {
let offchainMarketplaceContract: ContractData
let signerAddress: string
let signer: ethers.Wallet
let values: Record<string, any>
let domain: TypedDataDomain

beforeEach(async () => {
signer = ethers.Wallet.createRandom().connect(
ethers.providers.getDefaultProvider()
)
jest
.spyOn(ethUtils, 'getSigner')
.mockImplementation(() => Promise.resolve(signer))
signerAddress = (await signer.getAddress()).toLowerCase()
offchainMarketplaceContract = getContract(
ContractName.OffChainMarketplace,
ChainId.ETHEREUM_SEPOLIA
)

trade = {
signer: signerAddress,
type: TradeType.BID,
network: Network.ETHEREUM,
chainId: ChainId.ETHEREUM_SEPOLIA,
checks: {
expiration: Date.now() + 100000000000,
effective: Date.now(),
uses: 1,
salt: '0x',
allowedRoot: '0x',
contractSignatureIndex: 0,
externalChecks: [],
signerSignatureIndex: 0
},
sent: [
{
assetType: TradeAssetType.ERC20,
contractAddress: offchainMarketplaceContract.address,
amount: '2',
extra: ''
}
],
received: [
{
assetType: TradeAssetType.ERC721,
contractAddress: offchainMarketplaceContract.address,
tokenId: '1',
extra: '',
beneficiary: signerAddress
}
]
}

const SALT = ethers.utils.hexZeroPad(
ethers.utils.hexlify(trade.chainId),
32
)
offchainMarketplaceContract = getContract(
ContractName.OffChainMarketplace,
trade.chainId
)
domain = {
name: offchainMarketplaceContract.name,
version: offchainMarketplaceContract.version,
salt: SALT,
verifyingContract: offchainMarketplaceContract.address
}

values = {
checks: {
uses: trade.checks.uses,
expiration: fromMillisecondsToSeconds(trade.checks.expiration),
effective: fromMillisecondsToSeconds(trade.checks.effective),
salt: ethers.utils.hexZeroPad(trade.checks.salt, 32),
contractSignatureIndex: trade.checks.contractSignatureIndex,
signerSignatureIndex: trade.checks.signerSignatureIndex,
allowedRoot: ethers.utils.hexZeroPad(trade.checks.allowedRoot, 32),
externalChecks: trade.checks.externalChecks?.map(externalCheck => ({
contractAddress: externalCheck.contractAddress,
selector: externalCheck.selector,
value: externalCheck.value,
required: externalCheck.required
}))
},
sent: trade.sent.map(asset => ({
assetType: asset.assetType,
contractAddress: asset.contractAddress,
value: getValueForTradeAsset(asset),
extra: ethers.utils.hexlify(ethers.utils.toUtf8Bytes(asset.extra))
})),
received: trade.received.map(asset => ({
assetType: asset.assetType,
contractAddress: asset.contractAddress,
value: getValueForTradeAsset(asset),
extra: ethers.utils.hexlify(ethers.utils.toUtf8Bytes(asset.extra)),
beneficiary: asset.beneficiary
}))
}
})

it('should return the signature', async () => {
expect(await getTradeSignature(trade)).toBe(
await signer._signTypedData(domain, OFFCHAIN_MARKETPLACE_TYPES, values)
)
})
})
})

describe('when getting the trade to accept', () => {
let trade: Trade
let beneficiaryAddress: string

beforeEach(() => {
trade = {
id: 'an-id',
createdAt: Date.now(),
signature: '123123123',
signer: '0x123',
type: TradeType.BID,
network: Network.ETHEREUM,
chainId: ChainId.ETHEREUM_SEPOLIA,
checks: {
expiration: Date.now() + 100000000000,
effective: Date.now(),
uses: 1,
salt: '0x',
allowedRoot: '0x',
contractSignatureIndex: 0,
externalChecks: [],
signerSignatureIndex: 0
},
sent: [
{
assetType: TradeAssetType.ERC20,
contractAddress: '0x123',
amount: '2',
extra: ''
}
],
received: [
{
assetType: TradeAssetType.ERC721,
contractAddress: '0x123',
tokenId: '1',
extra: '',
beneficiary: '0x123123'
}
]
}

beneficiaryAddress = '0x123123'
})

it('should return the trade with the correct structure', () => {
expect(getOnChainTrade(trade, beneficiaryAddress)).toEqual({
signer: trade.signer,
signature: trade.signature,
checks: {
expiration: fromMillisecondsToSeconds(trade.checks.expiration),
effective: fromMillisecondsToSeconds(trade.checks.effective),
uses: trade.checks.uses,
salt: ethers.utils.hexZeroPad(trade.checks.salt, 32),
allowedRoot: ethers.utils.hexZeroPad(trade.checks.allowedRoot, 32),
allowedProof: [],
contractSignatureIndex: trade.checks.contractSignatureIndex,
signerSignatureIndex: trade.checks.signerSignatureIndex,
externalChecks: trade.checks.externalChecks
},
sent: trade.sent.map(asset => ({
assetType: asset.assetType,
contractAddress: asset.contractAddress,
value: getValueForTradeAsset(asset),
extra: ethers.utils.hexlify(ethers.utils.toUtf8Bytes(asset.extra)),
beneficiary: beneficiaryAddress
})),
received: trade.received.map(asset => ({
assetType: asset.assetType,
contractAddress: asset.contractAddress,
value: getValueForTradeAsset(asset),
extra: ethers.utils.hexlify(ethers.utils.toUtf8Bytes(asset.extra)),
beneficiary: asset.beneficiary
}))
})
})
})
Loading

0 comments on commit ec36e07

Please sign in to comment.