Skip to content

Commit

Permalink
add did (#4)
Browse files Browse the repository at this point in the history
  • Loading branch information
dangell7 authored Mar 10, 2024
1 parent 1be3763 commit e67e370
Show file tree
Hide file tree
Showing 3 changed files with 417 additions and 0 deletions.
168 changes: 168 additions & 0 deletions contracts/did/did.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2024 Transia, LLC
This financial tool is designed for use by individuals or organizations
that hold the appropriate licenses and qualifications to engage with such
products in a manner that complies with all relevant laws and regulations.
Unauthorized use or redistribution of this tool may result in legal action.
The content provided in this financial tool is for informational purposes
only and should not be interpreted as financial advice or an endorsement of
any particular investment or financial strategy. Users should seek advice
from a certified professional or financial advisor before making any
investment choices.
By using this financial tool, the user agrees to indemnify Transia, LLC from
any claims, damages, or losses that may arise from their use or reliance on
the information contained within. The user acknowledges that they are utilizing
this tool at their own risk and that Transia, LLC will not be held responsible
for any direct, indirect, incidental, punitive, special, or consequential
damages, including but not limited to, damages for lost profits, goodwill,
usage, data, or other intangible losses.
*/
//==============================================================================

#include <stdint.h>
#include "hookapi.h"

#define DONE(x)\
return accept(SBUF(x), __LINE__)

#define NOPE(x)\
return rollback(SBUF(x), __LINE__)

#define SIG_OFFSET 52U

const uint8_t dids_namespace[] = {
0x43U, 0xF6U, 0xCBU, 0x20U, 0x14U, 0x01U, 0x66U, 0xCCU,
0x9EU, 0x7AU, 0x5EU, 0x07U, 0xFCU, 0xA8U, 0xE8U, 0x4CU,
0xB7U, 0xE5U, 0x76U, 0x21U, 0x92U, 0x78U, 0x8BU, 0x5DU,
0x4CU, 0xD0U, 0x8FU, 0x1FU, 0xD0U, 0x5FU, 0xF1U, 0x58U
};

int64_t hook(uint32_t r)
{
_g(1,1);

uint8_t hook_acc[32];
hook_account(hook_acc + 12, 20);

uint8_t otx_acc[32];
otxn_field(otx_acc + 12, 20, sfAccount);

if (BUFFER_EQUAL_20(hook_acc, otx_acc))
DONE("did.c: passing outgoing txn");

int64_t tt = otxn_type();
if (tt != ttINVOKE)
NOPE("did.c: Rejecting non-Invoke, non-Payment txn.");

// get admin account
uint8_t admin[20];
if (hook_param(SBUF(admin), "ADM", 3) != 20)
NOPE("did.c: Misconfigured. Missing ADM install parameter.");

uint8_t op;
if (otxn_param(&op, 1, "OP", 2) != 1)
NOPE("did.c: Missing OP parameter on Invoke.");

TRACEHEX(op);

uint8_t so;
if (otxn_param(&so, 1, "SO", 2) != 1)
NOPE("did.c: Missing SO parameter on Invoke.");

TRACEHEX(so);

// admin invoke ops are:
// VC - validator create (admin)
// VU - validator update (admin)
// VD - validator delete (admin)

// validator invoke ops are:
// DC - did create (validator)
// DU - did update (validator)
// DD - did delete (validator)

// admin permission check
int64_t is_admin = BUFFER_EQUAL_20(otx_acc + 12, admin);
if (!is_admin && op == 'V')
NOPE("did.c: Admin only operation.");

// validator permission check
uint8_t acc[20];
uint8_t key[33];
if ((op == 'D') && state(SBUF(key), otx_acc + 12, 20) == DOESNT_EXIST)
{
NOPE("did.c: Validator does not exist.");
}

// get signature if any
// Signature format is packed binary data of the form:
// <20 byte dest accid><32 byte var string><signature>
uint8_t sig_buf[256];
int64_t sig_len = otxn_param(SBUF(sig_buf), "SIG", 3);
if (sig_len > 0)
{
if (sig_len < 80)
NOPE("did.c: Signature too short.");

if (!util_verify(sig_buf, SIG_OFFSET, sig_buf + SIG_OFFSET, sig_len - SIG_OFFSET, SBUF(key)))
NOPE("did.c: Signature verification failed.");
}
// action
switch (op)
{
case 'V':
{
otxn_param(SBUF(acc), "VA", 2);
otxn_param(SBUF(key), "VK", 2);
switch (so)
{
case 'C':
case 'U':
{
state_set(SBUF(key), acc, 20);
DONE("did.c: Validator Created.");
}
case 'D':
{
state_set(0, 0, acc, 20);
DONE("did.c: Validator Deleted.");
}
default:
NOPE("did.c: Unknown sub operation.");
}
}
case 'D':
{
otxn_param(SBUF(acc), "CA", 2);
switch (so)
{
case 'C':
case 'U':
{
state_foreign_set(SBUF(sig_buf), acc, 20, dids_namespace, 32, hook_acc + 12, 20);
DONE("did.c: DID Create.");
}
case 'D':
{
state_foreign_set(0, 0, acc, 20, dids_namespace, 32, hook_acc + 12, 20);
DONE("did.c: DID Create.");
}

default:
NOPE("did.c: Unknown sub operation.");
}
}

default:
{
NOPE("did.c: Unknown operation.");
}
}

return 0;
}
214 changes: 214 additions & 0 deletions test/integration/did/did.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,214 @@
// xrpl
import { Invoke, SetHookFlags, TransactionMetadata } from '@transia/xrpl'
// xrpl-helpers
import {
XrplIntegrationTestContext,
setupClient,
teardownClient,
serverUrl,
} from '@transia/hooks-toolkit/dist/npm/src/libs/xrpl-helpers'
// src
import {
Xrpld,
SetHookParams,
setHooksV3,
createHookPayload,
ExecutionUtility,
clearHookStateV3,
clearAllHooksV3,
iHook,
iHookParamEntry,
iHookParamName,
iHookParamValue,
StateUtility,
padHexString,
hexNamespace,
} from '@transia/hooks-toolkit'
import {
decodeModel,
xrpAddressToHex,
} from '@transia/hooks-toolkit/dist/npm/src/libs/binary-models'
import { sign, verify } from '@transia/ripple-keypairs'
import { DIDModel } from './models/DIDModel'

// Step 1:
// - DMV Manager adds/updates/deletes clerk
// Key: clerkAcct: Data: publicKey

// Step 2:
// - Document created/encrypted (Document ID is generated)
// - DMV Clerk signs DIDModel(owner, document id)
// - DMV Clerk submits invoke to hook
// Key: citizen: Data: message + sig

// Step 3:
// - Anyone Anywhere verifies user account

describe('oracle', () => {
let testContext: XrplIntegrationTestContext

beforeAll(async () => {
testContext = await setupClient(serverUrl)
const hookWallet = testContext.hook1
const adminWallet = testContext.alice
const hookParam1 = new iHookParamEntry(
new iHookParamName('ADM'),
new iHookParamValue(xrpAddressToHex(adminWallet.classicAddress), true)
)
const acct1hook1 = createHookPayload({
version: 0,
createFile: 'did',
namespace: 'validators',
flags: SetHookFlags.hsfOverride,
hookOnArray: ['Invoke'],
hookParams: [hookParam1.toXrpl()],
})
await setHooksV3({
client: testContext.client,
seed: hookWallet.seed,
hooks: [{ Hook: acct1hook1 }],
} as SetHookParams)
})
afterAll(async () => {
const clearHook1 = {
Flags: SetHookFlags.hsfNSDelete,
HookNamespace: hexNamespace('validators'),
} as iHook
const clearHook2 = {
Flags: SetHookFlags.hsfNSDelete,
HookNamespace: hexNamespace('dids'),
} as iHook
await clearHookStateV3({
client: testContext.client,
seed: testContext.hook1.seed,
hooks: [{ Hook: clearHook1 }, { Hook: clearHook2 }],
} as SetHookParams)

await clearAllHooksV3({
client: testContext.client,
seed: testContext.hook1.seed,
} as SetHookParams)
teardownClient(testContext)
})

it('did - create validator', async () => {
const hookWallet = testContext.hook1
const adminWallet = testContext.alice
const clerk1Wallet = testContext.bob
// const keypair = Wallet.generate()
const otxnParam1 = new iHookParamEntry(
new iHookParamName('OP'),
new iHookParamValue('V')
)
const otxnParam2 = new iHookParamEntry(
new iHookParamName('SO'),
new iHookParamValue('C')
)
const otxnParam3 = new iHookParamEntry(
new iHookParamName('VA'),
new iHookParamValue(xrpAddressToHex(clerk1Wallet.classicAddress), true)
)
const otxnParam4 = new iHookParamEntry(
new iHookParamName('VK'),
new iHookParamValue(clerk1Wallet.publicKey, true)
)
const builtTx1: Invoke = {
TransactionType: 'Invoke',
Account: adminWallet.classicAddress,
Destination: hookWallet.classicAddress,
HookParameters: [
otxnParam1.toXrpl(),
otxnParam2.toXrpl(),
otxnParam3.toXrpl(),
otxnParam4.toXrpl(),
],
}

const result1 = await Xrpld.submit(testContext.client, {
wallet: adminWallet,
tx: builtTx1,
})
const hookExecutions1 = await ExecutionUtility.getHookExecutionsFromMeta(
testContext.client,
result1.meta as TransactionMetadata
)
expect(hookExecutions1.executions[0].HookReturnString).toMatch(
'did.c: Validator Created.'
)
})
it('did - create did', async () => {
const hookWallet = testContext.hook1
const clerk1Wallet = testContext.bob
const citizenWallet = testContext.carol
// const keypair = Wallet.generate()
const otxnParam1 = new iHookParamEntry(
new iHookParamName('OP'),
new iHookParamValue('D')
)
const otxnParam2 = new iHookParamEntry(
new iHookParamName('SO'),
new iHookParamValue('C')
)
const otxnParam3 = new iHookParamEntry(
new iHookParamName('CA'),
new iHookParamValue(xrpAddressToHex(citizenWallet.classicAddress), true)
)
const hex = new DIDModel(clerk1Wallet.classicAddress, '123456').encode()
const signature = sign(hex, clerk1Wallet.privateKey)
expect(verify(hex, signature, clerk1Wallet.publicKey)).toBe(true)

const otxnParam4 = new iHookParamEntry(
new iHookParamName('SIG'),
new iHookParamValue(hex + signature, true)
)
const builtTx1: Invoke = {
TransactionType: 'Invoke',
Account: clerk1Wallet.classicAddress,
Destination: hookWallet.classicAddress,
HookParameters: [
otxnParam1.toXrpl(),
otxnParam2.toXrpl(),
otxnParam3.toXrpl(),
otxnParam4.toXrpl(),
],
}

const result1 = await Xrpld.submit(testContext.client, {
wallet: clerk1Wallet,
tx: builtTx1,
})
const hookExecutions1 = await ExecutionUtility.getHookExecutionsFromMeta(
testContext.client,
result1.meta as TransactionMetadata
)
expect(hookExecutions1.executions[0].HookReturnString).toMatch(
'did.c: DID Create.'
)

const sigState = await StateUtility.getHookState(
testContext.client,
hookWallet.classicAddress,
padHexString(xrpAddressToHex(citizenWallet.classicAddress)),
hexNamespace('dids')
)
// Signature Total - 256 (in hook) * 2
const sigTotal = 256 * 2
const model = decodeModel(
sigState.HookStateData.slice(0, hex.length),
DIDModel
)
const clerkState = await StateUtility.getHookState(
testContext.client,
hookWallet.classicAddress,
padHexString(xrpAddressToHex(model.validator)),
hexNamespace('validators')
)
expect(
verify(
model.encode(),
sigState.HookStateData.slice(hex.length, sigTotal).replace(/0+$/, ''),
clerkState.HookStateData
)
).toBe(true)
})
})
Loading

0 comments on commit e67e370

Please sign in to comment.