Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP feat: detokenize amount on warehouse #29

Closed
wants to merge 20 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
6535110
feat: detokenize amount on warehouse
danielstefanequilobe Nov 4, 2022
922a9e4
feat: detokenize amount on warehouse
danielstefanequilobe Nov 4, 2022
394d907
feat: detokenize amound on warehouse
danielstefanequilobe Nov 4, 2022
b8c3e9f
feat: detokenize amount on warehouse
danielstefanequilobe Nov 4, 2022
ff3d028
feat: detokenize amount on warehouse
danielstefanequilobe Nov 4, 2022
7da85bb
feat: detokenize amount on warehouse
danielstefanequilobe Nov 4, 2022
a91fa0e
feat: detokenize amount on warehouse
danielstefanequilobe Nov 4, 2022
0829974
Merge branch 'main' into feat-detokanize-amount-on-warehouse
danielstefanequilobe Nov 7, 2022
68c972e
Merge branch 'main' into feat-detokanize-amount-on-warehouse
danielstefanequilobe Nov 11, 2022
8e491f3
Merge branch 'main' into feat-detokanize-amount-on-warehouse
danielstefanequilobe Nov 17, 2022
474d43b
ci: update ARM variable for apt
TheLastCicada Jul 17, 2023
a77c38d
chore: version bump
TheLastCicada Jul 17, 2023
958cd25
Merge pull request #133 from Chia-Network/apt-arm-variable-update
TheLastCicada Jul 17, 2023
f7dfd5f
chore: migrate to node18
MichaelTaylor3D Jul 25, 2023
866d9cc
ci: replace deprecaited command
MichaelTaylor3D Jul 25, 2023
6ff6222
Merge pull request #135 from Chia-Network/dev/node18
MichaelTaylor3D Jul 31, 2023
d44e9a8
chore: bump to 1.2.0
MichaelTaylor3D Jul 31, 2023
3115315
Update to digicert HSM windows code signing
cmmarslender Aug 15, 2023
05e734b
Merge pull request #142 from Chia-Network/update-windows-signing
TheLastCicada Aug 15, 2023
330b4a5
fix: merge conflicts
MichaelTaylor3D Aug 24, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 10 additions & 15 deletions .github/workflows/build.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,13 @@ jobs:
- name: Checkout Code
uses: actions/checkout@v3

- name: Setup Node 16.x
- name: Setup Node 18.16
uses: actions/setup-node@v3
with:
node-version: '16.13'
node-version: '18.16'

- name: Ignore Husky
run: npm set-script prepare ""
run: npm pkg delete scripts.prepare
if: matrix.runs-on != 'windows-2019'

- name: npm install
Expand All @@ -72,19 +72,14 @@ jobs:
run: chmod +x dist/climate-tokenization*

# Windows Code Signing
- name: Decode code signing cert into an encrypted file
if: matrix.runs-on == 'windows-2019'
uses: kitek/[email protected]
with:
encoded-value: ${{ secrets.WIN_CODE_SIGN_CERT }}
destination-file: .\win_code_sign_cert.pfx

- name: Sign windows artifacts
if: matrix.runs-on == 'windows-2019'
uses: chia-network/actions/sign/windows@main
uses: chia-network/actions/digicert/windows-sign@main
with:
certificate_path: .\win_code_sign_cert.pfx
certificate_password: ${{ secrets.WIN_CODE_SIGN_PASSWORD }}
sm_api_key: ${{ secrets.SM_API_KEY }}
sm_client_cert_file_b64: ${{ secrets.SM_CLIENT_CERT_FILE_B64 }}
sm_client_cert_password: ${{ secrets.SM_CLIENT_CERT_PASSWORD }}
sm_code_signing_cert_sha1_hash: ${{ secrets.SM_CODE_SIGNING_CERT_SHA1_HASH }}
file: ${{ github.workspace }}/dist/climate-tokenization-engine.exe

# Mac .pkg build + sign
Expand Down Expand Up @@ -270,5 +265,5 @@ jobs:

