Skip to content

Commit

Permalink
Add API related to the settlement function
Browse files Browse the repository at this point in the history
  • Loading branch information
MichaelKim20 committed Oct 28, 2024
1 parent 724d7fe commit 1b74f4d
Show file tree
Hide file tree
Showing 7 changed files with 1,302 additions and 21 deletions.
2 changes: 1 addition & 1 deletion packages/library/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "acc-contracts-lib-v2",
"version": "2.8.0",
"version": "2.9.0",
"description": "",
"main": "dist/bundle-cjs.js",
"module": "dist/bundle-esm.js",
Expand Down
3 changes: 2 additions & 1 deletion packages/relay/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@
},
"dependencies": {
"@ethersproject/bignumber": "^5.7.0",
"@ethersproject/bytes": "^5.7.0",
"@ethersproject/constants": "^5.7.0",
"@ethersproject/wallet": "^5.7.0",
"@ethersproject/experimental": "^5.7.0",
Expand All @@ -70,7 +71,7 @@
"@typechain/ethers-v5": "^10.1.0",
"@typechain/hardhat": "^6.1.2",
"acc-bridge-contracts-v2": "~2.5.0",
"acc-contracts-v2": "~2.8.0",
"acc-contracts-v2": "~2.9.0",
"argparse": "^2.0.1",
"assert": "^2.0.0",
"axios": "^1.6.7",
Expand Down
323 changes: 323 additions & 0 deletions packages/relay/src/routers/ShopRouter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import { body, param, query, validationResult } from "express-validator";
import * as hre from "hardhat";

// tslint:disable-next-line:no-implicit-dependencies
import { BigNumber } from "@ethersproject/bignumber";
import { AddressZero } from "@ethersproject/constants";
import { ContractManager } from "../contract/ContractManager";
import { Metrics } from "../metrics/Metrics";
Expand Down Expand Up @@ -246,6 +247,88 @@ export class ShopRouter {
],
this.shop_refundable.bind(this)
);
this.app.post(
"/v1/shop/settlement/manager/set",
[
body("shopId")
.exists()
.trim()
.matches(/^(0x)[0-9a-f]{64}$/i),
body("account").exists().trim().isEthereumAddress(),
body("managerId")
.exists()
.trim()
.matches(/^(0x)[0-9a-f]{64}$/i),
body("signature")
.exists()
.trim()
.matches(/^(0x)[0-9a-f]{130}$/i),
],
this.shop_settlement_manager_set.bind(this)
);
this.app.post(
"/v1/shop/settlement/manager/remove",
[
body("shopId")
.exists()
.trim()
.matches(/^(0x)[0-9a-f]{64}$/i),
body("account").exists().trim().isEthereumAddress(),
body("signature")
.exists()
.trim()
.matches(/^(0x)[0-9a-f]{130}$/i),
],
this.shop_settlement_manager_remove.bind(this)
);
this.app.get(
"/v1/shop/settlement/manager/get/:shopId",
[
param("shopId")
.exists()
.trim()
.matches(/^(0x)[0-9a-f]{64}$/i),
],
this.shop_settlement_manager_get.bind(this)
);
this.app.get(
"/v1/shop/settlement/client/length/:shopId",
[
param("shopId")
.exists()
.trim()
.matches(/^(0x)[0-9a-f]{64}$/i),
],
this.shop_settlement_client_length.bind(this)
);
this.app.get(
"/v1/shop/settlement/client/list/:shopId",
[
param("shopId")
.exists()
.trim()
.matches(/^(0x)[0-9a-f]{64}$/i),
query("startIndex").exists().trim().isNumeric(),
query("endIndex").exists().trim().isNumeric(),
],
this.shop_settlement_client_list.bind(this)
);
this.app.post(
"/v1/shop/settlement/collect",
[
body("shopId")
.exists()
.trim()
.matches(/^(0x)[0-9a-f]{64}$/i),
body("account").exists().trim().isEthereumAddress(),
body("clients").exists(),
body("signature")
.exists()
.trim()
.matches(/^(0x)[0-9a-f]{130}$/i),
],
this.shop_settlement_collect.bind(this)
);
}

