Skip to content

Commit

Permalink
feat: 🎸 allow optional venues for 7.0 chains
Browse files Browse the repository at this point in the history
allow no venue id to be passed when creating instructions. None of the
assets can have venue filtering enabled
  • Loading branch information
polymath-eric authored and sansan committed Oct 4, 2024
1 parent 1f8caf7 commit 8750fe9
Show file tree
Hide file tree
Showing 4 changed files with 119 additions and 20 deletions.
2 changes: 1 addition & 1 deletion src/api/entities/Venue/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ export class Venue extends Entity<UniqueIdentifiers, string> {
settlement.details(venueId),
]);

const { creator, venueType: type } = venueInfo.unwrap();
const { creator, venueType: type } = venueInfo.unwrapOrDefault();

return {
owner: new Identity({ did: identityIdToString(creator) }, context),
Expand Down
74 changes: 74 additions & 0 deletions src/api/procedures/__tests__/addInstruction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -712,6 +712,63 @@ describe('addInstruction procedure', () => {
).rejects.toThrow(expectedError);
});

it('should throw an error if no venue is specified and an asset has filtering enabled', () => {
const proc = procedureMockUtils.getInstance<Params, Instruction[], Storage>(mockContext, {
portfoliosToAffirm: [],
});

const legOne = {
from,
to,
amount,
asset: entityMockUtils.getFungibleAssetInstance({
assetId: asset,
getVenueFilteringDetails: {
isEnabled: true,
allowedVenues: [entityMockUtils.getVenueInstance({ id: new BigNumber(1) })],
},
}),
};

const expectedError = new PolymeshError({
code: ErrorCode.UnmetPrerequisite,
message: 'One or more of the assets must be traded at a venue',
});

return expect(
prepareAddInstruction.call(proc, {
instructions: [{ legs: [legOne] }],
})
).rejects.toThrow(expectedError);
});

it('should throw an error if no venue and the chain is still on v6', () => {
mockContext.isV6 = true;
const proc = procedureMockUtils.getInstance<Params, Instruction[], Storage>(mockContext, {
portfoliosToAffirm: [],
});

const legOne = {
from,
to,
amount,
asset: entityMockUtils.getFungibleAssetInstance({
assetId: asset,
}),
};

const expectedError = new PolymeshError({
code: ErrorCode.General,
message: 'A venue id must be provided on v6 chains',
});

return expect(
prepareAddInstruction.call(proc, {
instructions: [{ legs: [legOne] }],
})
).rejects.toThrow(expectedError);
});

it('should throw an error if the end block is in the past', async () => {
dsMockUtils.configureMocks({ contextOptions: { latestBlock: new BigNumber(1000) } });

Expand Down Expand Up @@ -1115,6 +1172,23 @@ describe('addInstruction procedure', () => {
transactions: [TxTags.settlement.AddInstructionWithMediators],
},
});

result = await boundFunc({
instructions: [
{
mediators: [mediatorDid],
legs: [{ from: fromPortfolio, to: toPortfolio, amount, asset: '0x1111' }],
},
],
});

expect(result).toEqual({
permissions: {
assets: [],
portfolios: [],
transactions: [TxTags.settlement.AddInstructionWithMediators],
},
});
});
});

