diff --git a/.gitignore b/.gitignore index 90daadb..2b5397c 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,4 @@ coverage *.tgz *.log .turbo +.hidden diff --git a/packages/client-test/data/shop_info0.json b/packages/client-test/data/shop_info0.json new file mode 100644 index 0000000..fcd8e03 --- /dev/null +++ b/packages/client-test/data/shop_info0.json @@ -0,0 +1,5 @@ +{ + "shopId": "0x00011936a68f7c26797fa2ab64d444ea82c2fb1af36cdea6d4ff845da635f287", + "address": "0xB6f69F0e9e70034ba0578C542476cC13eF739269", + "privateKey": "0x595f911dcf0845cb1f2d0e5cec9f1ccfd62fa199ebeae215a72aa56014edbb32" +} diff --git a/packages/client-test/data/shop_info1.json b/packages/client-test/data/shop_info1.json new file mode 100644 index 0000000..e4d6f31 --- /dev/null +++ b/packages/client-test/data/shop_info1.json @@ -0,0 +1,5 @@ +{ + "shopId": "0x00011f2355a63165608a0f1c00cf1a03183cf9e7e0becb874092f1cdf9db8aa0", + "address": "0x9b3ABc653D15B5a0f4E43E6340096C1C9BB2CA2f", + "privateKey": "0xc3bc6d1141896f1729ece9c7a8bb97c6222cac8e7d902317746b073a369a263e" +} diff --git a/packages/client-test/data/shop_infos.json b/packages/client-test/data/shop_infos.json new file mode 100644 index 0000000..f851e03 --- /dev/null +++ b/packages/client-test/data/shop_infos.json @@ -0,0 +1,14 @@ +[{ + "shopId": "0x00011936a68f7c26797fa2ab64d444ea82c2fb1af36cdea6d4ff845da635f287", + "address": "0xB6f69F0e9e70034ba0578C542476cC13eF739269", + "privateKey": "0x595f911dcf0845cb1f2d0e5cec9f1ccfd62fa199ebeae215a72aa56014edbb32", + "name": "상점1", + "currency": "php" +},{ + "shopId": "0x00011f2355a63165608a0f1c00cf1a03183cf9e7e0becb874092f1cdf9db8aa0", + "address": "0x9b3ABc653D15B5a0f4E43E6340096C1C9BB2CA2f", + "privateKey": "0xc3bc6d1141896f1729ece9c7a8bb97c6222cac8e7d902317746b073a369a263e", + "name": "상점2", + "currency": "php" +} +] diff --git a/packages/client-test/data/user_info.json b/packages/client-test/data/user_info.json index 77e21ec..f67e6d6 100644 --- a/packages/client-test/data/user_info.json +++ b/packages/client-test/data/user_info.json @@ -1,5 +1,5 @@ { "phone": "+82 10-9520-1803", - "address": "0x9a568e50556e7d51d1d477b22C28a099d33Ea04f", - "privateKey": "0x00e8b7fdbed0d29a71339ca7699ff3982708867725e8c49e04ced69222189551" + "address": "0x5A3Fc8990417b3e6ddCdAE0E8039E798A609Ef84", + "privateKey": "0x1f38c07e88ca6bc2f7790f09a27bfc39f4524cf2a322d003435392cfa0d6dae3" } diff --git a/packages/client-test/package.json b/packages/client-test/package.json index 2ca2fe0..d03a982 100644 --- a/packages/client-test/package.json +++ b/packages/client-test/package.json @@ -13,9 +13,11 @@ "26-ledger:balance:point": "npx ts-node scripts/2-ledger/point.ts", "27-ledger:balance:unpayable": "npx ts-node scripts/2-ledger/unpayable.ts", "28-ledger:exchange:toToken": "npx ts-node scripts/2-ledger/changeToToken.ts", - "31-shop:add": "npx ts-node scripts/3-shop/add.ts", - "31-shop:get": "npx ts-node scripts/3-shop/get.ts", - "32-shop:createId": "npx ts-node scripts/3-shop/createId.ts", + "31-shop:addOne": "npx ts-node scripts/3-shop/addOne.ts", + "34-shop:addTwo": "npx ts-node scripts/3-shop/addTwo.ts", + "32-shop:get": "npx ts-node scripts/3-shop/get.ts", + "33-shop:createId": "npx ts-node scripts/3-shop/createId.ts", + "35-shop:refund": "npx ts-node scripts/3-shop/refund.ts", "41-save:account": "npx ts-node scripts/4-save/account.ts", "42-save:phone": "npx ts-node scripts/4-save/phone.ts", "51-use:new": "npx ts-node scripts/5-use/new.ts", @@ -55,7 +57,7 @@ "@types/mocha": "^10.0.0", "@types/node": "^12.20.43", "@types/urijs": "^1.19.12", - "acc-sdk-client-v2": "~2.7.0", + "acc-sdk-client-v2": "~2.8.0", "assert": "^2.0.0", "axios": "^1.6.7", "beautify": "^0.0.8", diff --git a/packages/client-test/scripts/2-ledger/changeToToken.ts b/packages/client-test/scripts/2-ledger/changeToToken.ts index 43211e4..7af4b52 100644 --- a/packages/client-test/scripts/2-ledger/changeToToken.ts +++ b/packages/client-test/scripts/2-ledger/changeToToken.ts @@ -10,7 +10,7 @@ async function main() { const context: Context = new Context(contextParams); const client = new Client(context); - const amount = BOACoin.make("10_000"); + const amount = BOACoin.make("1_000"); for await (const step of client.ledger.exchangePointToToken(amount.value)) { switch (step.key) { case NormalSteps.PREPARED: diff --git a/packages/client-test/scripts/3-shop/add.ts b/packages/client-test/scripts/3-shop/addOne.ts similarity index 100% rename from packages/client-test/scripts/3-shop/add.ts rename to packages/client-test/scripts/3-shop/addOne.ts diff --git a/packages/client-test/scripts/3-shop/addTwo.ts b/packages/client-test/scripts/3-shop/addTwo.ts new file mode 100644 index 0000000..8a1283a --- /dev/null +++ b/packages/client-test/scripts/3-shop/addTwo.ts @@ -0,0 +1,48 @@ +import { Helper } from "../utils"; +import { Client, Context, ContextBuilder, ContractUtils, NormalSteps } from "acc-sdk-client-v2"; +import fs from "fs"; +import { Wallet } from "ethers"; + +async function main() { + const shopInfos = JSON.parse(fs.readFileSync("./data/shop_infos.json", "utf8")).map( + (m: { shopId: string; privateKey: string; name: string; currency: string }) => { + return { + shopId: m.shopId, + wallet: new Wallet(m.privateKey), + name: m.name, + currency: m.currency, + }; + } + ); + for (const shopInfo of shopInfos) { + const contextParams = ContextBuilder.buildContextParams(Helper.NETWORK, shopInfo.wallet.privateKey); + if (Helper.RELAY_ENDPOINT !== "") contextParams.relayEndpoint = Helper.RELAY_ENDPOINT; + if (Helper.WEB3_ENDPOINT !== "") contextParams.web3Provider = Helper.WEB3_ENDPOINT; + const context: Context = new Context(contextParams); + const client = new Client(context); + console.log("상점 데이타를 추가합니다."); + + for await (const step of client.shop.add(shopInfo.shopId, shopInfo.name, shopInfo.currency)) { + switch (step.key) { + case NormalSteps.PREPARED: + console.log("NormalSteps.PREPARED"); + break; + case NormalSteps.SENT: + console.log("NormalSteps.SENT"); + break; + case NormalSteps.DONE: + console.log("NormalSteps.DONE"); + break; + default: + throw new Error("Unexpected add shop step: " + JSON.stringify(step, null, 2)); + } + } + + await ContractUtils.delay(1000); + } +} + +main().catch((error) => { + console.error(error); + process.exitCode = 1; +}); diff --git a/packages/client-test/scripts/3-shop/get.ts b/packages/client-test/scripts/3-shop/get.ts index 37231de..f8e3a08 100644 --- a/packages/client-test/scripts/3-shop/get.ts +++ b/packages/client-test/scripts/3-shop/get.ts @@ -6,6 +6,9 @@ const beautify = require("beautify"); async function main() { const shopInfo = Helper.loadShopInfo(); + console.log(`shopId: ${shopInfo.shopId}`); + console.log(`wallet.address: ${shopInfo.wallet.address}`); + const contextParams = ContextBuilder.buildContextParams(Helper.NETWORK, shopInfo.wallet.privateKey); if (Helper.RELAY_ENDPOINT !== "") contextParams.relayEndpoint = Helper.RELAY_ENDPOINT; if (Helper.WEB3_ENDPOINT !== "") contextParams.web3Provider = Helper.WEB3_ENDPOINT; diff --git a/packages/client-test/scripts/3-shop/refund.ts b/packages/client-test/scripts/3-shop/refund.ts new file mode 100644 index 0000000..b16ba98 --- /dev/null +++ b/packages/client-test/scripts/3-shop/refund.ts @@ -0,0 +1,60 @@ +import { Helper } from "../utils"; +import { Amount, Client, Context, ContextBuilder, NormalSteps } from "acc-sdk-client-v2"; +import { BOACoin } from "../../src/Amount"; +import { BigNumber } from "@ethersproject/bignumber"; + +const beautify = require("beautify"); + +async function main() { + const shopInfo = Helper.loadShopInfo(); + console.log(`shopId: ${shopInfo.shopId}`); + console.log(`wallet.address: ${shopInfo.wallet.address}`); + + const contextParams = ContextBuilder.buildContextParams(Helper.NETWORK, shopInfo.wallet.privateKey); + if (Helper.RELAY_ENDPOINT !== "") contextParams.relayEndpoint = Helper.RELAY_ENDPOINT; + if (Helper.WEB3_ENDPOINT !== "") contextParams.web3Provider = Helper.WEB3_ENDPOINT; + const context: Context = new Context(contextParams); + const client = new Client(context); + + console.log("상점 정보를 요청합니다."); + const info = await client.shop.getShopInfo(shopInfo.shopId); + const refundable = await client.shop.getRefundableAmount(shopInfo.shopId); + + console.log("처리결과입니다."); + console.log(`shopId: ${info.shopId}`); + console.log(`name: ${info.name}`); + console.log(`currency: ${info.currency}`); + console.log(`account: ${info.account}`); + console.log(`delegator: ${info.delegator}`); + console.log(`providedAmount: ${new BOACoin(info.providedAmount).toDisplayString(true, 2)}`); + console.log(`usedAmount: ${new BOACoin(info.usedAmount).toDisplayString(true, 2)}`); + console.log(`refundedAmount: ${new BOACoin(info.refundedAmount).toDisplayString(true, 2)}`); + console.log(`refundableAmount: ${new BOACoin(refundable.refundableAmount).toDisplayString(true, 2)}`); + + if (refundable.refundableAmount.gt(BigNumber.from(0))) { + for await (const step of client.shop.refund(shopInfo.shopId, refundable.refundableAmount)) { + switch (step.key) { + case NormalSteps.PREPARED: + console.log(`NormalSteps.PREPARED`); + console.log(`step.shopId: ${step.shopId}`); + console.log(`step.signature: ${step.signature}`); + break; + case NormalSteps.SENT: + console.log(`NormalSteps.SENT`); + console.log(`step.txHash: ${step.txHash}`); + break; + case NormalSteps.DONE: + console.log(`NormalSteps.DONE`); + console.log(`step.refundAmount: ${step.refundAmount.toString()}`); + break; + default: + throw new Error("Unexpected open withdrawal step: " + JSON.stringify(step, null, 2)); + } + } + } +} + +main().catch((error) => { + console.error(error); + process.exitCode = 1; +}); diff --git a/packages/client/package.json b/packages/client/package.json index eefa2aa..e09abbb 100644 --- a/packages/client/package.json +++ b/packages/client/package.json @@ -1,6 +1,6 @@ { "name": "acc-sdk-client-v2", - "version": "2.7.0", + "version": "2.8.0", "author": "BOSagora Foundation", "license": "AGPL-3.0-or-later", "main": "dist/index.js", @@ -81,7 +81,7 @@ "@ethersproject/providers": "^5.7.0", "@ethersproject/random": "^5.7.0", "@ethersproject/wallet": "^5.7.0", - "acc-contracts-lib-v2": "~2.5.0", + "acc-contracts-lib-v2": "~2.6.0", "acc-sdk-common-v2": "~2.0.0", "google-libphonenumber": "^3.2.35", "unfetch": "~4.2.0" diff --git a/packages/client/src/client-common/context.ts b/packages/client/src/client-common/context.ts index e88c322..ddc49b5 100644 --- a/packages/client/src/client-common/context.ts +++ b/packages/client/src/client-common/context.ts @@ -3,13 +3,13 @@ import { SupportedNetwork, SupportedNetworkArray } from "./interfaces/common"; import { InvalidAddressError, UnsupportedProtocolError, UnsupportedNetworkError } from "acc-sdk-common-v2"; import { getNetwork } from "../utils/Utilty"; import { LIVE_CONTRACTS } from "./constants"; -export { ContextParams } from "./interfaces/context"; import { isAddress } from "@ethersproject/address"; import { Network } from "@ethersproject/networks"; import { JsonRpcProvider, Networkish } from "@ethersproject/providers"; import { AddressZero } from "@ethersproject/constants"; import { Wallet } from "@ethersproject/wallet"; +export { ContextParams } from "./interfaces/context"; const supportedProtocols = ["https:", "http:"]; // if (typeof process !== "undefined" && process.env?.TESTING) { diff --git a/packages/client/src/utils/ContractUtils.ts b/packages/client/src/utils/ContractUtils.ts index 50eebad..9d29c33 100644 --- a/packages/client/src/utils/ContractUtils.ts +++ b/packages/client/src/utils/ContractUtils.ts @@ -560,6 +560,37 @@ export class ContractUtils { return arrayify(keccak256(encodedResult)); } + public static async getPurchaseSignature( + signer: Signer, + purchase: { + purchaseId: string; + amount: BigNumberish; + loyalty: BigNumberish; + currency: string; + shopId: BytesLike; + account: string; + phone: BytesLike; + sender: string; + }, + chainId: BigNumberish + ): Promise { + const encodedData = defaultAbiCoder.encode( + ["string", "uint256", "uint256", "string", "bytes32", "address", "bytes32", "address", "uint256"], + [ + purchase.purchaseId, + purchase.amount, + purchase.loyalty, + purchase.currency, + purchase.shopId, + purchase.account, + purchase.phone, + purchase.sender, + chainId + ] + ); + return signer.signMessage(arrayify(keccak256(encodedData))); + } + public static async signMessage(signer: Signer, message: Uint8Array): Promise { return signer.signMessage(message); } diff --git a/packages/client/test/history/shop.test.ts b/packages/client/test/history/shop.test.ts index 40e62a9..58a3d33 100644 --- a/packages/client/test/history/shop.test.ts +++ b/packages/client/test/history/shop.test.ts @@ -102,18 +102,28 @@ describe("Integrated test of Shop", () => { const loyaltyAmount = purchaseAmount.mul(5).div(100); const phoneHash = ContractUtils.getPhoneHash(""); const foundation = await accounts[AccountIndex.FOUNDATION].getAddress(); - const purchaseParams = users.map((m) => { - return { - purchaseId: NodeInfo.getPurchaseId(), - amount: purchaseAmount, - loyalty: loyaltyAmount, - currency: "php", - shopId: shops[0].shopId, - account: m.address, - phone: phoneHash, - sender: foundation - }; - }); + + const purchaseParams = await Promise.all( + users.map(async (m) => { + const purchaseItem = { + purchaseId: NodeInfo.getPurchaseId(), + amount: purchaseAmount, + loyalty: loyaltyAmount, + currency: "php", + shopId: shops[0].shopId, + account: m.address, + phone: phoneHash, + sender: foundation, + signature: "" + }; + purchaseItem.signature = await ContractUtils.getPurchaseSignature( + accounts[AccountIndex.FOUNDATION], + purchaseItem, + NodeInfo.getChainId() + ); + return purchaseItem; + }) + ); const purchaseMessage = ContractUtils.getPurchasesMessage(0, purchaseParams, NodeInfo.getChainId()); const signatures = await Promise.all( validatorWallets.map((m) => ContractUtils.signMessage(m, purchaseMessage)) diff --git a/packages/client/test/methods/ledger.test.ts b/packages/client/test/methods/ledger.test.ts index caabb05..1463569 100644 --- a/packages/client/test/methods/ledger.test.ts +++ b/packages/client/test/methods/ledger.test.ts @@ -166,8 +166,14 @@ describe("Ledger", () => { shopId: shopData[purchaseData[0].shopIndex].shopId, account: AddressZero, phone: phoneHash, - sender: await accounts[AccountIndex.FOUNDATION].getAddress() + sender: await accounts[AccountIndex.FOUNDATION].getAddress(), + signature: "" }; + purchaseParams.signature = await ContractUtils.getPurchaseSignature( + accounts[AccountIndex.FOUNDATION], + purchaseParams, + NodeInfo.getChainId() + ); const purchaseMessage = ContractUtils.getPurchasesMessage(0, [purchaseParams], NodeInfo.getChainId()); const signatures = await Promise.all( validatorWallets.map((m) => ContractUtils.signMessage(m, purchaseMessage)) @@ -195,8 +201,14 @@ describe("Ledger", () => { shopId: shopData[purchaseData[0].shopIndex].shopId, account: userAddress, phone: phoneHash, - sender: await accounts[AccountIndex.FOUNDATION].getAddress() + sender: await accounts[AccountIndex.FOUNDATION].getAddress(), + signature: "" }; + purchaseParams.signature = await ContractUtils.getPurchaseSignature( + accounts[AccountIndex.FOUNDATION], + purchaseParams, + NodeInfo.getChainId() + ); const purchaseMessage = ContractUtils.getPurchasesMessage(0, [purchaseParams], NodeInfo.getChainId()); const signatures = await Promise.all( validatorWallets.map((m) => ContractUtils.signMessage(m, purchaseMessage)) diff --git a/packages/client/test/methods/shop_refund.test.ts b/packages/client/test/methods/shop_refund.test.ts index e3ebeba..c27f87b 100644 --- a/packages/client/test/methods/shop_refund.test.ts +++ b/packages/client/test/methods/shop_refund.test.ts @@ -214,8 +214,14 @@ describe("Shop Withdrawal", () => { shopId: shopData[purchase.shopIndex].shopId, account: userAccount, phone: phoneHash, - sender: await accounts[AccountIndex.FOUNDATION].getAddress() + sender: await accounts[AccountIndex.FOUNDATION].getAddress(), + signature: "" }; + purchaseParams.signature = await ContractUtils.getPurchaseSignature( + accounts[AccountIndex.FOUNDATION], + purchaseParams, + NodeInfo.getChainId() + ); const purchaseMessage = ContractUtils.getPurchasesMessage(0, [purchaseParams], NodeInfo.getChainId()); const signatures = await Promise.all( validatorWallets.map((m) => ContractUtils.signMessage(m, purchaseMessage)) diff --git a/yarn.lock b/yarn.lock index 256fcc8..cb66592 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1968,10 +1968,10 @@ abbrev@^2.0.0: resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-2.0.0.tgz#cf59829b8b4f03f89dda2771cb7f3653828c89bf" integrity sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ== -acc-contracts-lib-v2@~2.5.0: - version "2.5.0" - resolved "https://registry.yarnpkg.com/acc-contracts-lib-v2/-/acc-contracts-lib-v2-2.5.0.tgz#2a1cfa376c5915e3a11545fcdc954376bbeec578" - integrity sha512-EUhHCcwAYAsjw4LE2zf2MbtdMiI8Ugk80LoNEg3eJGpnFr5w1BT2nIoAgIKkK1H5znSXk7UVpngjeyv2xkLhKA== +acc-contracts-lib-v2@~2.6.0: + version "2.6.0" + resolved "https://registry.yarnpkg.com/acc-contracts-lib-v2/-/acc-contracts-lib-v2-2.6.0.tgz#a6adb0fb19c7b3fe7120abeef71d492a1ca57540" + integrity sha512-7hJc/wwh+xgCDHXEznbMCxRVaMHTpW7s1bkbgBAkKBdvtH/aiiP39dB3rEUx4I4fG4OnH9JIcMZ9VXmrdgUaaQ== dependencies: ethers "5.7.0"