private async getNonce(req: express.Request, res: express.Response) {
Expand Down Expand Up @@ -1306,4 +1389,244 @@ export class ShopRouter {
return res.status(200).json(this.makeResponseData(msg.code, undefined, msg.error));
}
}

/**
* POST /v1/shop/settlement/manager/set
* @private
*/
private async shop_settlement_manager_set(req: express.Request, res: express.Response) {
logger.http(`POST /v1/shop/settlement/manager/set ${req.ip}:${JSON.stringify(req.body)}`);

const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(200).json(ResponseMessage.getErrorMessage("2001", { validation: errors.array() }));
}

const signerItem = await this.getRelaySigner();
try {
const shopId: string = String(req.body.shopId).trim();
const account: string = String(req.body.account).trim();
const managerId: string = String(req.body.managerId).trim();
const signature: string = String(req.body.signature).trim();

const contract = this.contractManager.sideShopContract;
const message = ContractUtils.getSetSettlementManagerMessage(
shopId,
managerId,
await contract.nonceOf(account),
this.contractManager.sideChainId
);
if (!ContractUtils.verifyMessage(account, message, signature))
return res.status(200).json(ResponseMessage.getErrorMessage("1501"));

const tx = await contract.connect(signerItem.signer).setSettlementManager(shopId, managerId, signature);
this.metrics.add("success", 1);
return res.status(200).json(
this.makeResponseData(0, {
shopId,
managerId,
txHash: tx.hash,
})
);
} catch (error: any) {
const msg = ResponseMessage.getEVMErrorMessage(error);
logger.error(`POST /v1/shop/settlement/manager/set : ${msg.error.message}`);
this.metrics.add("failure", 1);
return res.status(200).json(msg);
} finally {
this.releaseRelaySigner(signerItem);
}
}

/**
* POST /v1/shop/settlement/manager/remove
* @private
*/
private async shop_settlement_manager_remove(req: express.Request, res: express.Response) {
logger.http(`POST /v1/shop/settlement/manager/remove ${req.ip}:${JSON.stringify(req.body)}`);

const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(200).json(ResponseMessage.getErrorMessage("2001", { validation: errors.array() }));
}

const signerItem = await this.getRelaySigner();
try {
const shopId: string = String(req.body.shopId).trim();
const account: string = String(req.body.account).trim();
const signature: string = String(req.body.signature).trim();

const contract = this.contractManager.sideShopContract;
const message = ContractUtils.getRemoveSettlementManagerMessage(
shopId,
await contract.nonceOf(account),
this.contractManager.sideChainId
);
if (!ContractUtils.verifyMessage(account, message, signature))
return res.status(200).json(ResponseMessage.getErrorMessage("1501"));

const tx = await contract.connect(signerItem.signer).removeSettlementManager(shopId, signature);
this.metrics.add("success", 1);
return res.status(200).json(
this.makeResponseData(0, {
shopId,
txHash: tx.hash,
})
);
} catch (error: any) {
const msg = ResponseMessage.getEVMErrorMessage(error);
logger.error(`POST /v1/shop/settlement/manager/remove : ${msg.error.message}`);
this.metrics.add("failure", 1);
return res.status(200).json(msg);
} finally {
this.releaseRelaySigner(signerItem);
}
}

/**
* GET /v1/shop/settlement/manager/get
* @private
*/
private async shop_settlement_manager_get(req: express.Request, res: express.Response) {
logger.http(`GET /v1/shop/settlement/manager/get ${req.ip}:${JSON.stringify(req.params)}`);

const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(200).json(ResponseMessage.getErrorMessage("2001", { validation: errors.array() }));
}

