Skip to content

Commit

Permalink
Merge pull request #231 from logion-network/feature/direct-protection
Browse files Browse the repository at this point in the history
Review-less protection activation
  • Loading branch information
gdethier authored Feb 2, 2024
2 parents d6d2b7e + 033eb61 commit aa57ccb
Show file tree
Hide file tree
Showing 9 changed files with 302 additions and 484 deletions.
47 changes: 0 additions & 47 deletions packages/client-node/integration/Loc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -624,53 +624,6 @@ export async function collectionLocWithUpload(state: State) {
expect(items[2].termsAndConditions.length).toBe(1);
}

export async function identityLoc(state: State) {

const { alice, aliceAccount, newAccount, signer } = state;
const client = state.client.withCurrentAddress(newAccount);
let locsState = await client.locsState();

await initRequesterBalance(TEST_LOGION_CLIENT_CONFIG, signer, newAccount.address);

const pendingRequest = await locsState.requestIdentityLoc({
legalOfficerAddress: alice.address,
description: "This is an Identity LOC",
userIdentity: {
email: "[email protected]",
firstName: "John",
lastName: "Doe",
phoneNumber: "+1234",
},
userPostalAddress: {
line1: "Peace Street",
line2: "2nd floor",
postalCode: "10000",
city: "MyCity",
country: "Wonderland"
},
draft: false,
}) as PendingRequest;

locsState = pendingRequest.locsState();
expect(locsState.pendingRequests["Identity"][0].data().status).toBe("REVIEW_PENDING");

const aliceClient = state.client.withCurrentAddress(aliceAccount);
const alicePendingRequest = await findWithLegalOfficerClient(aliceClient, pendingRequest) as PendingRequest;
const aliceAcceptedRequest = await alicePendingRequest.legalOfficer.accept({ signer }) as AcceptedRequest;
expect(aliceAcceptedRequest.data().status).toBe("REVIEW_ACCEPTED");

const acceptedRequest = await pendingRequest.refresh() as AcceptedRequest;
const openLoc = await acceptedRequest.open({ signer, autoPublish: false });
expect(openLoc.data().status).toBe("OPEN");

let aliceOpenLoc = await aliceAcceptedRequest.refresh() as OpenLoc;
aliceOpenLoc = await waitFor<OpenLoc>({
producer: prev => prev ? prev.refresh() as Promise<OpenLoc> : aliceOpenLoc.refresh() as Promise<OpenLoc>,
predicate: state => state.legalOfficer.canClose(false),
});
await aliceOpenLoc.legalOfficer.close({ signer, autoAck: false });
}

