Skip to content

Commit

Permalink
Merge pull request #63 from pinknetworkx/develop
Browse files Browse the repository at this point in the history
Release 1.3.12
  • Loading branch information
fabian-emilius authored Apr 27, 2022
2 parents 0b5280c + dbbd0f8 commit eac33f3
Show file tree
Hide file tree
Showing 21 changed files with 1,186 additions and 730 deletions.
6 changes: 0 additions & 6 deletions definitions/materialized/atomicmarket_sale_prices.sql

This file was deleted.

4 changes: 0 additions & 4 deletions definitions/migrations/1.3.11/atomicassets.sql

This file was deleted.

14 changes: 4 additions & 10 deletions definitions/migrations/1.3.11/database.sql
Original file line number Diff line number Diff line change
@@ -1,14 +1,8 @@

select brin_summarize_new_values('contract_traces_idx_global_sequence'::regclass);
select brin_summarize_new_values('contract_traces_idx_created_at_time'::regclass);
SELECT brin_summarize_new_values('contract_traces_idx_global_sequence'::regclass);
SELECT brin_summarize_new_values('contract_traces_idx_created_at_time'::regclass);


ALTER TABLE contract_traces SET (autovacuum_vacuum_scale_factor = 0.0);
ALTER TABLE contract_traces SET (autovacuum_vacuum_threshold = 100000);
ALTER TABLE contract_traces SET (autovacuum_analyze_scale_factor = 0.0);
ALTER TABLE contract_traces SET (autovacuum_analyze_threshold = 1000000);

alter index contract_traces_idx_global_sequence set (autosummarize = on);
alter index contract_traces_idx_created_at_time set (autosummarize = on);
ALTER INDEX contract_traces_idx_global_sequence set (autosummarize = on);
ALTER INDEX contract_traces_idx_created_at_time set (autosummarize = on);

UPDATE dbinfo SET "value" = '1.3.11' WHERE name = 'version';
5 changes: 5 additions & 0 deletions definitions/migrations/1.3.12/atomicassets.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
SELECT brin_summarize_new_values('atomicassets_mints_idx_asset_id'::regclass);

ALTER INDEX atomicassets_mints_idx_asset_id set (autosummarize = on);

