Skip to content

Commit

Permalink
[Relay] Implement of the function to select the type of point
Browse files Browse the repository at this point in the history
  • Loading branch information
MichaelKim20 committed Oct 4, 2023
1 parent 2ffdbb0 commit c3a6155
Show file tree
Hide file tree
Showing 3 changed files with 151 additions and 25 deletions.
85 changes: 75 additions & 10 deletions packages/relay/src/routers/DefaultRouter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ export class DefaultRouter {
body("amount").custom(Validation.isAmount),
body("currency").exists(),
body("shopId").exists(),
body("signer").exists().isEthereumAddress(),
body("account").exists().isEthereumAddress(),
body("signature")
.exists()
.matches(/^(0x)[0-9a-f]{130}$/i),
Expand All @@ -202,13 +202,26 @@ export class DefaultRouter {
body("amount").custom(Validation.isAmount),
body("currency").exists(),
body("shopId").exists(),
body("signer").exists().isEthereumAddress(),
body("account").exists().isEthereumAddress(),
body("signature")
.exists()
.matches(/^(0x)[0-9a-f]{130}$/i),
],
this.payToken.bind(this)
);

// 포인트의 종류를 선택하는 기능
this.app.post(
"/setPointType",
[
body("pointType").exists().isIn(["0", "1"]),
body("account").exists().isEthereumAddress(),
body("signature")
.exists()
.matches(/^(0x)[0-9a-f]{130}$/i),
],
this.setPointType.bind(this)
);
}