- name: Trigger apt repo update
run: |
curl -s -XPOST -H "Authorization: Bearer ${{ secrets.GLUE_ACCESS_TOKEN }}" --data '{"climate_tokenization_repo":"${{ steps.repo-name.outputs.REPO_NAME }}","application_name":"climate-tokenization-engine","release_version":"${{ steps.tag-name.outputs.TAGNAME }}","add_debian_version":"true","arm64_available":"true"}' ${{ secrets.GLUE_API_URL }}/api/v1/climate-tokenization/${{ github.sha }}/start
curl -s -XPOST -H "Authorization: Bearer ${{ secrets.GLUE_ACCESS_TOKEN }}" --data '{"climate_tokenization_repo":"${{ steps.repo-name.outputs.REPO_NAME }}","application_name":"climate-tokenization-engine","release_version":"${{ steps.tag-name.outputs.TAGNAME }}","add_debian_version":"true","arm64_available":"true"}' ${{ secrets.GLUE_API_URL }}/api/v1/climate-tokenization/${{ github.sha }}/success/deploy
curl -s -XPOST -H "Authorization: Bearer ${{ secrets.GLUE_ACCESS_TOKEN }}" --data '{"climate_tokenization_repo":"${{ steps.repo-name.outputs.REPO_NAME }}","application_name":"climate-tokenization-engine","release_version":"${{ steps.tag-name.outputs.TAGNAME }}","add_debian_version":"true","arm64":"available"}' ${{ secrets.GLUE_API_URL }}/api/v1/climate-tokenization/${{ github.sha }}/start
curl -s -XPOST -H "Authorization: Bearer ${{ secrets.GLUE_ACCESS_TOKEN }}" --data '{"climate_tokenization_repo":"${{ steps.repo-name.outputs.REPO_NAME }}","application_name":"climate-tokenization-engine","release_version":"${{ steps.tag-name.outputs.TAGNAME }}","add_debian_version":"true","arm64":"available"}' ${{ secrets.GLUE_API_URL }}/api/v1/climate-tokenization/${{ github.sha }}/success/deploy
16 changes: 8 additions & 8 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "climate-tokenization-engine",
"version": "1.1.4",
"version": "1.2.0",
"bin": "./server.js",
"description": "",
"main": "proxy.js",
Expand Down
118 changes: 54 additions & 64 deletions server.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ const { createProxyMiddleware } = require("http-proxy-middleware");

const validator = joiExpress.createValidator({ passError: true });

const warehouseApi = require("./warehouse");
const { updateConfig, getConfig } = require("./utils/config-loader");
const { connectToOrgSchema, tokenizeUnitSchema } = require("./validations.js");
const { getStoreIds } = require("./datalayer.js");
Expand All @@ -22,6 +23,14 @@ const app = express();
const port = 31311;
let CONFIG = getConfig();

const addCadtApiKeyHeader = (headers = {}) => {
if (CONFIG.CADT_API_KEY) {
headers["x-api-key"] = CONFIG.CADT_API_KEY;
}

return headers;
};

const headerKeys = Object.freeze({
ORG_UID: "x-org-uid",
});
Expand Down Expand Up @@ -245,6 +254,7 @@ const updateUnitMarketplaceIdentifierWithAssetId = async (

const unitToBeUpdated = unitToBeUpdatedResponse.body;
unitToBeUpdated.marketplaceIdentifier = asset_id;
await warehouseApi.updateUnit(unitToBeUpdated);

delete unitToBeUpdated?.issuance?.orgUid;
delete unitToBeUpdated.issuanceId;
Expand Down Expand Up @@ -444,57 +454,6 @@ const sendParseDetokRequest = async (detokString) => {
}
};

const getOrgMetaData = async (orgUid) => {
try {
const url = `${CONFIG.CADT_API_SERVER_HOST}/v1/organizations/metadata?orgUid=${orgUid}`;
const response = await superagent.get(url).set(addCadtApiKeyHeader());

return response.body;
} catch (error) {
logger.error(`Could not get org meta data: ${error.message}`);
throw new Error(`Could not get org meta data: ${error}`);
}
};

const getProjectByWarehouseProjectId = async (warehouseProjectId) => {
try {
const url = `${CONFIG.CADT_API_SERVER_HOST}/v1/projects?projectIds=${warehouseProjectId}`;
const response = await superagent.get(url).set(addCadtApiKeyHeader());

return response.body[0];
} catch (error) {
logger.error(`Could not get corresponding project data: ${error.message}`);
throw new Error(`Could not get corresponding project data: ${error}`);
}
};

const getTokenizedUnitByAssetId = async (assetId) => {
try {
const url = `${CONFIG.CADT_API_SERVER_HOST}/v1/units?marketplaceIdentifiers=${assetId}`;
const response = await superagent.get(url).set(addCadtApiKeyHeader());

return response.body;
} catch (error) {
logger.error(`Could not get tokenized unit by asset id. ${error.message}`);
throw new Error(`Could not get tokenized unit by asset id. ${error}`);
}
};