export async function otherIdentityLoc(state: State): Promise<UUID> {
const { alice, aliceAccount, ethereumAccount, signer } = state;

Expand Down
4 changes: 1 addition & 3 deletions packages/client-node/integration/Main.spec.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
import { setupInitialState, State, tearDown } from "./Utils.js";
import { enablesProtection, requestsProtectionAndCancel, requestValidIdentity } from "./Protection.js";
import { enablesProtection, requestValidIdentity } from "./Protection.js";
import { transferAndCannotPayFees, transfers, transferWithInsufficientFunds } from "./Balance.js";
import { providesVault } from "./Vault.js";
import { recoverLostAccount, recoverLostVault, requestRecoveryAndCancel, requestRecoveryWithResubmit } from "./Recovery.js";
import {
requestTransactionLoc,
collectionLoc,
collectionLocWithUpload,
identityLoc,
otherIdentityLoc,
logionIdentityLoc,
transactionLocWithCustomLegalFee,
Expand Down Expand Up @@ -54,7 +53,6 @@ describe("Logion SDK", () => {

it("enables protection", async () => {
const identityLocs = await requestValidIdentity(state, state.requesterAccount);
await requestsProtectionAndCancel(state, identityLocs);
await enablesProtection(state, identityLocs);
});

Expand Down
173 changes: 12 additions & 161 deletions packages/client-node/integration/Protection.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,8 @@
import { buildApiClass, UUID, ValidAccountId } from '@logion/node-api';
import { UUID, ValidAccountId } from '@logion/node-api';

import {
LogionClient,
AxiosFactory,
AcceptedProtection,
ActiveProtection,
NoProtection,
PendingRecovery,
RejectedProtection,
PendingProtection,
LogionClientConfig,
FullSigner,
LegalOfficer,
ProtectionRequest,
PendingRequest,
AcceptedRequest,
OpenLoc,
Expand All @@ -37,34 +27,12 @@ export async function requestValidIdentity(state: State, account: ValidAccountId
}

export async function enablesProtection(state: State, identityLocs: IdentityLocs) {
const activate = await enableProtection(state, identityLocs);
const activate = await activateProtection(state, identityLocs);
expect(activate).toBeInstanceOf(ActiveProtection);
}

export async function requestsProtectionAndCancel(state: State, identityLocs: IdentityLocs) {
const cancelled = await requestProtectionAndCancel(state, identityLocs);
expect(cancelled).toBeInstanceOf(NoProtection);
}

async function requestProtectionAndCancel(state: State, identityLocs: IdentityLocs): Promise<NoProtection> {
const { client, signer, alice, aliceAccount, bob, bobAccount, requesterAccount } = state;

const pending = await requestProtection(state, identityLocs);

console.log("LO's - Alice and Bob Rejecting")
await rejectRequest(client, signer, bob, bobAccount, requesterAccount.address, "Your protection request is not complete");
await rejectRequest(client, signer, alice, aliceAccount, requesterAccount.address, "Some info is missing");

const maybeRejected = await pending.refresh();
if (maybeRejected instanceof RejectedProtection) {
return maybeRejected.cancel();
} else {
throw new Error("Unexpected state, aborting");
}
}

async function requestProtection(state: State, identityLocs: IdentityLocs): Promise<PendingProtection> {
const { client, alice, bob, requesterAccount } = state;
async function activateProtection(state: State, identityLocs: IdentityLocs): Promise<ActiveProtection> {
const { client, alice, charlie, requesterAccount, signer } = state;

const authenticatedClient = client.withCurrentAddress(requesterAccount);

Expand All @@ -73,11 +41,14 @@ async function requestProtection(state: State, identityLocs: IdentityLocs): Prom
expect(current).toBeInstanceOf(NoProtection);

if (current instanceof NoProtection) {
return await current.requestProtection({
legalOfficer1: authenticatedClient.getLegalOfficer(alice.address),
legalOfficer2: authenticatedClient.getLegalOfficer(bob.address),
requesterIdentityLoc1: identityLocs.alice,
requesterIdentityLoc2: identityLocs.bob,
return await current.activateProtection({
payload: {
legalOfficer1: authenticatedClient.getLegalOfficer(alice.address),
legalOfficer2: authenticatedClient.getLegalOfficer(charlie.address),
requesterIdentityLoc1: identityLocs.alice,
requesterIdentityLoc2: identityLocs.charlie,
},
signer,
});
} else {
throw new Error("Unexpected state, aborting");
Expand Down Expand Up @@ -131,123 +102,3 @@ async function createsIdentityLoc(state: State, account: ValidAccountId, legalOf
});
return await lloOpen.legalOfficer.close({ signer, autoAck: false }) as ClosedLoc;
}

async function enableProtection(state: State, identityLocs: IdentityLocs): Promise<ActiveProtection | PendingRecovery | undefined> {
const { client, signer, alice, aliceAccount, bob, bobAccount, charlie, charlieAccount, requesterAccount } = state;
const requester = requesterAccount.address;
const pending = await requestProtection(state, identityLocs);

console.log("LO's - Bob Rejecting")
await rejectRequest(client, signer, bob, bobAccount, requester, "I dont speak your language");

console.log("User changing LO: Charlie instead of Bob");
const rejected = (await pending.refresh()) as RejectedProtection;
const pendingAgain = await rejected.changeLegalOfficer(bob, charlie, identityLocs.charlie);

console.log("LO's - Alice Rejecting")
await rejectRequest(client, signer, alice, aliceAccount, requester, "Some info is missing");

console.log("User resubmitting to Alice");
const rejectedAgain = (await pendingAgain.refresh()) as RejectedProtection;
const stillPending = await rejectedAgain.resubmit(alice);

console.log("LO's - Accepting")
await acceptRequest(TEST_LOGION_CLIENT_CONFIG, client, signer, alice, aliceAccount, requester);
await acceptRequest(TEST_LOGION_CLIENT_CONFIG, client, signer, charlie, charlieAccount, requester);

const accepted = (await stillPending.refresh()) as AcceptedProtection;
console.log("Activating")
return accepted.activate({ signer });
}

export async function rejectRequest(
client: LogionClient,
signer: FullSigner,
legalOfficer: LegalOfficer,
legalOfficerAccount: ValidAccountId,
requesterAddress: string,
reason: string,
) {
const axios = await buildLegalOfficerAxios(client, signer, legalOfficer, legalOfficerAccount);

const response = await axios.put("/api/protection-request", {
legalOfficerAddress: legalOfficer.address,
statuses: [ "PENDING" ],
requesterAddress
});
const request: ProtectionRequest = response.data.requests[0];

await axios.post(`/api/protection-request/${ request.id }/reject`, {
reason
});
}

export async function acceptRequest(
config: LogionClientConfig,
client: LogionClient,
signer: FullSigner,
legalOfficer: LegalOfficer,
legalOfficerAccount: ValidAccountId,
requesterAddress: string,
) {
const legalOfficerAddress = legalOfficer.address;
const axios = await buildLegalOfficerAxios(client, signer, legalOfficer, legalOfficerAccount);

const response = await axios.put("/api/protection-request", {
legalOfficerAddress: legalOfficer.address,
statuses: [ "PENDING" ],
requesterAddress
});
const request: ProtectionRequest = response.data.requests[0];

const identityLocId = await createAndCloseIdentityLoc(
config,
signer,
legalOfficerAddress,
request.requesterAddress
);

await axios.post(`/api/protection-request/${ request.id }/accept`, {
locId: identityLocId.toString()
});
}

async function buildLegalOfficerAxios(
client: LogionClient,
signer: FullSigner,
legalOfficer: LegalOfficer,
legalOfficerAccount: ValidAccountId,
) {
const authenticatedClient = await client.authenticate([ legalOfficerAccount ], signer);
const token = authenticatedClient.tokens.get(legalOfficerAccount)!;
const axiosFactory = new AxiosFactory();
return axiosFactory.buildAxiosInstance(legalOfficer.node, token.value);
}

async function createAndCloseIdentityLoc(
config: LogionClientConfig,
signer: FullSigner,
legalOfficerAddress: string,
requesterAddress: string
): Promise<UUID> {
const api = await buildApiClass(config.rpcEndpoints);
const identityLocId = new UUID();
await signer.signAndSend({
signerId: requesterAddress,
submittable: api.polkadot.tx.logionLoc.createPolkadotIdentityLoc(
api.adapters.toLocId(identityLocId),
legalOfficerAddress,
api.fees.getDefaultLegalFee({ locType: "Identity" }).canonical,
{
metadata: [],
files: [],
links: [],
}
)
});
await signer.signAndSend({
signerId: legalOfficerAddress,
submittable: api.polkadot.tx.logionLoc.close(api.adapters.toLocId(identityLocId), null, false)
});
return identityLocId;
}
Loading

0 comments on commit aa57ccb

Please sign in to comment.