ALTER TABLE atomicassets_templates SET (fillfactor = 90);
1 change: 1 addition & 0 deletions definitions/migrations/1.3.12/atomicmarket.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
DROP MATERIALIZED VIEW IF EXISTS atomicmarket_sale_prices;
1 change: 1 addition & 0 deletions definitions/migrations/1.3.12/database.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
UPDATE dbinfo SET "value" = '1.3.12' WHERE name = 'version';
54 changes: 27 additions & 27 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "eosio-contract-api",
"version": "1.3.11",
"version": "1.3.12",
"description": "EOSIO Contract API",
"author": "pink.gg",
"license": "AGPL-3.0",
Expand All @@ -22,55 +22,55 @@
"dependencies": {
"async-exit-hook": "^2.0.1",
"atomicassets": "^1.4.2",
"await-lock": "^2.1.0",
"body-parser": "^1.19.1",
"await-lock": "^2.2.1",
"body-parser": "^1.20.0",
"common-tags": "^1.8.2",
"cookie-parser": "^1.4.6",
"cors": "^2.8.5",
"eosjs": "^22.1.0",
"express": "^4.17.2",
"express-rate-limit": "^6.2.0",
"express": "^4.18.0",
"express-rate-limit": "^6.4.0",
"int64-buffer": "^1.0.1",
"ioredis": "^4.28.3",
"moize": "^6.1.0",
"ioredis": "^5.0.4",
"moize": "^6.1.1",
"node-fetch": "^2.6.7",
"node-worker-threads-pool": "^1.5.1",
"p-queue": "^6.6.2",
"pg": "^8.7.1",
"pm2": "^5.1.2",
"pg": "^8.7.3",
"pm2": "^5.2.0",
"prom-client": "^14.0.1",
"rate-limit-redis": "^3.0.0",
"redis": "^4.0.3",
"socket.io": "^4.4.1",
"rate-limit-redis": "^3.0.1",
"redis": "^4.0.6",
"socket.io": "^4.5.0",
"swagger-ui-express": "^4.3.0",
"text-encoding": "^0.7.0",
"winston": "^3.3.3",
"ws": "^7.5.6"
"winston": "^3.7.2",
"ws": "^7.5.7"
},
"devDependencies": {
"@types/body-parser": "^1.19.2",
"@types/chai": "^4.3.0",
"@types/chai": "^4.3.1",
"@types/common-tags": "^1.8.1",
"@types/cookie-parser": "^1.4.2",
"@types/cors": "^2.8.12",
"@types/elliptic": "^6.4.14",
"@types/express": "^4.17.13",
"@types/ioredis": "^4.28.7",
"@types/mocha": "^9.0.0",
"@types/node": "^16.11.12",
"@types/node-fetch": "^2.5.12",
"@types/pg": "^8.6.4",
"@types/ioredis": "^4.28.10",
"@types/mocha": "^9.1.1",
"@types/node": "^16.11.29",
"@types/node-fetch": "^2.6.1",
"@types/pg": "^8.6.5",
"@types/swagger-ui-express": "^4.1.3",
"@types/text-encoding": "^0.0.36",
"@types/ws": "^7.4.7",
"@typescript-eslint/eslint-plugin": "^5.7.0",
"@typescript-eslint/parser": "^5.7.0",
"chai": "^4.3.4",
"@typescript-eslint/eslint-plugin": "^5.21.0",
"@typescript-eslint/parser": "^5.21.0",
"chai": "^4.3.6",
"eslint": "^7.32.0",
"mocha": "^9.1.3",
"mocha": "^9.2.2",
"rimraf": "^3.0.2",
"ts-loader": "^9.2.6",
"ts-node": "^10.4.0",
"typescript": "^4.5.5"
"ts-loader": "^9.2.8",
"ts-node": "^10.7.0",
"typescript": "^4.6.3"
}
}
2 changes: 1 addition & 1 deletion src/api/namespaces/atomicassets/test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ export class AtomicAssetsTestClient extends TestClient {
contract: 'aatest',
offer_id: values.offer_id ?? (await this.createOffer()).offer_id,
owner: 'owner',
index: 0,
index: 1,
asset_id: values.asset_id ?? (await this.createAsset(assetValues)).asset_id,
...values,
});
Expand Down
15 changes: 6 additions & 9 deletions src/api/namespaces/atomicmarket/format.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,27 +60,24 @@ export function formatBuyoffer(row: any): any {
}