private async getHealthStatus(req: express.Request, res: express.Response) {
Expand Down Expand Up @@ -239,14 +252,14 @@ export class DefaultRouter {
const amount: string = String(req.body.amount); // 구매 금액
const currency: string = String(req.body.currency).toLowerCase(); // 구매한 금액 통화코드
const shopId: string = String(req.body.shopId); // 구매한 가맹점 아이디
const signer: string = String(req.body.signer); // 구매자의 주소
const account: string = String(req.body.account); // 구매자의 주소
const signature: string = String(req.body.signature); // 서명

// TODO amount > 0 조건 검사

// 서명검증
const userNonce = await (await this.getLedgerContract()).nonceOf(signer);
if (!ContractUtils.verifyPayment(purchaseId, amount, currency, shopId, signer, userNonce, signature))
const userNonce = await (await this.getLedgerContract()).nonceOf(account);
if (!ContractUtils.verifyPayment(purchaseId, amount, currency, shopId, account, userNonce, signature))
return res.status(200).json(
this.makeResponseData(500, undefined, {
message: "Signature is not valid.",
Expand All @@ -255,7 +268,7 @@ export class DefaultRouter {

const tx = await (await this.getLedgerContract())
.connect(signerItem.signer)
.payPoint({ purchaseId, amount, currency, shopId, account: signer, signature });
.payPoint({ purchaseId, amount, currency, shopId, account, signature });

logger.http(`TxHash(payPoint): `, tx.hash);
return res.status(200).json(this.makeResponseData(200, { txHash: tx.hash }));
Expand Down Expand Up @@ -297,13 +310,13 @@ export class DefaultRouter {
const amount: string = String(req.body.amount); // 구매 금액
const currency: string = String(req.body.currency).toLowerCase(); // 구매한 금액 통화코드
const shopId: string = String(req.body.shopId); // 구매한 가맹점 아이디
const signer: string = String(req.body.signer); // 구매자의 주소
const account: string = String(req.body.account); // 구매자의 주소
const signature: string = String(req.body.signature); // 서명

// TODO amount > 0 조건 검사
// 서명검증
const userNonce = await (await this.getLedgerContract()).nonceOf(signer);
if (!ContractUtils.verifyPayment(purchaseId, amount, currency, shopId, signer, userNonce, signature))
const userNonce = await (await this.getLedgerContract()).nonceOf(account);
if (!ContractUtils.verifyPayment(purchaseId, amount, currency, shopId, account, userNonce, signature))
return res.status(200).json(
this.makeResponseData(500, undefined, {
message: "Signature is not valid.",
Expand All @@ -312,7 +325,7 @@ export class DefaultRouter {

const tx = await (await this.getLedgerContract())
.connect(signerItem.signer)
.payToken({ purchaseId, amount, currency, shopId, account: signer, signature });
.payToken({ purchaseId, amount, currency, shopId, account, signature });

logger.http(`TxHash(payToken): `, tx.hash);
return res.status(200).json(this.makeResponseData(200, { txHash: tx.hash }));
Expand All @@ -329,4 +342,56 @@ export class DefaultRouter {
this.releaseRelaySigner(signerItem);
}
}
/**
* 포인트의 종류를 선택한다.
* POST /setPointType
* @private
*/
private async setPointType(req: express.Request, res: express.Response) {
logger.http(`POST /setPointType`);

const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(200).json(
this.makeResponseData(501, undefined, {
message: "Failed to check the validity of parameters.",
validation: errors.array(),
})
);
}

const signerItem = await this.getRelaySigner();
try {
const pointType: number = Number(req.body.pointType);
const account: string = String(req.body.account); // 구매자의 주소
const signature: string = String(req.body.signature); // 서명

// 서명검증
const userNonce = await (await this.getLedgerContract()).nonceOf(account);
if (!ContractUtils.verifyPointType(pointType, account, userNonce, signature))
return res.status(200).json(
this.makeResponseData(500, undefined, {
message: "Signature is not valid.",
})
);

const tx = await (await this.getLedgerContract())
.connect(signerItem.signer)
.setPointType(pointType, account, signature);

logger.http(`TxHash(setPointType): `, tx.hash);
return res.status(200).json(this.makeResponseData(200, { txHash: tx.hash }));
} catch (error: any) {
let message = ContractUtils.cacheEVMError(error as any);
if (message === "") message = "Failed change point type";
logger.error(`POST /setPointType :`, message);
return res.status(200).json(
this.makeResponseData(500, undefined, {
message,
})
);
} finally {
this.releaseRelaySigner(signerItem);
}
}
}
47 changes: 38 additions & 9 deletions packages/relay/src/utils/ContractUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,16 @@ export class ContractUtils {
return Buffer.from(hex.substring(start), "hex");
}

public static getTimeStamp(): number {
return Math.floor(new Date().getTime() / 1000);
}

public static delay(interval: number): Promise<void> {
return new Promise<void>((resolve, _) => {
setTimeout(resolve, interval);
});
}

public static getPhoneHash(phone: string): string {
const encodedResult = hre.ethers.utils.defaultAbiCoder.encode(
["string", "string"],
Expand Down Expand Up @@ -123,27 +133,46 @@ export class ContractUtils {
amount: BigNumberish,
currency: string,
shopId: string,
signerAddress: string,
account: string,
nonce: BigNumberish,
signature: string
): boolean {
const message = ContractUtils.getPaymentMessage(signerAddress, purchaseId, amount, currency, shopId, nonce);
const message = ContractUtils.getPaymentMessage(account, purchaseId, amount, currency, shopId, nonce);
let res: string;
try {
res = ethers.utils.verifyMessage(message, signature);
} catch (error) {
return false;
}
return res.toLowerCase() === signerAddress.toLowerCase();
return res.toLowerCase() === account.toLowerCase();
}

public static getTimeStamp(): number {
return Math.floor(new Date().getTime() / 1000);
public static getPointTypeMessage(type: BigNumberish, account: string, nonce: BigNumberish): Uint8Array {
const encodedResult = hre.ethers.utils.defaultAbiCoder.encode(
["uint256", "address", "uint256"],
[type, account, nonce]
);
return arrayify(hre.ethers.utils.keccak256(encodedResult));
}

public static delay(interval: number): Promise<void> {
return new Promise<void>((resolve, _) => {
setTimeout(resolve, interval);
});
public static async signPointType(signer: Signer, type: BigNumberish, nonce: BigNumberish): Promise<string> {
const message = ContractUtils.getPointTypeMessage(type, await signer.getAddress(), nonce);
return signer.signMessage(message);
}

public static verifyPointType(
type: BigNumberish,
account: string,
nonce: BigNumberish,
signature: string
): boolean {
const message = ContractUtils.getPointTypeMessage(type, account, nonce);
let res: string;
try {
res = ethers.utils.verifyMessage(message, signature);
} catch (error) {
return false;
}
return res.toLowerCase() === account.toLowerCase();
}
}
44 changes: 38 additions & 6 deletions packages/relay/test/Endpoints.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -349,6 +349,38 @@ describe("Test of Server", function () {
});
});

context("Change point type", () => {
it("Check point type - before", async () => {
const userIndex = 0;
const pointType = await ledgerContract.pointTypeOf(users[userIndex].address);
expect(pointType).to.equal(0);
});

it("Send point type", async () => {
const pointType = 1;
const userIndex = 0;
const nonce = await ledgerContract.nonceOf(users[userIndex].address);
const signature = await ContractUtils.signPointType(users[userIndex], pointType, nonce);
const uri = URI(serverURL).directory("setPointType");
const url = uri.toString();
const response = await client.post(url, {
pointType,
account: users[userIndex].address,
signature,
});

expect(response.data.code).to.equal(200);
expect(response.data.data).to.not.equal(undefined);
expect(response.data.data.txHash).to.match(/^0x[A-Fa-f0-9]{64}$/i);
});

it("Check point type - after", async () => {
const userIndex = 0;
const pointType = await ledgerContract.pointTypeOf(users[userIndex].address);
expect(pointType).to.equal(1);
});
});

context("payPoint & payToken", () => {
const purchase: IPurchaseData = {
purchaseId: "P000001",
Expand Down Expand Up @@ -391,7 +423,7 @@ describe("Test of Server", function () {
amount: over_purchaseAmount.toString(),
currency: purchase.currency,
shopId: shop.shopId,
signer: users[purchase.userIndex].address,
account: users[purchase.userIndex].address,
signature,
});

Expand All @@ -417,7 +449,7 @@ describe("Test of Server", function () {
amount: purchaseAmount.toString(),
currency: purchase.currency,
shopId: shop.shopId,
signer: users[purchase.userIndex].address,
account: users[purchase.userIndex].address,
signature,
});

Expand All @@ -443,7 +475,7 @@ describe("Test of Server", function () {
amount: purchaseAmount.toString(),
currency: purchase.currency,
shopId: shop.shopId,
signer: users[purchase.userIndex].address,
account: users[purchase.userIndex].address,
signature,
});

Expand Down Expand Up @@ -472,7 +504,7 @@ describe("Test of Server", function () {
amount: over_purchaseAmount.toString(),
currency: purchase.currency,
shopId: shop.shopId,
signer: users[purchase.userIndex].address,
account: users[purchase.userIndex].address,
signature,
});

Expand All @@ -498,7 +530,7 @@ describe("Test of Server", function () {
amount: purchaseAmount.toString(),
currency: purchase.currency,
shopId: shop.shopId,
signer: users[purchase.userIndex].address,
account: users[purchase.userIndex].address,
signature,
});

Expand All @@ -524,7 +556,7 @@ describe("Test of Server", function () {
amount: purchaseAmount.toString(),
currency: purchase.currency,
shopId: shop.shopId,
signer: users[purchase.userIndex].address,
account: users[purchase.userIndex].address,
signature,
});

Expand Down

0 comments on commit c3a6155

Please sign in to comment.