Expand Down
61 changes: 43 additions & 18 deletions src/api/procedures/addInstruction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ import {
* @hidden
*/
export type Params = AddInstructionsParams & {
venueId: BigNumber;
venueId?: BigNumber;
};

/**
Expand All @@ -89,7 +89,7 @@ export interface Storage {
* @hidden
*/
type InternalAddAndAffirmInstructionParams = [
u64,
u64 | null,
PolymeshPrimitivesSettlementSettlementType,
u64 | null,
u64 | null,
Expand All @@ -103,7 +103,7 @@ type InternalAddAndAffirmInstructionParams = [
* @hidden
*/
type InternalAddInstructionParams = [
u64,
u64 | null,
PolymeshPrimitivesSettlementSettlementType,
u64 | null,
u64 | null,
Expand Down Expand Up @@ -227,7 +227,7 @@ async function separateLegs(
*/
async function assertVenueFiltering(
instructions: AddInstructionParams[],
venueId: BigNumber,
venueId: BigNumber | undefined,
context: Context
): Promise<void> {
const assetPromises = instructions.flatMap(instruction => {
Expand Down Expand Up @@ -260,15 +260,27 @@ async function assertVenueFiltering(
undefined
);

if (permittedVenues !== undefined && !permittedVenues.some(({ id }) => id.eq(venueId))) {
throw new PolymeshError({
code: ErrorCode.UnmetPrerequisite,
message: 'One or more assets are not allowed to be traded at this venue',
data: {
possibleVenues: permittedVenues.map(venue => venue.id.toString()),
venueId: venueId.toString(),
},
});
if (permittedVenues !== undefined) {
if (venueId === undefined) {
throw new PolymeshError({
code: ErrorCode.ValidationError,
message: 'One or more of the assets must be traded at a venue',
data: {
possibleVenues: permittedVenues.map(venue => venue.id.toString()),
},
});
}

if (!permittedVenues.some(({ id }) => id.eq(venueId))) {
throw new PolymeshError({
code: ErrorCode.UnmetPrerequisite,
message: 'One or more assets are not allowed to be traded at this venue',
data: {
possibleVenues: permittedVenues.map(venue => venue.id.toString()),
venueId: venueId.toString(),
},
});
}
}
}

Expand All @@ -279,7 +291,7 @@ async function getTxArgsAndErrors(
instructions: AddInstructionParams[],
portfoliosToAffirm: (DefaultPortfolio | NumberedPortfolio)[][],
latestBlock: BigNumber,
venueId: BigNumber,
venueId: BigNumber | undefined,
context: Context
): Promise<{
errIndexes: {
Expand Down Expand Up @@ -366,7 +378,7 @@ async function getTxArgsAndErrors(
!datesErrIndexes.length &&
!sameIdentityErrIndexes.length
) {
const rawVenueId = bigNumberToU64(venueId, context);
const rawVenueId = optionize(bigNumberToU64)(venueId, context);
const rawSettlementType = endConditionToSettlementType(endCondition, context);
const rawTradeDate = optionize(dateToMoment)(tradeDate, context);
const rawValueDate = optionize(dateToMoment)(valueDate, context);
Expand Down Expand Up @@ -504,22 +516,33 @@ export async function prepareAddInstruction(
polymeshApi: {
tx: { settlement },
},
isV6,
},
context,
storage: { portfoliosToAffirm },
} = this;
const { instructions, venueId } = args;

await assertVenueFiltering(instructions, venueId, context);
if (isV6 && !venueId) {
throw new PolymeshError({
code: ErrorCode.General,
message: 'A venue id must be provided on v6 chains',
});
}

const venueAssertions = [assertVenueFiltering(instructions, venueId, context)];
if (venueId) {
venueAssertions.push(assertVenueExists(venueId, context));
}

const allMediators = instructions.flatMap(
({ mediators }) => mediators?.map(mediator => asIdentity(mediator, context)) ?? []
);

const [latestBlock] = await Promise.all([
context.getLatestBlock(),
assertVenueExists(venueId, context),
...allMediators.map(mediator => assertIdentityExists(mediator)),
...venueAssertions,
]);

if (!instructions.length) {
Expand Down Expand Up @@ -649,8 +672,10 @@ export async function getAuthorization(
portfolios = unionWith(portfolios, portfoliosList, isEqual);
});

const roles = venueId ? [{ type: RoleType.VenueOwner, venueId } as const] : undefined;

return {
roles: [{ type: RoleType.VenueOwner, venueId }],
roles,
permissions: {
assets: [],
portfolios,
Expand Down
2 changes: 1 addition & 1 deletion src/api/procedures/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -973,7 +973,7 @@ export interface AddInstructionsParams {
}

export type AddInstructionWithVenueIdParams = AddInstructionParams & {
venueId: BigNumber;
venueId?: BigNumber;
};

export interface InstructionIdParams {
Expand Down

0 comments on commit 8750fe9

Please sign in to comment.