Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
40 changes: 40 additions & 0 deletions packages/token-app/app/api/wallet/bond/disclosure/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { NextRequest, NextResponse } from "next/server";
import {
getWrappedSdkWithKeyPairForParty,
keyPairFromSeed,
} from "@denotecapital/token-sdk";

export async function GET(request: NextRequest) {
try {
const searchParams = request.nextUrl.searchParams;
const bondInstrumentCid = searchParams.get("bondInstrumentCid");
const adminPartyId = searchParams.get("adminPartyId");

if (!bondInstrumentCid || !adminPartyId) {
return NextResponse.json(
{ error: "Missing bondInstrumentCid or adminPartyId" },
{ status: 400 }
);
}

// TODO: change to not hardcode the custodian seed
const keyPair = keyPairFromSeed("custodian");
const wrappedSdk = await getWrappedSdkWithKeyPairForParty(
adminPartyId,
keyPair
);

const disclosure =
await wrappedSdk.bonds.disclosure.getInstrumentDisclosure(
bondInstrumentCid
);

return NextResponse.json({ disclosure });
} catch (error) {
console.error("Error getting bond disclosure:", error);
return NextResponse.json(
{ error: error instanceof Error ? error.message : "Unknown error" },
{ status: 500 }
);
}
}
70 changes: 70 additions & 0 deletions packages/token-app/app/api/wallet/bond/factory/instrument/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import { NextRequest, NextResponse } from "next/server";
import {
keyPairFromSeed,
getWrappedSdkWithKeyPairForParty,
} from "@denotecapital/token-sdk";

