Skip to content

Commit

Permalink
add validations to the auction / marketplace
Browse files Browse the repository at this point in the history
  • Loading branch information
Samuel Sramko committed Sep 1, 2021
1 parent e534a0d commit a8e889b
Show file tree
Hide file tree
Showing 10 changed files with 91 additions and 11 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@tatumio/tatum",
"version": "1.23.4",
"version": "1.23.5",
"description": "Tatum API client allows browsers and Node.js clients to interact with Tatum API.",
"main": "dist/src/index.js",
"repository": "https://github.com/tatumio/tatum-js",
Expand Down
4 changes: 3 additions & 1 deletion src/model/request/CreateAuction.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import {Type} from 'class-transformer';
import {IsBoolean, IsIn, IsNotEmpty, IsNumber, IsNumberString, IsOptional, IsPositive, Length, Min} from 'class-validator';
import {IsBoolean, IsIn, IsNotEmpty, IsNumber, IsNumberString, IsOptional, IsPositive, Length, Min, Validate} from 'class-validator';
import {AmountDecimalValidator} from '../validation/AmountDecimalValidator';
import {Currency} from './Currency';
import {Fee} from './Fee';
import {PrivateKeyOrSignatureId} from './PrivateKeyOrSignatureId';
Expand Down Expand Up @@ -39,6 +40,7 @@ export class CreateAuction extends PrivateKeyOrSignatureId {
@IsNumberString()
public tokenId: string;

@Validate(AmountDecimalValidator)
@IsOptional()
@IsNumberString()
public amount?: string;
Expand Down
14 changes: 9 additions & 5 deletions src/model/request/CreateMarketplaceListing.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import {Type} from 'class-transformer'
import {IsBoolean, IsIn, IsNotEmpty, IsNumberString, IsOptional, Length, Min} from 'class-validator'
import {Currency} from './Currency'
import {Fee} from './Fee'
import {PrivateKeyOrSignatureId} from './PrivateKeyOrSignatureId'
import {Type} from 'class-transformer';
import {IsBoolean, IsIn, IsNotEmpty, IsNumberString, IsOptional, Length, Min, Validate} from 'class-validator';
import {AmountDecimalValidator} from '../validation/AmountDecimalValidator';
import {PriceDecimalValidator} from '../validation/PriceDecimalValidator';
import {Currency} from './Currency';
import {Fee} from './Fee';
import {PrivateKeyOrSignatureId} from './PrivateKeyOrSignatureId';

export class CreateMarketplaceListing extends PrivateKeyOrSignatureId {

Expand Down Expand Up @@ -32,6 +34,7 @@ export class CreateMarketplaceListing extends PrivateKeyOrSignatureId {

@IsNotEmpty()
@IsNumberString()
@Validate(PriceDecimalValidator)
public price: string;

@IsNotEmpty()
Expand All @@ -40,6 +43,7 @@ export class CreateMarketplaceListing extends PrivateKeyOrSignatureId {

@IsOptional()
@IsNumberString()
@Validate(AmountDecimalValidator)
public amount?: string;

@IsNotEmpty()
Expand Down
2 changes: 2 additions & 0 deletions src/model/request/DeployMarketplaceListing.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import {Type} from 'class-transformer';
import {IsIn, IsNotEmpty, IsNumber, IsOptional, IsPositive, Length, Max, Min} from 'class-validator';
import {HasDecimalPlaces} from '../validation/HasDecimalPlaces';
import {Currency} from './Currency';
import {Fee} from './Fee';
import {PrivateKeyOrSignatureId} from './PrivateKeyOrSignatureId';
Expand All @@ -14,6 +15,7 @@ export class DeployMarketplaceListing extends PrivateKeyOrSignatureId {
@IsNumber()
@IsPositive()
@Max(10000)
@HasDecimalPlaces(0)
public marketplaceFee: number;

@IsNotEmpty()
Expand Down
2 changes: 2 additions & 0 deletions src/model/request/DeployNftAuction.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import {Type} from 'class-transformer';
import {IsIn, IsNotEmpty, IsNumber, IsOptional, IsPositive, Length, Max, Min} from 'class-validator';
import {HasDecimalPlaces} from '../validation/HasDecimalPlaces';
import {Currency} from './Currency';
import {Fee} from './Fee';
import {PrivateKeyOrSignatureId} from './PrivateKeyOrSignatureId';
Expand All @@ -14,6 +15,7 @@ export class DeployNftAuction extends PrivateKeyOrSignatureId {
@IsNumber()
@IsPositive()
@Max(10000)
@HasDecimalPlaces(0)
public auctionFee: number;

@IsNotEmpty()
Expand Down
14 changes: 14 additions & 0 deletions src/model/validation/AmountDecimalValidator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import {BigNumber} from 'bignumber.js';
import {ValidationArguments, ValidatorConstraint, ValidatorConstraintInterface} from 'class-validator';

@ValidatorConstraint({name: 'amountDecimalValidator', async: false})
export class AmountDecimalValidator implements ValidatorConstraintInterface {
public defaultMessage(validationArguments?: ValidationArguments) {
return 'amount can\'t have more then 0 decimals.';
}

public validate(value: any, validationArguments?: ValidationArguments) {
return new BigNumber(value.amount || 0).decimalPlaces() == 18;
}

}
13 changes: 13 additions & 0 deletions src/model/validation/HasDecimalPlaces.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import {BigNumber} from 'bignumber.js';
import {buildMessage, ValidateBy, ValidationOptions} from 'class-validator';

export function HasDecimalPlaces(decimals: number, validationOptions?: ValidationOptions) {
return ValidateBy({
name: 'hasDecimalPlaces',
constraints: [decimals],
validator: {
validate: (value) => new BigNumber(value).decimalPlaces() <= decimals,
defaultMessage: buildMessage(eachPrefix => eachPrefix + '$property must have less than $constraint1 decimals', validationOptions),
}
}, validationOptions);
}
17 changes: 17 additions & 0 deletions src/model/validation/PriceDecimalValidator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import {BigNumber} from 'bignumber.js';
import {ValidationArguments, ValidatorConstraint, ValidatorConstraintInterface} from 'class-validator';

@ValidatorConstraint({name: 'priceDecimalValidator', async: false})
export class PriceDecimalValidator implements ValidatorConstraintInterface {
public defaultMessage(validationArguments?: ValidationArguments) {
return 'price can\'t have more then 18 decimals.';
}

public validate(value: any, validationArguments?: ValidationArguments) {
if (value.erc20Address) {
return new BigNumber(value.price || 0).decimalPlaces() <= 18;
}
return true;
}

}
26 changes: 26 additions & 0 deletions src/nft/marketplace/auction.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,32 @@ describe('Auction tests', () => {
expect(test).toBeDefined();
});

it('should not deploy auction - wrong validation', async () => {
const body = new DeployNftAuction();
body.fromPrivateKey = '0xa488a82b8b57c3ece4307525741fd8256781906c5fad948b85f1d63000948236';
body.feeRecipient = '0x8cb76aEd9C5e336ef961265c6079C14e9cD3D2eA';
body.auctionFee = 150.1;
body.feeCurrency = Currency.CUSD;
body.chain = Currency.CELO;
await deployAuction(true, body, 'https://alfajores-forno.celo-testnet.org');
});

it('should not create auction - wrong validation', async () => {
const body = new CreateAuction();
body.fromPrivateKey = '0xa488a82b8b57c3ece4307525741fd8256781906c5fad948b85f1d63000948236';
body.amount = '0.2';
body.nftAddress = '0x1214BEada6b25bc98f7494C7BDBf22C095FDCaBD';
body.contractAddress = '0x1214BEada6b25bc98f7494C7BDBf22C095FDCaBD';
body.endedAt = 123456789;
body.tokenId = tokenId;
body.id = tokenId;
body.isErc721 = false;
body.seller = '0x48d4bA7B2698A4b89635b9a2E391152350DB740f';
body.feeCurrency = Currency.CUSD;
body.chain = Currency.CELO;
await sendAuctionCreate(true, body, 'https://alfajores-forno.celo-testnet.org');
});

it('should create auction native asset', async () => {

const mint = new CeloMintErc721();
Expand Down
8 changes: 4 additions & 4 deletions src/nft/marketplace/auction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ export const getAuctionFeeRecipient = async (chain: Currency, contractAddress: s
* Before auction is created, seller must approve transfer of the NFT to the auction contract.
* Buyer will bid for the asset from the auction using native asset - send assets along the gid() smart contract call, or via ERC20 token.
* Buyer of the auction must perform approval for the smart contract to access ERC20 token, before the actual bid() method is called.
* Once there is higher bid then the actual one, the previous bidder's funds will be returned to him and new bidder will be the current winning one.
* Once there is higher bid than the actual one, the previous bidder's funds will be returned to him and new bidder will be the current winning one.
* When auction ends, anyone can settle the auction - NFT will be sent to the bidder, assets to the seller and fee to the operator.
* @param testnet chain to work with
* @param body request data
Expand All @@ -100,7 +100,7 @@ export const deployAuction = async (testnet: boolean, body: DeployNftAuction, pr
* Before auction is created, seller must approve transfer of the NFT to the auction contract.
* Buyer will bid for the asset from the auction using native asset - send assets along the gid() smart contract call, or via ERC20 token.
* Buyer of the auction must perform approval for the smart contract to access ERC20 token, before the actual bid() method is called.
* Once there is higher bid then the actual one, the previous bidder's funds will be returned to him and new bidder will be the current winning one.
* Once there is higher bid than the actual one, the previous bidder's funds will be returned to him and new bidder will be the current winning one.
* When auction ends, anyone can settle the auction - NFT will be sent to the bidder, assets to the seller and fee to the operator.
* @param testnet chain to work with
* @param body request data
Expand Down Expand Up @@ -234,7 +234,7 @@ export const prepareAuctionCancel = async (testnet: boolean, body: InvokeAuction
};

/**
* Settle auction. Only possible for the seller or the operator. There must be no buyer present for that auction. NFT asset is sent back to the seller. Auction must have ended.
* Settle auction. There must be buyer present for that auction. NFT will be sent to the bidder, assets to the seller and fee to the operator.
* @param testnet chain to work with
* @param body request data
* @param provider optional provider to enter. if not present, Tatum Web3 will be used.
Expand Down Expand Up @@ -314,7 +314,7 @@ export const sendAuctionCancel = async (testnet: boolean, body: InvokeAuctionOpe
helperBroadcastTx(body.chain, await prepareAuctionCancel(testnet, body, provider), body.signatureId);

/**
* Settle auction. Only possible for the seller or the operator. There must be no buyer present for that auction. NFT asset is sent back to the seller. Auction must have ended.
* Settle auction. There must be buyer present for that auction. NFT will be sent to the bidder, assets to the seller and fee to the operator.
* @param testnet chain to work with
* @param body request data
* @param provider optional provider to enter. if not present, Tatum Web3 will be used.
Expand Down

0 comments on commit a8e889b

Please sign in to comment.