try {
const shopId: string = String(req.params.shopId).trim();

const contract = this.contractManager.sideShopContract;
const managerId = await contract.settlementManagerOf(shopId);
this.metrics.add("success", 1);
return res.status(200).json(
this.makeResponseData(0, {
shopId,
managerId,
})
);
} catch (error: any) {
const msg = ResponseMessage.getEVMErrorMessage(error);
logger.error(`GET /v1/shop/settlement/manager/get : ${msg.error.message}`);
this.metrics.add("failure", 1);
return res.status(200).json(msg);
}
}

/**
* GET /v1/shop/settlement/client/length
* @private
*/
private async shop_settlement_client_length(req: express.Request, res: express.Response) {
logger.http(`GET /v1/shop/settlement/client/length ${req.ip}:${JSON.stringify(req.body)}`);

const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(200).json(ResponseMessage.getErrorMessage("2001", { validation: errors.array() }));
}

try {
const shopId: string = String(req.params.shopId).trim();

const contract = this.contractManager.sideShopContract;
const length = await contract.getSettlementClientLength(shopId);
this.metrics.add("success", 1);
return res.status(200).json(
this.makeResponseData(0, {
shopId,
length: length.toNumber(),
})
);
} catch (error: any) {
const msg = ResponseMessage.getEVMErrorMessage(error);
logger.error(`GET /v1/shop/settlement/client/length : ${msg.error.message}`);
this.metrics.add("failure", 1);
return res.status(200).json(msg);
}
}

/**
* GET /v1/shop/settlement/client/list
* @private
*/
private async shop_settlement_client_list(req: express.Request, res: express.Response) {
logger.http(`GET /v1/shop/settlement/client/list ${req.ip}:${JSON.stringify(req.body)}`);

const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(200).json(ResponseMessage.getErrorMessage("2001", { validation: errors.array() }));
}

try {
const shopId: string = String(req.params.shopId).trim();
const startIndex = BigNumber.from(String(req.query.startIndex).trim());
const endIndex = BigNumber.from(String(req.query.endIndex).trim());

const contract = this.contractManager.sideShopContract;
const clients = await contract.getSettlementClientList(shopId, startIndex, endIndex);
this.metrics.add("success", 1);
return res.status(200).json(
this.makeResponseData(0, {
shopId,
clients,
})
);
} catch (error: any) {
const msg = ResponseMessage.getEVMErrorMessage(error);
logger.error(`GET /v1/shop/settlement/client/list : ${msg.error.message}`);
this.metrics.add("failure", 1);
return res.status(200).json(msg);
}
}

/**
* POST /v1/shop/settlement/collect
* @private
*/
private async shop_settlement_collect(req: express.Request, res: express.Response) {
logger.http(`POST /v1/shop/settlement/collect ${req.ip}:${JSON.stringify(req.body)}`);

const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(200).json(ResponseMessage.getErrorMessage("2001", { validation: errors.array() }));
}

const signerItem = await this.getRelaySigner();
try {
const shopId: string = String(req.body.shopId).trim();
const account: string = String(req.body.account).trim();
const clients: string[] = String(req.body.clients).trim().split(",");
const signature: string = String(req.body.signature).trim();

const contract = this.contractManager.sideShopContract;
const message = ContractUtils.getCollectSettlementAmountMultiClientMessage(
shopId,
clients,
await contract.nonceOf(account),
this.contractManager.sideChainId
);
if (!ContractUtils.verifyMessage(account, message, signature))
return res.status(200).json(ResponseMessage.getErrorMessage("1501"));

const tx = await contract
.connect(signerItem.signer)
.collectSettlementAmountMultiClient(shopId, clients, signature);
this.metrics.add("success", 1);
return res.status(200).json(
this.makeResponseData(0, {
shopId,
txHash: tx.hash,
})
);
} catch (error: any) {
const msg = ResponseMessage.getEVMErrorMessage(error);
logger.error(`POST /v1/shop/settlement/collect : ${msg.error.message}`);
this.metrics.add("failure", 1);
return res.status(200).json(msg);
} finally {
this.releaseRelaySigner(signerItem);
}
}
}
Loading

0 comments on commit 1b74f4d

Please sign in to comment.