export async function POST(request: NextRequest) {
try {
const {
instrumentId,
notional,
couponRate,
couponFrequency,
maturityDate,
partyId,
seed,
} = await request.json();

if (
!instrumentId ||
notional === undefined ||
couponRate === undefined ||
couponFrequency === undefined ||
!maturityDate ||
!partyId ||
!seed
) {
return NextResponse.json(
{
error: "Missing required fields",
},
{ status: 400 }
);
}

const keyPair = keyPairFromSeed(seed);
const wrappedSdk = await getWrappedSdkWithKeyPairForParty(
partyId,
keyPair
);

const bondFactoryCid = await wrappedSdk.bonds.factory.getOrCreate(
instrumentId
);

const bondInstrumentCid =
await wrappedSdk.bonds.factory.createInstrument(
bondFactoryCid,
instrumentId,
{
depository: partyId,
notional,
couponRate,
couponFrequency,
maturityDate,
}
);

return NextResponse.json({
bondInstrumentCid,
bondFactoryCid,
});
} catch (error) {
console.error("Error creating bond instrument:", error);
return NextResponse.json(
{ error: error instanceof Error ? error.message : "Unknown error" },
{ status: 500 }
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import { NextRequest, NextResponse } from "next/server";
import {
getSdkForParty,
bondInstrumentTemplateId,
ActiveContractResponse,
} from "@denotecapital/token-sdk";

interface BondInstrumentParams {
issuer: string;
instrumentId: string;
maturityDate: string;
couponRate: number;
couponFrequency: number;
}

export async function GET(request: NextRequest) {
try {
const searchParams = request.nextUrl.searchParams;
const custodianPartyId = searchParams.get("custodianPartyId");

if (!custodianPartyId) {
return NextResponse.json(
{ error: "Missing custodianPartyId" },
{ status: 400 }
);
}

const sdk = await getSdkForParty(custodianPartyId);
const ledger = sdk.userLedger!;
const end = await ledger.ledgerEnd();

const activeContracts = (await ledger.activeContracts({
offset: end.offset,
filterByParty: true,
parties: [custodianPartyId],
templateIds: [bondInstrumentTemplateId],
})) as ActiveContractResponse<BondInstrumentParams>[];

const instruments = activeContracts
.map((contract) => {
const jsActive = contract.contractEntry.JsActiveContract;
if (!jsActive) return null;

const createArg = jsActive.createdEvent.createArgument;
const contractId = jsActive.createdEvent.contractId;

if (createArg.issuer !== custodianPartyId) return null;

const instrumentId = createArg.instrumentId;
const nameMatch = instrumentId.match(/^[^#]+#(.+)$/);
const name = nameMatch ? nameMatch[1] : instrumentId;

return {
name,
instrumentId,
custodianPartyId,
bondInstrumentCid: contractId,
maturityDate: createArg.maturityDate,
couponRate: createArg.couponRate,
couponFrequency: createArg.couponFrequency,
};
})
.filter((inst): inst is NonNullable<typeof inst> => inst !== null);

return NextResponse.json({ instruments });
} catch (error) {
console.error("Error getting bond instruments:", error);
return NextResponse.json(
{ error: error instanceof Error ? error.message : "Unknown error" },
{ status: 500 }
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
import { NextRequest, NextResponse } from "next/server";
import {
keyPairFromSeed,
getWrappedSdkWithKeyPairForParty,
getSdkForParty,
bondLifecycleClaimRequestTemplateId,
ActiveContractResponse,
} from "@denotecapital/token-sdk";

export async function GET(request: NextRequest) {
try {
const searchParams = request.nextUrl.searchParams;
const partyId = searchParams.get("partyId");
const issuer = searchParams.get("issuer");

if (!partyId || !issuer) {
return NextResponse.json(
{ error: "Missing partyId or issuer" },
{ status: 400 }
);
}

const sdk = await getSdkForParty(partyId);
const ledger = sdk.userLedger!;
const end = await ledger.ledgerEnd();

const activeContracts = (await ledger.activeContracts({
offset: end.offset,
filterByParty: true,
parties: [partyId],
templateIds: [bondLifecycleClaimRequestTemplateId],
})) as ActiveContractResponse[];

const requests = activeContracts
.map((contract) => {
const jsActive = contract.contractEntry.JsActiveContract;
if (!jsActive) return null;

const createArg = jsActive.createdEvent.createArgument as {
effectCid: string;
bondHoldingCid: string;
holder: string;
issuer: string;
};
const contractId = jsActive.createdEvent.contractId;

if (createArg.issuer !== issuer) return null;

return {
contractId,
effectCid: createArg.effectCid,
bondHoldingCid: createArg.bondHoldingCid,
holder: createArg.holder,
issuer: createArg.issuer,
};
})
.filter((req): req is NonNullable<typeof req> => req !== null);

return NextResponse.json({ requests });
} catch (error) {
console.error("Error getting lifecycle claim requests:", error);
return NextResponse.json(
{ error: error instanceof Error ? error.message : "Unknown error" },
{ status: 500 }
);
}
}

export async function POST(request: NextRequest) {
try {
const {
effectCid,
bondHoldingCid,
bondRulesCid,
bondInstrumentCid,
currencyTransferFactoryCid,
issuerCurrencyHoldingCid,
holder,
issuer,
seed,
disclosure,
} = await request.json();

if (
!effectCid ||
!bondHoldingCid ||
!bondRulesCid ||
!bondInstrumentCid ||
!currencyTransferFactoryCid ||
!issuerCurrencyHoldingCid ||
!holder ||
!issuer ||
!seed
) {
return NextResponse.json(
{ error: "Missing required fields" },
{ status: 400 }
);
}

const keyPair = keyPairFromSeed(seed);
const wrappedSdk = await getWrappedSdkWithKeyPairForParty(
holder,
keyPair
);

await wrappedSdk.bonds.lifecycleClaimRequest.create(
{
effectCid,
bondHoldingCid,
bondRulesCid,
bondInstrumentCid,
currencyTransferFactoryCid,
issuerCurrencyHoldingCid,
holder,
issuer,
},
disclosure ? [disclosure] : undefined
);

return NextResponse.json({ success: true });
} catch (error) {
console.error("Error creating lifecycle claim request:", error);
return NextResponse.json(
{ error: error instanceof Error ? error.message : "Unknown error" },
{ status: 500 }
);
}
}
39 changes: 39 additions & 0 deletions packages/token-app/app/api/wallet/bond/lifecycle/effect/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { NextRequest, NextResponse } from "next/server";
import { getWrappedSdkForParty } from "@denotecapital/token-sdk";

export async function GET(request: NextRequest) {
try {
const searchParams = request.nextUrl.searchParams;
const partyId = searchParams.get("partyId");

if (!partyId) {
return NextResponse.json(
{ error: "Missing partyId" },
{ status: 400 }
);
}

const wrappedSdk = await getWrappedSdkForParty(partyId);

try {
const effects = await wrappedSdk.bonds.lifecycleEffect.getAll(
partyId
);
return NextResponse.json(effects);
} catch (error) {
if (
error instanceof Error &&
error.message.includes("Bond lifecycle effect not found")
) {
return NextResponse.json([], { status: 200 });
}
throw error;
}
} catch (error) {
console.error("Error getting lifecycle effect:", error);
return NextResponse.json(
{ error: error instanceof Error ? error.message : "Unknown error" },
{ status: 500 }
);
}
}
Loading
Loading