/**
* If an API key for the Climate Action Data Trust (CADT) is set in the server configuration, add the API key value to
* the headers that are sent with a request to the CADT. This function mutates the header object passed in and returns
* the object for convenience. If no headers are passed to this function, a new dictionary containing just the CADT API
* key (or an empty dictionary, if the API key is not set) is created and returned. If CADT_API_KEY is not set in the
* configuration, the header object will not be modified.
*/
const addCadtApiKeyHeader = (headers = {}) => {
if (CONFIG.CADT_API_KEY) {
headers["x-api-key"] = CONFIG.CADT_API_KEY;
}

return headers;
};

app.post("/parse-detok-file", async (req, res) => {
try {
let detokString = req.body.detokString;
Expand All @@ -512,25 +471,17 @@ app.post("/parse-detok-file", async (req, res) => {
}

const assetId = parseDetokResponse?.token?.asset_id;
const unitToBeDetokenizedResponse = await getTokenizedUnitByAssetId(
assetId
);
let unitToBeDetokenized = JSON.parse(unitToBeDetokenizedResponse);
if (unitToBeDetokenized.length) {
unitToBeDetokenized = unitToBeDetokenized[0];
}

if (parseDetokResponse?.payment?.amount) {
unitToBeDetokenized.unitCount = parseDetokResponse?.payment?.amount;
}
const unitsToBeDetokenizedResponse =
await warehouseApi.getTokenizedUnitsByAssetId(assetId);
const unitToBeDetokenized = unitsToBeDetokenizedResponse[0];

const project = await getProjectByWarehouseProjectId(
const project = await warehouseApi.getProjectByWarehouseProjectId(
unitToBeDetokenized?.issuance?.warehouseProjectId
);

const orgUid = unitToBeDetokenized?.orgUid;

const orgMetaData = await getOrgMetaData(orgUid);
const orgMetaData = await warehouseApi.getOrgMetaData(orgUid);
const assetIdOrgMetaData = orgMetaData[`meta_${assetId}`];
const parsedAssetIdOrgMetaData = JSON.parse(assetIdOrgMetaData);

Expand All @@ -540,13 +491,16 @@ app.post("/parse-detok-file", async (req, res) => {
project_id: project.projectId,
vintage_year: unitToBeDetokenized?.vintageYear,
sequence_num: 0,
//index: orgMetaData,
index: parsedAssetIdOrgMetaData?.index,
// public_key: orgMetaData,
public_key: parsedAssetIdOrgMetaData?.public_key,
asset_id: assetId,
warehouse_project_id: project.warehouseProjectId,
},
content: detokString,
unit: unitToBeDetokenized,
amount: parseDetokResponse?.payment?.amount,
};

res.send(responseObject);
Expand All @@ -564,9 +518,45 @@ app.post("/confirm-detokanization", async (req, res) => {
const confirmDetokanizationBody = _.cloneDeep(req.body);

const assetId = confirmDetokanizationBody?.token?.asset_id;

const warehouseUnitsToDetokenizeFrom =
await warehouseApi.getTokenizedUnitsByAssetId(assetId);
warehouseUnitsToDetokenizeFrom.sort((a, b) => b.unitCount - a.unitCount);

let amountLeftToBeDetokenized = confirmDetokanizationBody?.amount;
for (
let x = 0;
x < warehouseUnitsToDetokenizeFrom.length &&
amountLeftToBeDetokenized > 0;
x++
) {
const unit = warehouseUnitsToDetokenizeFrom[x];
const { unitCount } = unit;

if (unitCount <= amountLeftToBeDetokenized) {
await warehouseApi.detokenizeUnit(unit);
amountLeftToBeDetokenized -= unitCount;
} else {
await warehouseApi.splitDetokenizeUnit(unit, amountLeftToBeDetokenized);
amountLeftToBeDetokenized = 0;
}
}

if (amountLeftToBeDetokenized > 0) {
await warehouseApi.deleteStagingData();
throw new Error(
"Could not detokenize warehouseunits. Total unitCount lower than needed detokanziation amount."
);
}

await warehouseApi.commitStagingData();

if (confirmDetokanizationBody.unit) {
delete confirmDetokanizationBody.unit;
}
if (confirmDetokanizationBody.amount) {
delete confirmDetokanizationBody.amount;
}

const confirmDetokanizationResponse = await request({
method: "put",
Expand Down
Binary file removed token-engine.zip
Binary file not shown.
Loading
Loading