From ce92330f17fb251dfd0bfa879e8472736097ca7b Mon Sep 17 00:00:00 2001 From: HardlyDifficult Date: Mon, 16 Jun 2025 09:20:09 -0400 Subject: [PATCH] Revert "POC Canton demo integration" This reverts commit 57497a1b141081af747f551c2aa83b71e4bd09f2. --- .env.example | 7 +- .github/workflows/deploy.dev.yaml | 19 +- .github/workflows/deploy.prod.yaml | 12 - .prettierignore | 3 +- eslint.config.js | 4 +- src/chain-operations/canton/clientConfig.js | 7 - src/chain-operations/canton/constants.js | 9 - .../canton/deployCapTableCanton.js | 29 -- src/chain-operations/canton/lib/client.js | 281 ------------------ src/chain-operations/canton/lib/config.js | 35 --- .../canton/lib/fairmintClient.js | 153 ---------- src/chain-operations/canton/lib/types.js | 58 ---- .../canton/stakeholderControllerCanton.js | 11 - .../canton/stockClassControllerCanton.js | 13 - .../canton/transferControllerCanton.js | 21 -- src/chain-operations/deployCapTable.js | 8 +- src/chain-operations/getContractInstances.js | 6 - src/chain-operations/getProvider.js | 5 - .../issuanceControllerCanton.js | 19 -- src/controllers/stockClassController.js | 8 +- .../transactions/issuanceController.js | 20 +- .../transactions/transferController.js | 6 - src/db/objects/Issuer.js | 1 - src/db/objects/Stakeholder.js | 2 - src/db/objects/StockClass.js | 1 - src/examples/testTransfer.mjs | 3 +- src/routes/issuer.js | 8 +- src/routes/stakeholder/base.js | 22 +- src/routes/stockClass.js | 20 +- src/routes/transactions/base.js | 66 +--- src/utils/chains.js | 10 - src/utils/websocket.ts | 10 - 32 files changed, 25 insertions(+), 852 deletions(-) delete mode 100644 src/chain-operations/canton/clientConfig.js delete mode 100644 src/chain-operations/canton/constants.js delete mode 100644 src/chain-operations/canton/deployCapTableCanton.js delete mode 100644 src/chain-operations/canton/lib/client.js delete mode 100644 src/chain-operations/canton/lib/config.js delete mode 100644 src/chain-operations/canton/lib/fairmintClient.js delete mode 100644 src/chain-operations/canton/lib/types.js delete mode 100644 src/chain-operations/canton/stakeholderControllerCanton.js delete mode 100644 src/chain-operations/canton/stockClassControllerCanton.js delete mode 100644 src/chain-operations/canton/transferControllerCanton.js delete mode 100644 src/chain-operations/issuanceControllerCanton.js diff --git a/.env.example b/.env.example index b24f9fcf..bec8e4db 100644 --- a/.env.example +++ b/.env.example @@ -29,9 +29,4 @@ CONVERTIBLES_FACET= EQUITY_COMPENSATION_FACET= STOCK_PLAN_FACET= WARRANT_FACET= -STAKEHOLDER_NFT_FACET= - -# Canton config -TRANSFER_AGENT_CLIENT_SECRET= -FAIRMINT_PARTY_ID= -FAIRMINT_USER_ID= +STAKEHOLDER_NFT_FACET= \ No newline at end of file diff --git a/.github/workflows/deploy.dev.yaml b/.github/workflows/deploy.dev.yaml index 05f44d69..a65b8b58 100644 --- a/.github/workflows/deploy.dev.yaml +++ b/.github/workflows/deploy.dev.yaml @@ -56,12 +56,6 @@ jobs: SENTRY_DSN: ${{ secrets.SENTRY_DSN }} DATABASE_URL: ${{ secrets.DATABASE_URL }} RPC_URL: ${{ secrets.RPC_URL }} - FAIRMINT_MAINNET_USER_ID: ${{ secrets.FAIRMINT_MAINNET_USER_ID }} - FAIRMINT_MAINNET_PARTY_ID: ${{ secrets.FAIRMINT_MAINNET_PARTY_ID }} - TRANSFER_AGENT_MAINNET_CLIENT_SECRET: ${{ secrets.TRANSFER_AGENT_MAINNET_CLIENT_SECRET }} - FAIRMINT_DEVNET_USER_ID: ${{ secrets.FAIRMINT_DEVNET_USER_ID }} - FAIRMINT_DEVNET_PARTY_ID: ${{ secrets.FAIRMINT_DEVNET_PARTY_ID }} - TRANSFER_AGENT_DEVNET_CLIENT_SECRET: ${{ secrets.TRANSFER_AGENT_DEVNET_CLIENT_SECRET }} run: | # Generate timestamp for deployment @@ -127,25 +121,14 @@ jobs: -e PORT=8080 \ -e PRIVATE_KEY='${PRIVATE_KEY}' \ -e ETHERSCAN_L2_API_KEY='${ETHERSCAN_L2_API_KEY}' \ - -e FAIRMINT_MAINNET_USER_ID='${FAIRMINT_MAINNET_USER_ID}' \ - -e FAIRMINT_MAINNET_PARTY_ID='${FAIRMINT_MAINNET_PARTY_ID}' \ - -e TRANSFER_AGENT_MAINNET_CLIENT_SECRET='${TRANSFER_AGENT_MAINNET_CLIENT_SECRET}' \ - -e FAIRMINT_DEVNET_USER_ID='${FAIRMINT_DEVNET_USER_ID}' \ - -e FAIRMINT_DEVNET_PARTY_ID='${FAIRMINT_DEVNET_PARTY_ID}' \ - -e TRANSFER_AGENT_DEVNET_CLIENT_SECRET='${TRANSFER_AGENT_DEVNET_CLIENT_SECRET}' \ -v '/home/ubuntu/global-bundle.pem:/global-bundle.pem' \ ocp-dev:${DEPLOY_TIME} && \ # Wait for container to be healthy - echo "Printing logs before health check:" - docker logs \$CONTAINER_NAME || true - - wait_for_health "\$CONTAINER_NAME" + wait_for_health "\$CONTAINER_NAME" && \ if [ \$? -eq 0 ]; then handle_container_switch "\$CONTAINER_NAME" "${DEPLOY_TIME}" "dev" else - echo "Container failed health check. Printing logs:" - docker logs \$CONTAINER_NAME || true handle_failed_deployment "\$CONTAINER_NAME" "${DEPLOY_TIME}" "dev" fi " diff --git a/.github/workflows/deploy.prod.yaml b/.github/workflows/deploy.prod.yaml index ff2590a7..acf215c3 100644 --- a/.github/workflows/deploy.prod.yaml +++ b/.github/workflows/deploy.prod.yaml @@ -55,12 +55,6 @@ jobs: SENTRY_DSN: ${{ secrets.SENTRY_DSN }} DATABASE_URL: ${{ secrets.DATABASE_URL }} RPC_URL: ${{ secrets.RPC_URL }} - FAIRMINT_MAINNET_USER_ID: ${{ secrets.FAIRMINT_MAINNET_USER_ID }} - FAIRMINT_MAINNET_PARTY_ID: ${{ secrets.FAIRMINT_MAINNET_PARTY_ID }} - TRANSFER_AGENT_MAINNET_CLIENT_SECRET: ${{ secrets.TRANSFER_AGENT_MAINNET_CLIENT_SECRET }} - FAIRMINT_DEVNET_USER_ID: ${{ secrets.FAIRMINT_DEVNET_USER_ID }} - FAIRMINT_DEVNET_PARTY_ID: ${{ secrets.FAIRMINT_DEVNET_PARTY_ID }} - TRANSFER_AGENT_DEVNET_CLIENT_SECRET: ${{ secrets.TRANSFER_AGENT_DEVNET_CLIENT_SECRET }} run: | # Generate timestamp for deployment @@ -126,12 +120,6 @@ jobs: -e PORT=8080 \ -e PRIVATE_KEY='${PRIVATE_KEY}' \ -e ETHERSCAN_L2_API_KEY='${ETHERSCAN_L2_API_KEY}' \ - -e FAIRMINT_MAINNET_USER_ID='${FAIRMINT_MAINNET_USER_ID}' \ - -e FAIRMINT_MAINNET_PARTY_ID='${FAIRMINT_MAINNET_PARTY_ID}' \ - -e TRANSFER_AGENT_MAINNET_CLIENT_SECRET='${TRANSFER_AGENT_MAINNET_CLIENT_SECRET}' \ - -e FAIRMINT_DEVNET_USER_ID='${FAIRMINT_DEVNET_USER_ID}' \ - -e FAIRMINT_DEVNET_PARTY_ID='${FAIRMINT_DEVNET_PARTY_ID}' \ - -e TRANSFER_AGENT_DEVNET_CLIENT_SECRET='${TRANSFER_AGENT_DEVNET_CLIENT_SECRET}' \ -v '/home/ubuntu/global-bundle.pem:/global-bundle.pem' \ ocp-prod:${DEPLOY_TIME} && \ diff --git a/.prettierignore b/.prettierignore index 09a9e083..d1086455 100644 --- a/.prettierignore +++ b/.prettierignore @@ -2,7 +2,6 @@ /node_modules /chain/out .history -src/chain-operations/canton/lib # Build output /dist @@ -15,4 +14,4 @@ src/chain-operations/canton/lib .env* # Logs -*.log +*.log \ No newline at end of file diff --git a/eslint.config.js b/eslint.config.js index 3ed31e68..901bbf4c 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -7,7 +7,7 @@ import importPlugin from "eslint-plugin-import"; export default [ { files: ["**/*.{js,ts,mjs,mts}"], - ignores: ["node_modules/**", "eslint.config.js", "src/chain-operations/canton/lib/**"], + ignores: ["node_modules/**", "eslint.config.js"], languageOptions: { ecmaVersion: 2022, sourceType: "module", @@ -39,7 +39,7 @@ export default [ }, { files: ["**/*.ts"], - ignores: ["node_modules/**", "src/chain-operations/canton/lib/**"], + ignores: ["node_modules/**"], languageOptions: { parser: tsparser, parserOptions: { diff --git a/src/chain-operations/canton/clientConfig.js b/src/chain-operations/canton/clientConfig.js deleted file mode 100644 index a5eab7fd..00000000 --- a/src/chain-operations/canton/clientConfig.js +++ /dev/null @@ -1,7 +0,0 @@ -import { TransferAgentConfig } from "./lib/config"; -import { FairmintClient } from "./lib/fairmintClient"; - -const config = new TransferAgentConfig(true); -const client = new FairmintClient(config); - -export { config, client }; diff --git a/src/chain-operations/canton/constants.js b/src/chain-operations/canton/constants.js deleted file mode 100644 index 90a5789e..00000000 --- a/src/chain-operations/canton/constants.js +++ /dev/null @@ -1,9 +0,0 @@ -// TODO https://github.com/ChainAgnostic/CAIPs/blob/master/CAIPs/caip-7.md -// Once changed from chainId: number to CAIP-7: string, use `canton:mainnet` and `canton:devnet` - -export const CANTON_MAINNET_CHAIN_ID = 6765788401; -export const CANTON_DEVNET_CHAIN_ID = 6765788402; - -export function isCantonChainId(chainId) { - return chainId == CANTON_MAINNET_CHAIN_ID || chainId == CANTON_DEVNET_CHAIN_ID; -} diff --git a/src/chain-operations/canton/deployCapTableCanton.js b/src/chain-operations/canton/deployCapTableCanton.js deleted file mode 100644 index cc15f101..00000000 --- a/src/chain-operations/canton/deployCapTableCanton.js +++ /dev/null @@ -1,29 +0,0 @@ -import { client } from "./clientConfig"; - -// eslint-disable-next-line no-unused-vars -export async function deployCapTableCanton(issuerId, initial_shares_authorized, chainId, issuer) { - console.log("🗽 | Deploying cap table on Canton..."); - - // Create FairmintAdminService [One time] - const { contractId } = await client.createFairmintAdminService(); - - // Create new party for issuer [Once per issuer] - const { partyId: issuerPartyId } = await client.createParty(issuerId); - - // Authorize issuer [Once per issuer] - const authorizationContractId = await client.authorizeIssuer(contractId, issuerPartyId); - - // Issuer accepts authorization [Once per issuer] - const issuerContractId = await client.acceptIssuerAuthorization( - authorizationContractId, - issuer.legal_name, - initial_shares_authorized, - issuerPartyId - ); - - return { - partyId: issuerPartyId, - // deployId: updateId, // TODO - address: issuerContractId, - }; -} diff --git a/src/chain-operations/canton/lib/client.js b/src/chain-operations/canton/lib/client.js deleted file mode 100644 index eb1c062b..00000000 --- a/src/chain-operations/canton/lib/client.js +++ /dev/null @@ -1,281 +0,0 @@ -import axios from 'axios'; -import { TransferAgentConfig } from './config.js'; -import * as fs from 'fs'; -import * as path from 'path'; - -export class TransferAgentClient { - constructor(config) { - this.config = config; - this.bearerToken = null; - this.sequenceNumber = 1; - this.axiosInstance = axios.create(); - this.logDir = path.join(process.cwd(), 'logs'); - if (!fs.existsSync(this.logDir)) { - fs.mkdirSync(this.logDir, { recursive: true }); - } - } - - getFairmintPartyId() { - return this.config.fairmintPartyId; - } - - async logRequestResponse(url, request, response) { - const timestamp = new Date().toISOString().replace(/[:.]/g, '-'); - const logFile = path.join(this.logDir, `request-${timestamp}.json`); - - const logData = { - timestamp, - url, - request, - response - }; - - fs.writeFileSync(logFile, JSON.stringify(logData, null, 2)); - } - - async makePostRequest(url, data, headers) { - try { - const response = await this.axiosInstance.post(url, data, { headers }); - await this.logRequestResponse(url, data, response.data); - return response.data; - } catch (error) { - if (axios.isAxiosError(error)) { - const errorData = error.response?.data; - - // Check for security-sensitive error - if (errorData?.cause === "A security-sensitive error has been received") { - // Clear the bearer token to force re-authentication - this.bearerToken = null; - - // Get new headers with fresh authentication - const newHeaders = await this.getHeaders(); - - // Retry the request once with new authentication - try { - const retryResponse = await this.axiosInstance.post(url, data, { headers: newHeaders }); - await this.logRequestResponse(url, data, retryResponse.data); - return retryResponse.data; - } catch (retryError) { - // If retry fails, log and throw the original error - await this.logRequestResponse(url, data, { - error: axios.isAxiosError(retryError) ? retryError.response?.data || retryError.message : retryError - }); - throw error; - } - } - - await this.logRequestResponse(url, data, { - error: errorData || error.message - }); - throw error; - } - throw error; - } - } - - async authenticate() { - const formData = new URLSearchParams(); - formData.append('grant_type', 'client_credentials'); - formData.append('client_id', this.config.clientId); - formData.append('client_secret', this.config.clientSecret); - formData.append('audience', this.config.audience); - formData.append('scope', this.config.scope); - - try { - const response = await this.makePostRequest( - this.config.authUrl, - formData.toString(), - { - 'Content-Type': 'application/x-www-form-urlencoded', - } - ); - - this.bearerToken = response.access_token; - return this.bearerToken; - } catch (error) { - if (axios.isAxiosError(error)) { - throw new Error(`Authentication failed: ${error.response?.data || error.message}`); - } - throw error; - } - } - - async getHeaders() { - if (!this.bearerToken) { - await this.authenticate(); - } - - return { - 'Authorization': `Bearer ${this.bearerToken}`, - 'Content-Type': 'application/json', - }; - } - - async createCommand(params) { - const command = { - commands: [{ - CreateCommand: { - templateId: params.templateId, - createArguments: params.createArguments, - }, - }], - commandId: this.sequenceNumber.toString(), - actAs: params.actAs, - }; - - this.sequenceNumber++; - - try { - const headers = await this.getHeaders(); - const response = await this.makePostRequest( - `${this.config.ledgerUrl}/commands/submit-and-wait-for-transaction-tree`, - command, - headers - ); - - return { - contractId: response.transactionTree.eventsById['#' + response.transactionTree.updateId + ':0'].CreatedTreeEvent.value.contractId, - updateId: response.transactionTree.updateId - }; - } catch (error) { - if (axios.isAxiosError(error)) { - const errorData = error.response?.data ? JSON.stringify(error.response.data, null, 2) : error.message; - throw new Error(`Failed to create command: ${errorData}`); - } - throw error; - } - } - - async exerciseCommand(params) { - const command = { - commands: [{ - ExerciseCommand: { - templateId: params.templateId, - contractId: params.contractId, - choice: params.choice, - choiceArgument: params.choiceArgument - } - }], - commandId: this.sequenceNumber.toString(), - actAs: params.actAs - }; - - this.sequenceNumber++; - - try { - const headers = await this.getHeaders(); - const response = await this.makePostRequest( - `${this.config.ledgerUrl}/commands/submit-and-wait-for-transaction-tree`, - command, - headers - ); - return response; - } catch (error) { - if (axios.isAxiosError(error)) { - const errorData = error.response?.data ? JSON.stringify(error.response.data, null, 2) : error.message; - throw new Error(`Failed to exercise command: ${errorData}`); - } - throw error; - } - } - - async createParty(partyIdHint) { - try { - const headers = await this.getHeaders(); - const response = await this.makePostRequest( - `${this.config.ledgerUrl}/parties`, - { - partyIdHint: `FM:${partyIdHint}`, - displayName: partyIdHint, - identityProviderId: "" - }, - headers - ); - - const partyId = response.partyDetails.party; - - // Set user rights for the newly created party - await this.setUserRights(partyId); - - return {partyId, isNewParty: true}; - } catch (error) { - if (axios.isAxiosError(error)) { - const errorData = error.response?.data; - // Check if this is a "party already exists" error - if (errorData?.cause?.includes('Party already exists')) { - // Look up the party ID from the ledger - const parties = await this.getParties(); - const existingParty = parties.partyDetails.find(p => p.party.startsWith(`FM:${partyIdHint}`)); - if (existingParty) { - // Set user rights for the newly created party - await this.setUserRights(existingParty.party); - - return { partyId: existingParty.party, isNewParty: false }; - } - } - const errorMessage = errorData ? JSON.stringify(errorData, null, 2) : error.message; - throw new Error(`Failed to create party: ${errorMessage}`); - } - throw error; - } - } - - async setUserRights(partyId) { - const headers = await this.getHeaders(); - await this.makePostRequest( - `${this.config.ledgerUrl}/users/${this.config.fairmintUserId}/rights`, - { - userId: this.config.fairmintUserId, - rights: [ - { - kind: { - "CanActAs": { - value: { - party: partyId - } - } - }, - }, - { - kind: { - "CanReadAs": { - value: { - party: partyId - } - } - }, - } - ], - identityProviderId: "" - }, - headers - ); - } - - async getParties() { - const headers = await this.getHeaders(); - return await this.makePostRequest( - `${this.config.ledgerUrl}/parties`, - {}, - headers - ); - } - - async getEventsByContractId(contractId) { - const headers = await this.getHeaders(); - return await this.makePostRequest( - `${this.config.ledgerUrl}/events/contract/${contractId}`, - {}, - headers - ); - } - - async getTransactionTreeByOffset(offset) { - const headers = await this.getHeaders(); - return await this.makePostRequest( - `${this.config.ledgerUrl}/transactions/tree/${offset}`, - {}, - headers - ); - } -} \ No newline at end of file diff --git a/src/chain-operations/canton/lib/config.js b/src/chain-operations/canton/lib/config.js deleted file mode 100644 index 5b7bdabb..00000000 --- a/src/chain-operations/canton/lib/config.js +++ /dev/null @@ -1,35 +0,0 @@ -import dotenv from 'dotenv'; - -// Load environment variables -dotenv.config(); - -export class TransferAgentConfig { - constructor(isMainnet = false) { - this.authUrl = 'https://auth.transfer-agent.xyz/application/o/token/'; - this.scope = 'daml_ledger_apia'; - - if (isMainnet) { - this.ledgerUrl = 'https://ledger-api.validator.transfer-agent.xyz/v2'; - this.clientId = this.audience = 'validator-mainnet-m2m'; - this.clientSecret = process.env.TRANSFER_AGENT_MAINNET_CLIENT_SECRET || ''; - this.fairmintPartyId = process.env.FAIRMINT_MAINNET_PARTY_ID || ''; - this.fairmintUserId = process.env.FAIRMINT_MAINNET_USER_ID || ''; - } else { - this.ledgerUrl = 'https://ledger-api.validator.devnet.transfer-agent.xyz/v2'; - this.clientId = this.audience = 'validator-devnet-m2m'; - this.clientSecret = process.env.TRANSFER_AGENT_DEVNET_CLIENT_SECRET || ''; - this.fairmintPartyId = process.env.FAIRMINT_DEVNET_PARTY_ID || ''; - this.fairmintUserId = process.env.FAIRMINT_DEVNET_USER_ID || ''; - } - - if (!this.clientSecret) { - throw new Error(`${isMainnet ? 'TRANSFER_AGENT_MAINNET_CLIENT_SECRET' : 'TRANSFER_AGENT_DEVNET_CLIENT_SECRET'} environment variable is not set`); - } - if (!this.fairmintPartyId) { - throw new Error(`${isMainnet ? 'FAIRMINT_MAINNET_PARTY_ID' : 'FAIRMINT_DEVNET_PARTY_ID'} environment variable is not set`); - } - if (!this.fairmintUserId) { - throw new Error(`${isMainnet ? 'FAIRMINT_MAINNET_USER_ID' : 'FAIRMINT_DEVNET_USER_ID'} environment variable is not set`); - } - } -} \ No newline at end of file diff --git a/src/chain-operations/canton/lib/fairmintClient.js b/src/chain-operations/canton/lib/fairmintClient.js deleted file mode 100644 index 66e03fa2..00000000 --- a/src/chain-operations/canton/lib/fairmintClient.js +++ /dev/null @@ -1,153 +0,0 @@ -import { TransferAgentClient } from './client.js'; -import { TransferAgentConfig } from './config.js'; - -// Application specific constants -const TEMPLATES = { - FAIRMINT_ADMIN_SERVICE: '#OpenCapTable-v00:FairmintAdminService:FairmintAdminService' -}; - -export class FairmintClient { - constructor(config) { - this.client = new TransferAgentClient(config); - } - - async createFairmintAdminService() { - const response = await this.client.createCommand({ - templateId: TEMPLATES.FAIRMINT_ADMIN_SERVICE, - createArguments: { - fairmint: this.client.getFairmintPartyId(), - }, - actAs: [this.client.getFairmintPartyId()], - }); - console.debug(`Created FairmintAdminService with contract ID: ${response.contractId}`); - return response; - } - - async authorizeIssuer(contractId, issuerPartyId) { - const response = await this.client.exerciseCommand({ - templateId: TEMPLATES.FAIRMINT_ADMIN_SERVICE, - contractId, - choice: 'AuthorizeIssuer', - choiceArgument: { - issuer: issuerPartyId - }, - actAs: [this.client.getFairmintPartyId()] - }); - - // Extract the IssuerAuthorization contract ID from the response - const authorizationContractId = response.transactionTree.eventsById['#' + response.transactionTree.updateId + ':0'].ExercisedTreeEvent.exerciseResult; - console.debug(`Successfully authorized issuer with contract ID: ${authorizationContractId}`); - return authorizationContractId; - } - - async createParty(partyIdHint) { - const response = await this.client.createParty(partyIdHint); - console.debug(`${response.isNewParty ? 'Created' : 'Reused'} party for ${partyIdHint} with ID: ${response.partyId}`); - return response; - } - - async acceptIssuerAuthorization(authorizationContractId, name, authorizedShares, issuerPartyId) { - const response = await this.client.exerciseCommand({ - templateId: '#OpenCapTable-v00:IssuerAuthorization:IssuerAuthorization', - contractId: authorizationContractId, - choice: 'CreateIssuer', - choiceArgument: { - name, - authorizedShares: authorizedShares.toString() - }, - actAs: [issuerPartyId] - }); - - // Extract the Issuer contract ID from the response - const issuerContractId = response.transactionTree.eventsById['#' + response.transactionTree.updateId + ':1'].CreatedTreeEvent.value.contractId; - console.debug(`Successfully created issuer with contract ID: ${issuerContractId}`); - return issuerContractId; - } - - async createStockClass(issuerContractId, stockClassType, shares, issuerPartyId) { - const response = await this.client.exerciseCommand({ - templateId: '#OpenCapTable-v00:Issuer:Issuer', - contractId: issuerContractId, - choice: 'CreateStockClass', - choiceArgument: { - stockClassType, - shares: shares.toString() - }, - actAs: [issuerPartyId] - }); - - // Extract both the StockClass and updated Issuer contract IDs from the response - const stockClassContractId = response.transactionTree.eventsById['#' + response.transactionTree.updateId + ':2'].CreatedTreeEvent.value.contractId; - const updatedIssuerContractId = response.transactionTree.eventsById['#' + response.transactionTree.updateId + ':1'].CreatedTreeEvent.value.contractId; - console.debug(`Created stock class with contract ID: ${stockClassContractId}`); - return { stockClassContractId, updatedIssuerContractId }; - } - - async proposeIssueStock(stockClassContractId, recipientPartyId, quantity, issuerPartyId) { - const response = await this.client.exerciseCommand({ - templateId: '#OpenCapTable-v00:StockClass:StockClass', - contractId: stockClassContractId, - choice: 'ProposeIssueStock', - choiceArgument: { - recipient: recipientPartyId, - quantity: quantity.toString() - }, - actAs: [issuerPartyId] - }); - - // Extract both the IssueStockClassProposal and updated StockClass contract IDs from the response - const proposalContractId = response.transactionTree.eventsById['#' + response.transactionTree.updateId + ':1'].CreatedTreeEvent.value.contractId; - const updatedStockClassContractId = response.transactionTree.eventsById['#' + response.transactionTree.updateId + ':2'].CreatedTreeEvent.value.contractId; - console.debug(`Proposed stock issuance to ${recipientPartyId} with proposal ID: ${proposalContractId}`); - return { proposalContractId, updatedStockClassContractId }; - } - - async acceptIssueStockProposal(proposalContractId, recipientPartyId) { - const response = await this.client.exerciseCommand({ - templateId: '#OpenCapTable-v00:StockClass:IssueStockClassProposal', - contractId: proposalContractId, - choice: 'AcceptIssueStockProposal', - choiceArgument: {}, - actAs: [recipientPartyId] - }); - - // Extract the StockPosition contract ID from the response - const stockPositionContractId = response.transactionTree.eventsById['#' + response.transactionTree.updateId + ':1'].CreatedTreeEvent.value.contractId; - console.debug(`${recipientPartyId} accepted stock issuance and received position with ID: ${stockPositionContractId}`); - return stockPositionContractId; - } - - async proposeTransfer(stockPositionContractId, recipientPartyId, quantity, ownerPartyId) { - const response = await this.client.exerciseCommand({ - templateId: '#OpenCapTable-v00:StockPosition:StockPosition', - contractId: stockPositionContractId, - choice: 'ProposeTransfer', - choiceArgument: { - recipient: recipientPartyId, - quantityToTransfer: quantity.toString() - }, - actAs: [ownerPartyId] - }); - - // Extract both the TransferProposal and updated StockPosition contract IDs from the response - const transferProposalContractId = response.transactionTree.eventsById['#' + response.transactionTree.updateId + ':1'].CreatedTreeEvent.value.contractId; - const updatedStockPositionContractId = response.transactionTree.eventsById['#' + response.transactionTree.updateId + ':2'].CreatedTreeEvent.value.contractId; - console.debug(`${ownerPartyId} proposed transfer to ${recipientPartyId} with proposal ID: ${transferProposalContractId}`); - return { transferProposalContractId, updatedStockPositionContractId }; - } - - async acceptTransfer(transferProposalContractId, recipientPartyId) { - const response = await this.client.exerciseCommand({ - templateId: '#OpenCapTable-v00:StockPosition:StockTransferProposal', - contractId: transferProposalContractId, - choice: 'AcceptTransfer', - choiceArgument: {}, - actAs: [recipientPartyId] - }); - - // Extract the new StockPosition contract ID from the response - const stockPositionContractId = response.transactionTree.eventsById['#' + response.transactionTree.updateId + ':1'].CreatedTreeEvent.value.contractId; - console.debug(`${recipientPartyId} accepted transfer and received position with ID: ${stockPositionContractId}`); - return stockPositionContractId; - } -} \ No newline at end of file diff --git a/src/chain-operations/canton/lib/types.js b/src/chain-operations/canton/lib/types.js deleted file mode 100644 index 418508ff..00000000 --- a/src/chain-operations/canton/lib/types.js +++ /dev/null @@ -1,58 +0,0 @@ -// Note: This file is kept for documentation purposes only -// The types are not used in JavaScript but are documented here for reference - -/** - * @typedef {Object} AuthResponse - * @property {string} access_token - */ - -/** - * @typedef {Object} CreateCommand - * @property {Object} CreateCommand - * @property {string} CreateCommand.templateId - * @property {Object} CreateCommand.createArguments - */ - -/** - * @typedef {Object} ExerciseCommand - * @property {Object} ExerciseCommand - * @property {string} ExerciseCommand.templateId - * @property {string} ExerciseCommand.contractId - * @property {string} ExerciseCommand.choice - * @property {Object} ExerciseCommand.choiceArgument - */ - -/** - * @typedef {CreateCommand|ExerciseCommand} Command - */ - -/** - * @typedef {Object} CommandRequest - * @property {Command[]} commands - * @property {string} commandId - * @property {string[]} actAs - */ - -/** - * @typedef {Object} CreatedTreeEvent - * @property {Object} CreatedTreeEvent - * @property {Object} CreatedTreeEvent.value - * @property {string} CreatedTreeEvent.value.contractId - */ - -/** - * @typedef {Object} TransactionTree - * @property {string} updateId - * @property {Object.} eventsById - */ - -/** - * @typedef {Object} CommandResponse - * @property {TransactionTree} transactionTree - */ - -/** - * @typedef {Object} CreateContractResponse - * @property {string} contractId - * @property {string} updateId - */ \ No newline at end of file diff --git a/src/chain-operations/canton/stakeholderControllerCanton.js b/src/chain-operations/canton/stakeholderControllerCanton.js deleted file mode 100644 index 57c13893..00000000 --- a/src/chain-operations/canton/stakeholderControllerCanton.js +++ /dev/null @@ -1,11 +0,0 @@ -import { client } from "./clientConfig"; - -// eslint-disable-next-line no-unused-vars -export const convertAndReflectStakeholderOnchainCanton = async (stakeholderId) => { - console.log("🗽 | Converting and reflecting stakeholder onchain Canton..."); - - // Create new party for stakeholder [Once per stakeholder] - const { partyId } = await client.createParty(stakeholderId); - - return { partyId, updateId: null /* TODO */ }; -}; diff --git a/src/chain-operations/canton/stockClassControllerCanton.js b/src/chain-operations/canton/stockClassControllerCanton.js deleted file mode 100644 index c0af06fc..00000000 --- a/src/chain-operations/canton/stockClassControllerCanton.js +++ /dev/null @@ -1,13 +0,0 @@ -import { client } from "./clientConfig"; - -export const convertAndReflectStockClassOnchainCanton = async (stockClass, issuer) => { - const classType = stockClass.class_type === "COMMON" ? "Common" : "Unknown"; - const { stockClassContractId, updatedIssuerContractId } = await client.createStockClass( - issuer.deployed_to, - classType, - stockClass.initial_shares_authorized, - issuer.party_id - ); - - return { stockClassContractId, updatedIssuerContractId }; -}; diff --git a/src/chain-operations/canton/transferControllerCanton.js b/src/chain-operations/canton/transferControllerCanton.js deleted file mode 100644 index 3a9d73d4..00000000 --- a/src/chain-operations/canton/transferControllerCanton.js +++ /dev/null @@ -1,21 +0,0 @@ -import { client } from "./clientConfig"; - -export const convertAndCreateTransferStockOnchainCanton = async (contract, transfer) => { - const { transferorPartyId, transferorStockPositionContractId, transfereePartyId, quantity } = transfer; - - // Transferer proposes share transfer to transferee - const { transferProposalContractId, updatedStockPositionContractId } = await client.proposeTransfer( - transferorStockPositionContractId, - transfereePartyId, - quantity, - transferorPartyId - ); - - // Transferee accepts the transfer proposal and receives shares - const transfereeStockPositionContractId = await client.acceptTransfer(transferProposalContractId, transfereePartyId); - - return { - transferorUpdatedStockPositionContractId: updatedStockPositionContractId, - transfereeStockPositionContractId: transfereeStockPositionContractId, - }; -}; diff --git a/src/chain-operations/deployCapTable.js b/src/chain-operations/deployCapTable.js index 7deb48a4..3ebdb5c3 100644 --- a/src/chain-operations/deployCapTable.js +++ b/src/chain-operations/deployCapTable.js @@ -7,8 +7,6 @@ import getProvider from "./getProvider.js"; import Factory, { FACTORY_VERSION } from "../db/objects/Factory.js"; import assert from "node:assert"; import { decodeError } from "../utils/errorDecoder"; -import { isCantonChainId } from "./canton/constants.js"; -import { deployCapTableCanton } from "./canton/deployCapTableCanton.js"; setupEnv(); @@ -22,11 +20,7 @@ export const getWallet = async (chainId) => { return new ethers.Wallet(WALLET_PRIVATE_KEY, provider); }; -async function deployCapTable(issuerId, initial_shares_authorized, chainId, issuer) { - if (isCantonChainId(chainId)) { - return deployCapTableCanton(issuerId, initial_shares_authorized, chainId, issuer); - } - +async function deployCapTable(issuerId, initial_shares_authorized, chainId) { // Get provider for specified chain const wallet = await getWallet(chainId); console.log("🗽 | Wallet address: ", wallet.address); diff --git a/src/chain-operations/getContractInstances.js b/src/chain-operations/getContractInstances.js index 606b32c8..a4afc68a 100644 --- a/src/chain-operations/getContractInstances.js +++ b/src/chain-operations/getContractInstances.js @@ -11,16 +11,10 @@ import WARRANT_FACET from "../../chain/out/WarrantFacet.sol/WarrantFacet.json"; import EQUITY_COMPENSATION_FACET from "../../chain/out/EquityCompensationFacet.sol/EquityCompensationFacet.json"; import STOCK_PLAN_FACET from "../../chain/out/StockPlanFacet.sol/StockPlanFacet.json"; import STAKEHOLDER_NFT_FACET from "../../chain/out/StakeholderNFTFacet.sol/StakeholderNFTFacet.json"; -import { isCantonChainId } from "./canton/constants.js"; setupEnv(); export const getContractInstance = (address, chainId) => { - if (isCantonChainId(chainId)) { - console.log(`Canton chain ${chainId} contract instance is not supported yet`); - return null; - } - const WALLET_PRIVATE_KEY = process.env.PRIVATE_KEY; // Create a combined ABI from all facets const combinedABI = [ diff --git a/src/chain-operations/getProvider.js b/src/chain-operations/getProvider.js index a1916042..e361ca80 100644 --- a/src/chain-operations/getProvider.js +++ b/src/chain-operations/getProvider.js @@ -1,12 +1,7 @@ import { ethers } from "ethers"; import { getChainConfig } from "../utils/chains.js"; -import { isCantonChainId } from "./canton/constants.js"; function getProvider(chainId) { - if (isCantonChainId(chainId)) { - throw new Error("Canton is not supported yet"); - } - const chainConfig = getChainConfig(chainId); if (!chainConfig) { throw new Error(`Unsupported chain ID: ${chainId}`); diff --git a/src/chain-operations/issuanceControllerCanton.js b/src/chain-operations/issuanceControllerCanton.js deleted file mode 100644 index fbe5f7a8..00000000 --- a/src/chain-operations/issuanceControllerCanton.js +++ /dev/null @@ -1,19 +0,0 @@ -import { client } from "./canton/clientConfig"; - -export const convertAndCreateIssuanceStockOnchainCanton = async ({ stockClassContractId, stakeholderPartyId, quantity, issuerPartyId }) => { - // Issuer proposes quantity shares to stakeholder - const { proposalContractId, updatedStockClassContractId } = await client.proposeIssueStock( - stockClassContractId, - stakeholderPartyId, - quantity, - issuerPartyId - ); - - // Stakeholder accepts the proposal and receives shares - const stakeholderStockPositionContractId = await client.acceptIssueStockProposal(proposalContractId, stakeholderPartyId); - - return { - stakeholderStockPositionContractId, - updatedStockClassContractId, - }; -}; diff --git a/src/controllers/stockClassController.js b/src/controllers/stockClassController.js index a30b52f5..2d14c004 100644 --- a/src/controllers/stockClassController.js +++ b/src/controllers/stockClassController.js @@ -1,15 +1,9 @@ import { toScaledBigNumber } from "../utils/convertToFixedPointDecimals.js"; import { convertUUIDToBytes16 } from "../utils/convertUUID.js"; import { decodeError } from "../utils/errorDecoder.js"; -import { isCantonChainId } from "../chain-operations/canton/constants.js"; -import { convertAndReflectStockClassOnchainCanton } from "../chain-operations/canton/stockClassControllerCanton.js"; /// @dev: controller handles conversion from OCF type to Onchain types and creates the stock class. -export const convertAndReflectStockClassOnchain = async (contract, stockClass, issuer) => { - if (isCantonChainId(issuer.chain_id)) { - return convertAndReflectStockClassOnchainCanton(stockClass, issuer); - } - +export const convertAndReflectStockClassOnchain = async (contract, stockClass) => { try { const stockClassIdBytes16 = convertUUIDToBytes16(stockClass.id); const scaledSharePrice = toScaledBigNumber(stockClass.price_per_share.amount); diff --git a/src/controllers/transactions/issuanceController.js b/src/controllers/transactions/issuanceController.js index f63fd198..ca1e5a41 100644 --- a/src/controllers/transactions/issuanceController.js +++ b/src/controllers/transactions/issuanceController.js @@ -1,30 +1,12 @@ import { convertUUIDToBytes16 } from "../../utils/convertUUID.js"; import { toScaledBigNumber } from "../../utils/convertToFixedPointDecimals.js"; import { decodeError } from "../../utils/errorDecoder.js"; -import { isCantonChainId } from "../../chain-operations/canton/constants.js"; -import { convertAndCreateIssuanceStockOnchainCanton } from "../../chain-operations/issuanceControllerCanton.js"; // Stock Issuance export const convertAndCreateIssuanceStockOnchain = async ( contract, - { - id, - chain_id, - security_id, - stock_class_id, - stakeholder_id, - quantity, - share_price, - custom_id = "", - stockClassContractId, - stakeholderPartyId, - issuerPartyId, - } + { id, security_id, stock_class_id, stakeholder_id, quantity, share_price, custom_id = "" } ) => { - if (isCantonChainId(chain_id)) { - return convertAndCreateIssuanceStockOnchainCanton({ stockClassContractId, stakeholderPartyId, quantity, issuerPartyId }); - } - try { const tx = await contract.issueStock({ id: convertUUIDToBytes16(id), diff --git a/src/controllers/transactions/transferController.js b/src/controllers/transactions/transferController.js index 18c6a450..99d56305 100644 --- a/src/controllers/transactions/transferController.js +++ b/src/controllers/transactions/transferController.js @@ -1,14 +1,8 @@ import { convertUUIDToBytes16 } from "../../utils/convertUUID.js"; import { toScaledBigNumber } from "../../utils/convertToFixedPointDecimals.js"; import { decodeError } from "../../utils/errorDecoder.js"; -import { isCantonChainId } from "../../chain-operations/canton/constants.js"; -import { convertAndCreateTransferStockOnchainCanton } from "../../chain-operations/canton/transferControllerCanton.js"; export const convertAndCreateTransferStockOnchain = async (contract, transfer) => { - if (isCantonChainId(transfer.chain_id)) { - return convertAndCreateTransferStockOnchainCanton(contract, transfer); - } - try { const { quantity, transferorId, transfereeId, stockClassId, sharePrice } = transfer; diff --git a/src/db/objects/Issuer.js b/src/db/objects/Issuer.js index f1e259e2..7a2f5f93 100644 --- a/src/db/objects/Issuer.js +++ b/src/db/objects/Issuer.js @@ -23,7 +23,6 @@ const IssuerSchema = new mongoose.Schema( chain_id: { type: Number, required: true }, tx_hash: { type: String, default: null }, factory: { ref: "Factory", type: String }, - party_id: { type: String, default: null }, }, { timestamps: true } ); diff --git a/src/db/objects/Stakeholder.js b/src/db/objects/Stakeholder.js index ff4d845a..01cd9f52 100644 --- a/src/db/objects/Stakeholder.js +++ b/src/db/objects/Stakeholder.js @@ -20,8 +20,6 @@ const StakeholderSchema = new mongoose.Schema( addresses: [{}], tax_ids: [{}], tx_hash: { type: String, default: null }, - party_id: { type: String, default: null }, - stock_position_contract_id: { type: String, default: null }, }, { timestamps: true } ); diff --git a/src/db/objects/StockClass.js b/src/db/objects/StockClass.js index a4bafffe..2ce98201 100644 --- a/src/db/objects/StockClass.js +++ b/src/db/objects/StockClass.js @@ -25,7 +25,6 @@ const StockClassSchema = new mongoose.Schema( }, is_onchain_synced: { type: Boolean, default: false }, tx_hash: { type: String, default: null }, - contract_id: { type: String, default: null }, }, { timestamps: true } ); diff --git a/src/examples/testTransfer.mjs b/src/examples/testTransfer.mjs index c38a727f..d0c391aa 100644 --- a/src/examples/testTransfer.mjs +++ b/src/examples/testTransfer.mjs @@ -2,7 +2,6 @@ import { issuer, stakeholder1, stakeholder2, stockClass, stockIssuance, stockTra import axios from "axios"; import sleep from "../utils/sleep.js"; import { v4 as uuid } from "uuid"; -import { CANTON_DEVNET_CHAIN_ID } from "../chain-operations/canton/constants.js"; const main = async () => { try { @@ -15,7 +14,7 @@ const main = async () => { // 1. Create issuer console.log("⏳ Creating issuer..."); issuer.id = issuerId; - issuer.chain_id = CANTON_DEVNET_CHAIN_ID; + issuer.chain_id = 31337; const issuerResponse = await axios.post("http://localhost:8080/issuer/create", issuer); console.log("✅ Issuer created:", issuerResponse.data); diff --git a/src/routes/issuer.js b/src/routes/issuer.js index 1442c43d..d798983f 100644 --- a/src/routes/issuer.js +++ b/src/routes/issuer.js @@ -64,19 +64,13 @@ issuer.post("/create", async (req, res) => { const issuerIdBytes16 = convertUUIDToBytes16(incomingIssuerToValidate.id); console.log("💾 | Issuer id in bytes16 ", issuerIdBytes16); - const { address, deployHash, partyId } = await deployCapTable( - issuerIdBytes16, - incomingIssuerToValidate.initial_shares_authorized, - chain_id, - incomingIssuerToValidate - ); + const { address, deployHash } = await deployCapTable(issuerIdBytes16, incomingIssuerToValidate.initial_shares_authorized, chain_id); const incomingIssuerForDB = { ...incomingIssuerToValidate, deployed_to: address, tx_hash: deployHash, chain_id, - party_id: partyId, }; const issuer = await createIssuer(incomingIssuerForDB); diff --git a/src/routes/stakeholder/base.js b/src/routes/stakeholder/base.js index e4fff84c..6a643b2b 100644 --- a/src/routes/stakeholder/base.js +++ b/src/routes/stakeholder/base.js @@ -12,8 +12,6 @@ import { createStakeholder } from "../../db/operations/create.js"; import { readIssuerById, readStakeholderById, getAllStakeholdersByIssuerId } from "../../db/operations/read.js"; import validateInputAgainstOCF from "../../utils/validateInputAgainstSchema.js"; import Stakeholder from "../../db/objects/Stakeholder.js"; -import { isCantonChainId } from "../../chain-operations/canton/constants.js"; -import { convertAndReflectStakeholderOnchainCanton } from "../../chain-operations/canton/stakeholderControllerCanton.js"; const router = Router(); @@ -111,25 +109,15 @@ router.post("/create", async (req, res) => { } // Save offchain - const stakeholder = await createStakeholder({ ...incomingStakeholderForDB }); - console.log("✅ | Stakeholder created offchain:", stakeholder); + const stakeholder = await createStakeholder(incomingStakeholderForDB); // Save onchain - let tx_hash; - let partyId = null; - if (!isCantonChainId(issuer.chain_id)) { - ({ hash: tx_hash } = await convertAndReflectStakeholderOnchain(contract, incomingStakeholderForDB.id)); - await Stakeholder.findByIdAndUpdate(stakeholder._id, { tx_hash }); - } else { - ({ updateId: tx_hash, partyId } = await convertAndReflectStakeholderOnchainCanton(incomingStakeholderForDB.id)); - } + const receipt = await convertAndReflectStakeholderOnchain(contract, incomingStakeholderForDB.id); + await Stakeholder.findByIdAndUpdate(stakeholder._id, { tx_hash: receipt.hash }); - if (partyId) { - await Stakeholder.findByIdAndUpdate(stakeholder._id, { party_id: partyId }); - console.log("✅ | Stakeholder updated offchain with new partyId:", partyId); - } + console.log("✅ | Stakeholder created offchain:", stakeholder); - res.status(200).send({ stakeholder: { ...stakeholder.toObject(), tx_hash, partyId } }); + res.status(200).send({ stakeholder: { ...stakeholder.toObject(), tx_hash: receipt.hash } }); } catch (error) { console.error(error); res.status(500).send(`${error}`); diff --git a/src/routes/stockClass.js b/src/routes/stockClass.js index 45ce1d2a..aefc1824 100644 --- a/src/routes/stockClass.js +++ b/src/routes/stockClass.js @@ -6,7 +6,6 @@ import { createStockClass } from "../db/operations/create.js"; import { readIssuerById, readStockClassById } from "../db/operations/read.js"; import validateInputAgainstOCF from "../utils/validateInputAgainstSchema.js"; import Stockclass from "../db/objects/StockClass"; -import Issuer from "../db/objects/Issuer"; const stockClass = Router(); @@ -46,9 +45,6 @@ stockClass.post("/create", async (req, res) => { try { const issuer = await readIssuerById(issuerId); - if (!issuer) { - return res.status(404).send({ message: "Issuer not found" }); - } // OCF doesn't allow extra fields in their validation const incomingStockClassToValidate = { @@ -72,20 +68,12 @@ stockClass.post("/create", async (req, res) => { const stockClass = await createStockClass(incomingStockClassForDB); // Save Onchain - const { - hash: tx_hash, - stockClassContractId, - updatedIssuerContractId, - } = await convertAndReflectStockClassOnchain(contract, incomingStockClassForDB, issuer); - await Stockclass.findByIdAndUpdate(stockClass._id, { tx_hash, contract_id: stockClassContractId ?? null }); - console.log("✅ | Stock Class created offchain:", stockClass); + const receipt = await convertAndReflectStockClassOnchain(contract, incomingStockClassForDB); + await Stockclass.findByIdAndUpdate(stockClass._id, { tx_hash: receipt.hash }); - if (updatedIssuerContractId) { - await Issuer.findByIdAndUpdate(issuerId, { deployed_to: updatedIssuerContractId }); - console.log("✅ | Issuer updated offchain:", issuer); - } + console.log("✅ | Stock Class created offchain:", stockClass); - res.status(200).send({ stockClass: { ...stockClass.toObject(), tx_hash: tx_hash ?? null } }); + res.status(200).send({ stockClass: { ...stockClass.toObject(), tx_hash: receipt.hash } }); } catch (error) { console.error(error); res.status(500).send(`${error}`); diff --git a/src/routes/transactions/base.js b/src/routes/transactions/base.js index 99fcce65..ec439ae0 100644 --- a/src/routes/transactions/base.js +++ b/src/routes/transactions/base.js @@ -44,7 +44,6 @@ import { readStockPlanById, readIssuerById, readStockClassById, - readStakeholderById, readConvertibleIssuanceBySecurityId, readStockIssuanceBySecurityId, readEquityCompensationIssuanceBySecurityId, @@ -57,7 +56,6 @@ import get from "lodash/get"; import { convertAndCreateEquityCompensationExerciseOnchain } from "../../controllers/transactions/exerciseController"; import { adjustStockPlanPoolOnchain } from "../../controllers/stockPlanController"; import StockIssuance from "../../db/objects/transactions/issuance/StockIssuance.js"; -import StockClass from "../../db/objects/StockClass.js"; import ConvertibleIssuance from "../../db/objects/transactions/issuance/ConvertibleIssuance.js"; import EquityCompensationIssuance from "../../db/objects/transactions/issuance/EquityCompensationIssuance.js"; import WarrantIssuance from "../../db/objects/transactions/issuance/WarrantIssuance.js"; @@ -65,7 +63,6 @@ import StockClassAuthorizedSharesAdjustment from "../../db/objects/transactions/ import StockPlanPoolAdjustment from "../../db/objects/transactions/adjustment/StockPlanPoolAdjustment.js"; import { EquityCompensationExercise } from "../../db/objects/transactions/exercise"; import { StockCancellation } from "../../db/objects/transactions/cancellation"; -import Stakeholder from "../../db/objects/Stakeholder"; const transactions = Router(); @@ -74,7 +71,7 @@ transactions.post("/issuance/stock", async (req, res) => { const { issuerId, data } = req.body; try { - const issuer = await readIssuerById(issuerId); + await readIssuerById(issuerId); const incomingStockIssuance = { id: uuid(), // for OCF Validation security_id: uuid(), // for OCF Validation @@ -93,20 +90,8 @@ transactions.post("/issuance/stock", async (req, res) => { } const stockIssuance = await createStockIssuance({ ...incomingStockIssuance, issuer: issuerId }); - const stockClass = await readStockClassById(incomingStockIssuance.stock_class_id); - if (!stockClass?._id) { - return res.status(404).send({ message: "Stock class not found" }); - } - const stakeholder = await readStakeholderById(incomingStockIssuance.stakeholder_id); - if (!stakeholder?._id) { - return res.status(404).send({ message: "Stakeholder not found" }); - } - const { - hash: tx_hash, - stakeholderStockPositionContractId, - updatedStockClassContractId, - } = await convertAndCreateIssuanceStockOnchain(contract, { + const receipt = await convertAndCreateIssuanceStockOnchain(contract, { security_id: incomingStockIssuance.security_id, stock_class_id: incomingStockIssuance.stock_class_id, stakeholder_id: incomingStockIssuance.stakeholder_id, @@ -115,27 +100,12 @@ transactions.post("/issuance/stock", async (req, res) => { stock_legend_ids_mapping: incomingStockIssuance.stock_legend_ids_mapping, custom_id: incomingStockIssuance.custom_id || "", id: incomingStockIssuance.id, - - chain_id: issuer.chain_id, - stockClassContractId: stockClass.contract_id, - issuerPartyId: issuer.party_id, - stakeholderPartyId: stakeholder.party_id, }); // Update the stock issuance with tx_hash - await StockIssuance.findByIdAndUpdate(stockIssuance._id, { tx_hash: tx_hash ?? null }); + await StockIssuance.findByIdAndUpdate(stockIssuance._id, { tx_hash: receipt.hash }); - // Canton only updates: - if (stakeholderStockPositionContractId) { - await Stakeholder.findByIdAndUpdate(stakeholder._id, { stock_position_contract_id: stakeholderStockPositionContractId }); - console.log("✅ | Stakeholder updated offchain with new Stock Position Contract ID", stakeholderStockPositionContractId); - } - if (updatedStockClassContractId) { - await StockClass.findByIdAndUpdate(stockClass._id, { contract_id: updatedStockClassContractId }); - console.log("✅ | Stock Class updated offchain with new Contract ID", updatedStockClassContractId); - } - - res.status(200).send({ stockIssuance: { ...stockIssuance.toObject(), tx_hash: tx_hash ?? null } }); + res.status(200).send({ stockIssuance: { ...stockIssuance.toObject(), tx_hash: receipt.hash } }); } catch (error) { console.error(error); res.status(500).send(`${error}`); @@ -147,34 +117,10 @@ transactions.post("/transfer/stock", async (req, res) => { const { issuerId, data } = req.body; try { - const issuer = await readIssuerById(issuerId); - const transferor = await readStakeholderById(data.transferorId); - if (!transferor) { - return res.status(404).send({ message: "Transferor not found" }); - } - const transferee = await readStakeholderById(data.transfereeId); - if (!transferee) { - return res.status(404).send({ message: "Transferee not found" }); - } + await readIssuerById(issuerId); // @dev: Transfer Validation is not possible through schema because it validates that the transfer has occurred,at this stage it has not yet. - const { transferorUpdatedStockPositionContractId, transfereeStockPositionContractId } = await convertAndCreateTransferStockOnchain(contract, { - ...data, - chain_id: issuer.chain_id, - transferorPartyId: transferor.party_id, - transferorStockPositionContractId: transferor.stock_position_contract_id, - transfereePartyId: transferee.party_id, - }); - - // Canton only updates: - if (transferorUpdatedStockPositionContractId) { - await Stakeholder.findByIdAndUpdate(transferor._id, { stock_position_contract_id: transferorUpdatedStockPositionContractId }); - console.log("✅ | Transferor updated offchain with new Stock Position Contract ID", transferorUpdatedStockPositionContractId); - } - if (transfereeStockPositionContractId) { - await Stakeholder.findByIdAndUpdate(transferee._id, { stock_position_contract_id: transfereeStockPositionContractId }); - console.log("✅ | Transferee updated offchain with new Stock Position Contract ID", transfereeStockPositionContractId); - } + await convertAndCreateTransferStockOnchain(contract, data); res.status(200).send("success"); } catch (error) { diff --git a/src/utils/chains.js b/src/utils/chains.js index 9595838e..abca1b0b 100644 --- a/src/utils/chains.js +++ b/src/utils/chains.js @@ -1,5 +1,3 @@ -import { CANTON_DEVNET_CHAIN_ID, CANTON_MAINNET_CHAIN_ID } from "../chain-operations/canton/constants.js"; - // Chain configuration for supported networks export const SUPPORTED_CHAINS = { 8453: { @@ -20,14 +18,6 @@ export const SUPPORTED_CHAINS = { rpcUrl: "http://localhost:8545", wsUrl: "ws://localhost:8545", }, - [CANTON_DEVNET_CHAIN_ID]: { - // Canton - name: "Canton", - }, - [CANTON_MAINNET_CHAIN_ID]: { - // Canton - name: "Canton Mainnet", - }, }; // Get chain configuration diff --git a/src/utils/websocket.ts b/src/utils/websocket.ts index bcf47723..9640b025 100644 --- a/src/utils/websocket.ts +++ b/src/utils/websocket.ts @@ -7,7 +7,6 @@ import { handleStockPlan, txMapper, txTypes } from "../chain-operations/transact import { handleStakeholder, handleStockClass } from "../chain-operations/transactionHandlers"; import Issuer from "../db/objects/Issuer"; import { TxCreated, StakeholderCreated, StockClassCreated, StockPlanCreated } from "../chain-operations/topics"; -import { isCantonChainId } from "../chain-operations/canton/constants"; const TOPICS = { TxCreated, StakeholderCreated, StockClassCreated, StockPlanCreated }; @@ -28,11 +27,6 @@ const getChainProvider = (chainId: string): ethers.Provider => { // Function to add new addresses to watch for a specific chain export const addAddressesToWatch = async (chainId: string, addresses: string | string[]) => { - if (isCantonChainId(chainId)) { - console.log(`Canton chain ${chainId} address watching is not supported yet`); - return; - } - const addressArray = Array.isArray(addresses) ? addresses : [addresses]; if (!watchedAddressesByChain.has(chainId)) { @@ -48,10 +42,6 @@ export const addAddressesToWatch = async (chainId: string, addresses: string | s // Function to setup a single chain listener const setupChainListener = async (chainId: string, addresses: string[]) => { - if (isCantonChainId(chainId)) { - console.log(`Canton chain ${chainId} chain listener is not supported yet`); - return; - } const provider = getChainProvider(chainId); if (addresses.length > 0) {