export function formatSale(row: any): any {
const data = {...row};
const {raw_price, sale_state, offer_state, ...data} = row;

data.price.amount = row.raw_price;
data.price.amount = raw_price;

if (row.sale_state === SaleState.WAITING.valueOf()) {
if (sale_state === SaleState.WAITING.valueOf()) {
data.state = SaleApiState.WAITING.valueOf();
} else if (row.sale_state === SaleState.LISTED.valueOf() && row.offer_state === OfferState.PENDING.valueOf()) {
} else if (sale_state === SaleState.LISTED.valueOf() && offer_state === OfferState.PENDING.valueOf()) {
data.state = SaleApiState.LISTED.valueOf();
} else if (row.sale_state === SaleState.CANCELED.valueOf()) {
} else if (sale_state === SaleState.CANCELED.valueOf()) {
data.state = SaleApiState.CANCELED.valueOf();
} else if (row.sale_state === SaleState.SOLD.valueOf()) {
} else if (sale_state === SaleState.SOLD.valueOf()) {
data.state = SaleApiState.SOLD.valueOf();
} else {
data.state = SaleApiState.INVALID.valueOf();
}

delete data.raw_price;
delete data.raw_token_symbol;
delete data.raw_token_precision;
delete data.sale_state;
delete data.offer_state;

return data;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -177,42 +177,28 @@ describe('AtomicMarket Sales API', () => {
.to.deep.equal([sale_id]);
});

txit('throws error when maximum price filter is set without settlement symbol', async () => {
txit('filters by minimum price', async () => {
let err;
try {
await getSalesIds({max_price: '1'});
await getSalesIds({min_price: '2'});
} catch (e) {
err = e;
}

expect(err).to.be.instanceof(ApiError);
expect(err.message).to.equal('Price range filters require the "symbol" filter');
});

txit('filters by minimum price', async () => {
await client.createSale({});

const {sale_id} = await client.createSale({
listing_price: 200000000,
});

await client.query('REFRESH MATERIALIZED VIEW atomicmarket_sale_prices');

expect(await getSalesIds({symbol: 'TEST', min_price: '2'}))
.to.deep.equal([sale_id]);
expect(err.message).to.equal('Price filters are removed in /v1/sales, use /v2/sales');
});

txit('filters by maximum price', async () => {
await client.createSale({
listing_price: 200000000,
});

const {sale_id} = await client.createSale({});

await client.query('REFRESH MATERIALIZED VIEW atomicmarket_sale_prices');
let err;
try {
await getSalesIds({max_price: '1'});
} catch (e) {
err = e;
}

expect(await getSalesIds({symbol: 'TEST', max_price: '1'}))
.to.deep.equal([sale_id]);
expect(err).to.be.instanceof(ApiError);
expect(err.message).to.equal('Price filters are removed in /v1/sales, use /v2/sales');
});

txit('filters out seller contracts unless whitelisted', async () => {
Expand Down Expand Up @@ -670,15 +656,15 @@ describe('AtomicMarket Sales API', () => {
});

txit('orders by price', async () => {
const sale_id2 = `${client.getId()}`;
const {sale_id: sale_id1} = await client.createSale({listing_price: 2});

await client.createSale({listing_price: 1, sale_id: sale_id2});

await client.query('REFRESH MATERIALIZED VIEW atomicmarket_sale_prices');
let err;
try {
await getSalesIds({sort: 'price'});
} catch (e) {
err = e;
}

expect(await getSalesIds({sort: 'price'}))
.to.deep.equal([sale_id1, sale_id2]);
expect(err).to.be.instanceof(ApiError);
expect(err.message).to.equal('Sorting by price removed in /v1/sales, use /v2/sales');
});

txit('orders by template_mint', async () => {
Expand Down
107 changes: 6 additions & 101 deletions src/api/namespaces/atomicmarket/handlers/sales.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,7 @@ import { AtomicMarketContext } from '../index';
import { applyActionGreylistFilters, getContractActionLogs } from '../../../utils';
import QueryBuilder from '../../../builder';
import { buildSaleFilter, hasListingFilter } from '../utils';
import { buildAssetFilter, buildGreylistFilter, hasAssetFilter, hasDataFilters } from '../../atomicassets/utils';
import { OfferState } from '../../../../filler/handlers/atomicassets';
import { SaleState } from '../../../../filler/handlers/atomicmarket';
import { buildGreylistFilter, hasAssetFilter, hasDataFilters } from '../../atomicassets/utils';
import { filterQueryArgs } from '../../validation';

export async function getSaleAction(params: RequestValues, ctx: AtomicMarketContext): Promise<any> {
Expand Down Expand Up @@ -63,11 +61,14 @@ export async function getSalesAction(params: RequestValues, ctx: AtomicMarketCon
count: {type: 'bool'}
});

if (args.sort === 'price') {
throw new ApiError('Sorting by price removed in /v1/sales, use /v2/sales', 400);
}

const query = new QueryBuilder(`
SELECT listing.sale_id
FROM atomicmarket_sales listing
JOIN atomicassets_offers offer ON (listing.assets_contract = offer.contract AND listing.offer_id = offer.offer_id)
LEFT JOIN atomicmarket_sale_prices price ON (price.market_contract = listing.market_contract AND price.sale_id = listing.sale_id)
`);

query.equal('listing.market_contract', ctx.coreArgs.atomicmarket_account);
Expand Down Expand Up @@ -96,7 +97,7 @@ export async function getSalesAction(params: RequestValues, ctx: AtomicMarketCon
sale_id: {column: 'listing.sale_id', nullable: false, numericIndex: true},
created: {column: 'listing.created_at_time', nullable: false, numericIndex: true},
updated: {column: 'listing.updated_at_time', nullable: false, numericIndex: true},
price: {column: args.state === '3' ? 'listing.final_price' : 'price.price', nullable: true, numericIndex: false},
price: {column: 'listing.final_price', nullable: true, numericIndex: true},
template_mint: {column: 'LOWER(listing.template_mint)', nullable: true, numericIndex: false}
};

Expand Down Expand Up @@ -124,99 +125,3 @@ export async function getSalesAction(params: RequestValues, ctx: AtomicMarketCon
export async function getSalesCountAction(params: RequestValues, ctx: AtomicMarketContext): Promise<any> {
return await getSalesAction({...params, count: 'true'}, ctx);
}

export async function getSalesTemplatesAction(params: RequestValues, ctx: AtomicMarketContext): Promise<any> {
const maxLimit = ctx.coreArgs.limits?.sales_templates || 100;
const args = filterQueryArgs(params, {
symbol: {type: 'string', min: 1},
collection_name: {type: 'string', min: 1},
collection_whitelist: {type: 'string', min: 1},

min_price: {type: 'float', min: 0},
max_price: {type: 'float', min: 0},

page: {type: 'int', min: 1, default: 1},
limit: {type: 'int', min: 1, max: maxLimit, default: Math.min(maxLimit, 100)},
sort: {
type: 'string',
allowedValues: ['template_id', 'price'],
default: 'template_id'
},
order: {type: 'string', allowedValues: ['asc', 'desc'], default: 'desc'},
});

if (!args.symbol) {
throw new ApiError('symbol parameter is required', 200);
}

if (!hasAssetFilter(params) && !args.collection_whitelist) {
throw new ApiError('You need to specify an asset filter!', 200);
}

const query = new QueryBuilder(`
SELECT DISTINCT ON(asset.contract, asset.template_id)
sale.market_contract, sale.sale_id, asset.contract assets_contract, asset.template_id, price.price
FROM
atomicmarket_sales sale, atomicassets_offers offer, atomicassets_offers_assets offer_asset,
atomicassets_assets asset, atomicmarket_sale_prices price, atomicassets_templates "template"
`);

query.addCondition(`
sale.assets_contract = offer.contract AND sale.offer_id = offer.offer_id AND
offer.contract = offer_asset.contract AND offer.offer_id = offer_asset.offer_id AND
offer_asset.contract = asset.contract AND offer_asset.asset_id = asset.asset_id AND
asset.contract = "template".contract AND asset.template_id = "template".template_id AND
sale.market_contract = price.market_contract AND sale.sale_id = price.sale_id AND
asset.template_id IS NOT NULL AND offer_asset.index = 1 AND
offer.state = ${OfferState.PENDING.valueOf()} AND sale.state = ${SaleState.LISTED.valueOf()}
`);

query.equal('sale.market_contract', ctx.coreArgs.atomicmarket_account);
query.equal('sale.settlement_symbol', args.symbol);

if (!args.collection_name) {
buildGreylistFilter(params, query, {collectionName: 'sale.collection_name'});
}

buildAssetFilter(params, query, {assetTable: '"asset"', templateTable: '"template"'});

if (args.min_price) {
query.addCondition('price.price >= ' + query.addVariable(args.min_price) + ' * POW(10, price.settlement_precision)');
}

if (args.max_price) {
query.addCondition('price.price <= ' + query.addVariable(args.max_price) + ' * POW(10, price.settlement_precision)');
}

if (args.collection_name) {
query.equalMany('sale.collection_name', args.collection_name.split(','));
}

query.append('ORDER BY asset.contract, asset.template_id, price.price ASC');

const sortColumnMapping: {[key: string]: string} = {
price: 't1.price',
template_id: 't1.template_id',
};

let queryString = 'SELECT * FROM (' + query.buildString() + ') t1 ';
queryString += 'ORDER BY ' + sortColumnMapping[args.sort] + ' ' + args.order + ' NULLS LAST, t1.template_id ASC ';
queryString += 'LIMIT ' + query.addVariable(args.limit) + ' OFFSET ' + query.addVariable((args.page - 1) * args.limit) + ' ';

const saleResult = await ctx.db.query(queryString, query.buildValues());

const result = await ctx.db.query(
'SELECT * FROM atomicmarket_sales_master WHERE market_contract = $1 AND sale_id = ANY ($2)',
[ctx.coreArgs.atomicmarket_account, saleResult.rows.map(row => row.sale_id)]
);

const saleLookup: {[key: string]: any} = result.rows.reduce((prev, current) => {
prev[String(current.sale_id)] = current;

return prev;
}, {});

return await fillSales(
ctx.db, ctx.coreArgs.atomicassets_account, saleResult.rows.map((row) => formatSale(saleLookup[String(row.sale_id)]))
);
}
Loading

0 comments on commit eac33f3

Please sign in to comment.