add option, fix type errors because of changes regarding need of communityId on some places

This commit is contained in:
einhornimmond 2026-02-25 16:05:14 +01:00
parent f45705e714
commit 10334f5a46
28 changed files with 156 additions and 64 deletions

View File

@ -1,5 +1,5 @@
import { readFileSync } from 'node:fs'
import { loadCryptoKeys, MemoryBlock } from 'gradido-blockchain-js'
import { InMemoryBlockchainProvider, loadCryptoKeys, MemoryBlock } from 'gradido-blockchain-js'
import { configure, getLogger, Logger } from 'log4js'
import * as v from 'valibot'
import { CONFIG } from '../config'
@ -80,6 +80,7 @@ export async function checkGradidoNode(
// ask gradido node if community blockchain was created
try {
InMemoryBlockchainProvider.getInstance().getBlockchain(homeCommunity.uuid)
if (
!(await clients.gradidoNode.getTransaction({
transactionId: 1,

View File

@ -9,7 +9,6 @@ import { HieroClient } from '../client/hiero/HieroClient'
import { CONFIG } from '../config'
import {
GRADIDO_NODE_HOME_FOLDER_NAME,
GRADIDO_NODE_RUNTIME_PATH,
LOG4JS_BASE_CATEGORY,
} from '../config/const'
import { checkFileExist, checkPathExist } from '../utils/filesystem'
@ -37,7 +36,7 @@ export async function initGradidoNode(clients: AppContextClients): Promise<void>
// write Hedera Address Book
exportHederaAddressbooks(gradidoNodeHomeFolder, clients.hiero),
// check GradidoNode Runtime, download when missing
ensureGradidoNodeRuntimeAvailable(GRADIDO_NODE_RUNTIME_PATH),
ensureGradidoNodeRuntimeAvailable(GradidoNodeProcess.getRuntimePathFileName()),
// export communities to GradidoNode Folder
exportCommunities(gradidoNodeHomeFolder, clients.backend),
])

View File

@ -8,7 +8,7 @@ import { LOG4JS_BASE_CATEGORY } from '../../config/const'
import { AddressType } from '../../data/AddressType.enum'
import { Uuidv4Hash } from '../../data/Uuidv4Hash'
import { addressTypeSchema, confirmedTransactionSchema } from '../../schemas/typeConverter.schema'
import { Hex32, Hex32Input, HieroId, hex32Schema } from '../../schemas/typeGuard.schema'
import { Hex32, Hex32Input, Uuidv4, hex32Schema } from '../../schemas/typeGuard.schema'
import { isPortOpenRetry } from '../../utils/network'
import { GradidoNodeErrorCodes } from './GradidoNodeErrorCodes'
import {
@ -75,7 +75,7 @@ export class GradidoNodeClient {
const response = await this.rpcCall<{ transaction: string }>('getTransaction', parameter)
if (response.isSuccess()) {
// this.logger.debug('result: ', response.result.transaction)
return v.parse(confirmedTransactionSchema, response.result.transaction)
return v.parse(confirmedTransactionSchema, { base64: response.result.transaction, communityId: parameter.communityId })
}
if (response.isError()) {
if (response.error.code === GradidoNodeErrorCodes.TRANSACTION_NOT_FOUND) {
@ -88,19 +88,19 @@ export class GradidoNodeClient {
/**
* getLastTransaction
* get the last confirmed transaction from a specific community
* @param hieroTopic the community hiero topic id
* @param communityId the community id
* @returns the last confirmed transaction or undefined if blockchain for community is empty or not found
* @throws GradidoNodeRequestError
*/
public async getLastTransaction(hieroTopic: HieroId): Promise<ConfirmedTransaction | undefined> {
public async getLastTransaction(communityId: Uuidv4): Promise<ConfirmedTransaction | undefined> {
const parameter = {
format: 'base64',
topic: hieroTopic,
communityId,
}
const response = await this.rpcCall<{ transaction: string }>('getLastTransaction', parameter)
if (response.isSuccess()) {
return v.parse(confirmedTransactionSchema, response.result.transaction)
return v.parse(confirmedTransactionSchema, { base64: response.result.transaction, communityId: parameter.communityId })
}
if (response.isError()) {
if (response.error.code === GradidoNodeErrorCodes.GRADIDO_NODE_ERROR) {
@ -115,7 +115,7 @@ export class GradidoNodeClient {
* get list of confirmed transactions from a specific community
* @param input fromTransactionId is the id of the first transaction to return
* @param input maxResultCount is the max number of transactions to return
* @param input topic is the community hiero topic id
* @param input communityId is the community id
* @returns list of confirmed transactions
* @throws GradidoNodeRequestError
* @example
@ -123,7 +123,7 @@ export class GradidoNodeClient {
* const transactions = await getTransactions({
* fromTransactionId: 1,
* maxResultCount: 100,
* topic: communityUuid,
* communityId: communityUuid,
* })
* ```
*/
@ -137,7 +137,7 @@ export class GradidoNodeClient {
parameter,
)
return result.transactions.map((transactionBase64) =>
v.parse(confirmedTransactionSchema, transactionBase64),
v.parse(confirmedTransactionSchema, { base64: transactionBase64, communityId: parameter.communityId }),
)
}
@ -163,7 +163,7 @@ export class GradidoNodeClient {
parameter,
)
return response.transactions.map((transactionBase64) =>
v.parse(confirmedTransactionSchema, transactionBase64),
v.parse(confirmedTransactionSchema, { base64: transactionBase64, communityId: parameter.communityId }),
)
}
@ -173,15 +173,15 @@ export class GradidoNodeClient {
* can be used to check if user/account exists on blockchain
* look also for gmw, auf and deferred transfer accounts
* @param pubkey the public key of the user or account
* @param hieroTopic the community hiero topic id
* @param communityId the community id
* @returns the address type of the user/account, AddressType.NONE if not found
* @throws GradidoNodeRequestError
*/
public async getAddressType(pubkey: Hex32Input, hieroTopic: HieroId): Promise<AddressType> {
public async getAddressType(pubkey: Hex32Input, communityId: Uuidv4): Promise<AddressType> {
const parameter = {
pubkey: v.parse(hex32Schema, pubkey),
topic: hieroTopic,
communityId,
}
const response = await this.rpcCallResolved<{ addressType: string }>(
'getAddressType',
@ -194,17 +194,17 @@ export class GradidoNodeClient {
* findUserByNameHash
* find a user by name hash
* @param nameHash the name hash of the user
* @param hieroTopic the community hiero topic id
* @param communityId the community id
* @returns the public key of the user as hex32 string or undefined if user is not found
* @throws GradidoNodeRequestError
*/
public async findUserByNameHash(
nameHash: Uuidv4Hash,
hieroTopic: HieroId,
communityId: Uuidv4,
): Promise<Hex32 | undefined> {
const parameter = {
nameHash: nameHash.getAsHexString(),
topic: hieroTopic,
communityId,
}
const response = await this.rpcCall<{ pubkey: string; timeUsed: string }>(
'findUserByNameHash',

View File

@ -10,6 +10,7 @@ import {
LOG4JS_BASE_CATEGORY,
} from '../../config/const'
import { delay } from '../../utils/time'
import path from 'node:path'
/**
* A Singleton class defines the `getInstance` method that lets clients access
* the unique singleton instance.
@ -43,6 +44,20 @@ export class GradidoNodeProcess {
return GradidoNodeProcess.instance
}
public static getRuntimePathFileName(): string {
const isWindows = process.platform === 'win32'
const binaryName = isWindows ? 'GradidoNode.exe' : 'GradidoNode'
return path.join(
__dirname,
'..',
'..',
'gradido_node',
'bin',
binaryName,
)
}
public start() {
if (this.proc) {
this.logger.warn('GradidoNodeProcess already running.')
@ -57,6 +72,7 @@ export class GradidoNodeProcess {
SERVER_JSON_RPC_PORT: CONFIG.DLT_NODE_SERVER_PORT.toString(),
USERPROFILE: CONFIG.DLT_GRADIDO_NODE_SERVER_HOME_FOLDER,
HOME: CONFIG.DLT_GRADIDO_NODE_SERVER_HOME_FOLDER,
UNSECURE_ALLOW_CORS_ALL: CONFIG.DLT_GRADIDO_NODE_SERVER_ALLOW_CORS ? '1' : '0',
},
onExit(_proc, exitCode, signalCode, error) {
logger.warn(`GradidoNodeProcess exited with code ${exitCode} and signalCode ${signalCode}`)

View File

@ -1,18 +1,20 @@
import { beforeAll, describe, expect, it } from 'bun:test'
import * as v from 'valibot'
import {
HieroId,
HieroTransactionIdString,
Uuidv4,
hieroIdSchema,
hieroTransactionIdStringSchema,
uuidv4Schema,
} from '../../schemas/typeGuard.schema'
import { transactionIdentifierSchema } from './input.schema'
import { v4 as uuidv4 } from 'uuid'
let topic: HieroId
const topicString = '0.0.261'
let communityId: Uuidv4
const uuidv4String = uuidv4()
let hieroTransactionId: HieroTransactionIdString
beforeAll(() => {
topic = v.parse(hieroIdSchema, topicString)
communityId = v.parse(uuidv4Schema, uuidv4String)
hieroTransactionId = v.parse(hieroTransactionIdStringSchema, '0.0.261-1755348116-1281621')
})
@ -21,26 +23,26 @@ describe('transactionIdentifierSchema ', () => {
expect(
v.parse(transactionIdentifierSchema, {
transactionId: 1,
topic: topicString,
communityId,
}),
).toEqual({
transactionId: 1,
hieroTransactionId: undefined,
topic,
communityId,
})
})
it('valid, transaction identified by hieroTransactionId and topic', () => {
expect(
v.parse(transactionIdentifierSchema, {
hieroTransactionId: '0.0.261-1755348116-1281621',
topic: topicString,
communityId,
}),
).toEqual({
hieroTransactionId,
topic,
communityId,
})
})
it('invalid, missing topic', () => {
it('invalid, missing communityId', () => {
expect(() =>
v.parse(transactionIdentifierSchema, {
transactionId: 1,
@ -53,7 +55,7 @@ describe('transactionIdentifierSchema ', () => {
v.parse(transactionIdentifierSchema, {
transactionId: 1,
hieroTransactionId: '0.0.261-1755348116-1281621',
topic,
communityId,
}),
).toThrowError(new Error('expect transactionNr or hieroTransactionId not both'))
})

View File

@ -20,7 +20,7 @@ import { getLogger, Logger } from 'log4js'
import * as v from 'valibot'
import { CONFIG } from '../../config'
import { LOG4JS_BASE_CATEGORY } from '../../config/const'
import { HieroId, hieroIdSchema } from '../../schemas/typeGuard.schema'
import { HieroId, hieroIdSchema, Uuidv4 } from '../../schemas/typeGuard.schema'
import { durationInMinutesFromDates, printTimeDuration } from '../../utils/time'
import { GradidoNodeClient } from '../GradidoNode/GradidoNodeClient'
import { GradidoNodeProcess } from '../GradidoNode/GradidoNodeProcess'
@ -72,6 +72,7 @@ export class HieroClient {
public async sendMessage(
topicId: HieroId,
communityId: Uuidv4,
transaction: GradidoTransaction,
): Promise<TransactionId | null> {
const timeUsed = new Profiler()
@ -102,7 +103,7 @@ export class HieroClient {
// after 10 seconds, else restart GradidoNode
setTimeout(async () => {
const transaction = await GradidoNodeClient.getInstance().getTransaction({
topic: topicId,
communityId,
hieroTransactionId: sendResponse.transactionId.toString(),
})
if (!transaction) {

View File

@ -90,6 +90,13 @@ export const configSchema = v.object({
v.string('The home folder for the gradido dlt node server'),
path.join(__dirname, '..', '..', 'gradido_node'),
),
DLT_GRADIDO_NODE_SERVER_ALLOW_CORS: v.optional(
v.pipe(
v.string('Whether to allow CORS for the gradido dlt node server'),
v.transform<string, boolean>((input: string) => input === 'true'),
),
'false',
),
BACKEND_PORT: v.optional(
v.pipe(
v.string('A valid port on which the backend server is running'),

View File

@ -54,6 +54,9 @@ export class KeyPairIdentifierLogic {
return this.identifier.seed
}
getCommunityId(): Uuidv4 {
return this.identifier.communityId
}
getCommunityTopicId(): HieroId {
return this.identifier.communityTopicId
}
@ -76,7 +79,7 @@ export class KeyPairIdentifierLogic {
return this.getSeed()
}
getCommunityKey(): string {
return this.getCommunityTopicId()
return this.getCommunityId()
}
getCommunityUserKey(): string {
return this.deriveCommunityUserHash(0)
@ -107,7 +110,7 @@ export class KeyPairIdentifierLogic {
)
}
const resultString =
this.identifier.communityTopicId +
this.identifier.communityId +
this.identifier.account.userUuid.replace(/-/g, '') +
accountNr.toString()
return new MemoryBlock(resultString).calculateHash().convertToHex()

View File

@ -1,10 +1,10 @@
import { KeyPairEd25519 } from 'gradido-blockchain-js'
import { HieroId } from '../../schemas/typeGuard.schema'
import { Uuidv4 } from '../../schemas/typeGuard.schema'
export abstract class AbstractRemoteKeyPairRole {
protected topic: HieroId
public constructor(communityTopicId: HieroId) {
this.topic = communityTopicId
protected communityId: Uuidv4
public constructor(communityId: Uuidv4) {
this.communityId = communityId
}
public abstract retrieveKeyPair(): Promise<KeyPairEd25519>
}

View File

@ -10,7 +10,7 @@ export class ForeignCommunityKeyPairRole extends AbstractRemoteKeyPairRole {
public async retrieveKeyPair(): Promise<KeyPairEd25519> {
const transactionIdentifier = {
transactionId: 1,
topic: this.topic,
communityId: this.communityId,
}
const firstTransaction =
await GradidoNodeClient.getInstance().getTransaction(transactionIdentifier)

View File

@ -7,7 +7,7 @@ import { AbstractRemoteKeyPairRole } from './AbstractRemoteKeyPair.role'
export class RemoteAccountKeyPairRole extends AbstractRemoteKeyPairRole {
public constructor(private identifier: IdentifierAccount) {
super(identifier.communityTopicId)
super(identifier.communityId)
}
public async retrieveKeyPair(): Promise<KeyPairEd25519> {
@ -17,7 +17,7 @@ export class RemoteAccountKeyPairRole extends AbstractRemoteKeyPairRole {
const accountPublicKey = await GradidoNodeClient.getInstance().findUserByNameHash(
new Uuidv4Hash(this.identifier.account.userUuid),
this.topic,
this.communityId,
)
if (accountPublicKey) {
return new KeyPairEd25519(MemoryBlock.createPtr(MemoryBlock.fromHex(accountPublicKey)))

View File

@ -45,7 +45,7 @@ export async function ResolveKeyPair(input: KeyPairIdentifierLogic): Promise<Key
if (cache.getHomeCommunityTopicId() !== input.getCommunityTopicId()) {
const role = input.isAccountKeyPair()
? new RemoteAccountKeyPairRole(input.identifier)
: new ForeignCommunityKeyPairRole(input.getCommunityTopicId())
: new ForeignCommunityKeyPairRole(input.getCommunityId())
return await role.retrieveKeyPair()
}
// Community

View File

@ -27,7 +27,10 @@ export class CommunityRootTransactionRole extends AbstractTransactionRole {
public async getGradidoTransactionBuilder(): Promise<GradidoTransactionBuilder> {
const builder = new GradidoTransactionBuilder()
const communityKeyPair = await ResolveKeyPair(
new KeyPairIdentifierLogic({ communityTopicId: this.community.hieroTopicId }),
new KeyPairIdentifierLogic({
communityTopicId: this.community.hieroTopicId,
communityId: this.community.uuid,
}),
)
const gmwKeyPair = communityKeyPair.deriveChild(
hardenDerivationIndex(GMW_ACCOUNT_DERIVATION_INDEX),

View File

@ -52,6 +52,7 @@ export class CreationTransactionRole extends AbstractTransactionRole {
const homeCommunityKeyPair = await ResolveKeyPair(
new KeyPairIdentifierLogic({
communityTopicId: this.homeCommunityTopicId,
communityId: this.creationTransaction.user.communityId,
}),
)
// Memo: encrypted, home community and recipient can decrypt it
@ -65,7 +66,11 @@ export class CreationTransactionRole extends AbstractTransactionRole {
),
)
.setTransactionCreation(
new TransferAmount(recipientKeyPair.getPublicKey(), this.creationTransaction.amount),
new TransferAmount(
recipientKeyPair.getPublicKey(),
this.creationTransaction.amount,
this.creationTransaction.user.communityId,
),
this.creationTransaction.targetDate,
)
.sign(signerKeyPair)

View File

@ -41,6 +41,7 @@ export class DeferredTransferTransactionRole extends AbstractTransactionRole {
const recipientKeyPair = await ResolveKeyPair(
new KeyPairIdentifierLogic({
communityTopicId: this.deferredTransferTransaction.linkedUser.communityTopicId,
communityId: this.deferredTransferTransaction.linkedUser.communityId,
seed: this.seed,
}),
)
@ -61,6 +62,7 @@ export class DeferredTransferTransactionRole extends AbstractTransactionRole {
this.deferredTransferTransaction.amount.calculateCompoundInterest(
this.deferredTransferTransaction.timeoutDuration.getSeconds(),
),
this.deferredTransferTransaction.user.communityId,
),
recipientKeyPair.getPublicKey(),
),

View File

@ -65,6 +65,7 @@ export class RedeemDeferredTransferTransactionRole extends AbstractTransactionRo
new TransferAmount(
senderKeyPair.getPublicKey(),
this.redeemDeferredTransferTransaction.amount,
this.redeemDeferredTransferTransaction.user.communityId,
),
recipientKeyPair.getPublicKey(),
),

View File

@ -35,7 +35,10 @@ export class RegisterAddressTransactionRole extends AbstractTransactionRole {
public async getGradidoTransactionBuilder(): Promise<GradidoTransactionBuilder> {
const builder = new GradidoTransactionBuilder()
const communityTopicId = this.registerAddressTransaction.user.communityTopicId
const communityKeyPair = await ResolveKeyPair(new KeyPairIdentifierLogic({ communityTopicId }))
const communityKeyPair = await ResolveKeyPair(new KeyPairIdentifierLogic({
communityTopicId,
communityId: this.registerAddressTransaction.user.communityId,
}))
const keyPairIdentifier = this.registerAddressTransaction.user
// when accountNr is 0 it is the user account
keyPairIdentifier.account.accountNr = 0

View File

@ -23,6 +23,8 @@ import {
HieroTransactionIdString,
hieroTransactionIdStringSchema,
identifierSeedSchema,
Uuidv4,
uuidv4Schema,
} from '../../schemas/typeGuard.schema'
import { isTopicStillOpen } from '../../utils/hiero'
import { LinkedTransactionKeyPairRole } from '../resolveKeyPair/LinkedTransactionKeyPair.role'
@ -59,6 +61,7 @@ export async function SendToHieroContext(
const outboundHieroTransactionIdString = await sendViaHiero(
outboundTransaction,
role.getSenderCommunityTopicId(),
v.parse(uuidv4Schema, outboundTransaction.getCommunityId()),
)
// attach Hiero transaction ID to the builder for the inbound transaction
@ -69,7 +72,11 @@ export async function SendToHieroContext(
validate(inboundTransaction)
// send inbound transaction to hiero
await sendViaHiero(inboundTransaction, role.getRecipientCommunityTopicId())
await sendViaHiero(
inboundTransaction,
role.getRecipientCommunityTopicId(),
v.parse(uuidv4Schema, inboundTransaction.getCommunityId()),
)
return outboundHieroTransactionIdString
} else {
// build and validate local transaction
@ -80,6 +87,7 @@ export async function SendToHieroContext(
const hieroTransactionIdString = await sendViaHiero(
transaction,
role.getSenderCommunityTopicId(),
v.parse(uuidv4Schema, transaction.getCommunityId()),
)
return hieroTransactionIdString
}
@ -95,9 +103,10 @@ function validate(transaction: GradidoTransaction): void {
async function sendViaHiero(
gradidoTransaction: GradidoTransaction,
topic: HieroId,
communityId: Uuidv4
): Promise<HieroTransactionIdString> {
const client = HieroClient.getInstance()
const transactionId = await client.sendMessage(topic, gradidoTransaction)
const transactionId = await client.sendMessage(topic, communityId, gradidoTransaction)
if (!transactionId) {
throw new Error('missing transaction id from hiero')
}
@ -153,7 +162,7 @@ async function chooseCorrectRole(
throw new Error("redeem deferred transfer: couldn't generate seed public key")
}
const transactions = await GradidoNodeClient.getInstance().getTransactionsForAccount(
{ maxResultCount: 2, topic: transaction.user.communityTopicId },
{ maxResultCount: 2, communityId: transaction.user.communityId },
seedPublicKey.convertToHex(),
)
if (!transactions || transactions.length !== 1) {

View File

@ -51,7 +51,11 @@ export class TransferTransactionRole extends AbstractTransactionRole {
),
)
.setTransactionTransfer(
new TransferAmount(senderKeyPair.getPublicKey(), this.transferTransaction.amount),
new TransferAmount(
senderKeyPair.getPublicKey(),
this.transferTransaction.amount,
this.transferTransaction.user.communityId,
),
recipientKeyPair.getPublicKey(),
)
const senderCommunity = this.transferTransaction.user.communityTopicId

View File

@ -30,7 +30,7 @@ export function generateKeyPairCommunity(
if (!keyPair) {
throw new Error(`Couldn't create key pair for community ${community.communityUuid}`)
}
const communityKeyPairKey = new KeyPairIdentifierLogic({ communityTopicId: topicId }).getKey()
const communityKeyPairKey = new KeyPairIdentifierLogic({ communityTopicId: topicId, communityId: community.communityUuid }).getKey()
cache.addKeyPair(communityKeyPairKey, keyPair)
logger.info(`Community Key Pair added with key: ${communityKeyPairKey}`)
}
@ -44,6 +44,7 @@ export async function generateKeyPairUserAccount(
const userKeyPairRole = new UserKeyPairRole(user.gradidoId, communityKeyPair)
const userKeyPairKey = new KeyPairIdentifierLogic({
communityTopicId: communityTopicId,
communityId: user.communityUuid,
account: {
userUuid: user.gradidoId,
accountNr: 0,
@ -56,6 +57,7 @@ export async function generateKeyPairUserAccount(
const accountKeyPairRole = new AccountKeyPairRole(1, userKeyPair)
const accountKeyPairKey = new KeyPairIdentifierLogic({
communityTopicId: communityTopicId,
communityId: user.communityUuid,
account: {
userUuid: user.gradidoId,
accountNr: 1,

View File

@ -11,6 +11,7 @@ export type IdentifierCommunityAccount = v.InferOutput<typeof identifierCommunit
export const identifierKeyPairSchema = v.object({
communityTopicId: hieroIdSchema,
communityId: uuidv4Schema,
account: v.optional(identifierCommunityAccountSchema),
seed: v.optional(identifierSeedSchema),
})

View File

@ -34,8 +34,12 @@ const transactionLinkCode = (date: Date): string => {
}
let topic: HieroId
const topicString = '0.0.261'
let communityUuid: Uuidv4
const communityUuidString = '123e4567-e89b-12d3-a456-426614174000'
beforeAll(() => {
topic = v.parse(hieroIdSchema, topicString)
communityUuid = v.parse(uuidv4Schema, communityUuidString)
})
describe('transaction schemas', () => {
@ -55,6 +59,7 @@ describe('transaction schemas', () => {
registerAddress = {
user: {
communityTopicId: topicString,
communityId: communityUuidString,
account: { userUuid: userUuidString },
},
type: InputTransactionType.REGISTER_ADDRESS,
@ -66,6 +71,7 @@ describe('transaction schemas', () => {
expect(v.parse(transactionSchema, registerAddress)).toEqual({
user: {
communityTopicId: topic,
communityId: communityUuid,
account: {
userUuid,
accountNr: 0,
@ -80,6 +86,7 @@ describe('transaction schemas', () => {
expect(v.parse(registerAddressTransactionSchema, registerAddress)).toEqual({
user: {
communityTopicId: topic,
communityId: communityUuid,
account: {
userUuid,
accountNr: 0,
@ -101,10 +108,12 @@ describe('transaction schemas', () => {
const gradidoTransfer: TransactionInput = {
user: {
communityTopicId: topicString,
communityId: communityUuidString,
account: { userUuid: userUuidString },
},
linkedUser: {
communityTopicId: topicString,
communityId: communityUuidString,
account: { userUuid: userUuidString },
},
amount: '100',
@ -115,6 +124,7 @@ describe('transaction schemas', () => {
expect(v.parse(transactionSchema, gradidoTransfer)).toEqual({
user: {
communityTopicId: topic,
communityId: communityUuid,
account: {
userUuid,
accountNr: 0,
@ -122,6 +132,7 @@ describe('transaction schemas', () => {
},
linkedUser: {
communityTopicId: topic,
communityId: communityUuid,
account: {
userUuid,
accountNr: 0,
@ -138,10 +149,12 @@ describe('transaction schemas', () => {
const gradidoCreation: TransactionInput = {
user: {
communityTopicId: topicString,
communityId: communityUuidString,
account: { userUuid: userUuidString },
},
linkedUser: {
communityTopicId: topicString,
communityId: communityUuidString,
account: { userUuid: userUuidString },
},
amount: '1000',
@ -153,10 +166,12 @@ describe('transaction schemas', () => {
expect(v.parse(transactionSchema, gradidoCreation)).toEqual({
user: {
communityTopicId: topic,
communityId: communityUuid,
account: { userUuid, accountNr: 0 },
},
linkedUser: {
communityTopicId: topic,
communityId: communityUuid,
account: { userUuid, accountNr: 0 },
},
amount: v.parse(gradidoAmountSchema, gradidoCreation.amount!),
@ -172,12 +187,14 @@ describe('transaction schemas', () => {
const gradidoTransactionLink: TransactionInput = {
user: {
communityTopicId: topicString,
communityId: communityUuidString,
account: {
userUuid: userUuidString,
},
},
linkedUser: {
communityTopicId: topicString,
communityId: communityUuidString,
seed,
},
amount: '100',
@ -189,6 +206,7 @@ describe('transaction schemas', () => {
expect(v.parse(transactionSchema, gradidoTransactionLink)).toEqual({
user: {
communityTopicId: topic,
communityId: communityUuid,
account: {
userUuid,
accountNr: 0,
@ -196,6 +214,7 @@ describe('transaction schemas', () => {
},
linkedUser: {
communityTopicId: topic,
communityId: communityUuid,
seed: seedParsed,
},
amount: v.parse(gradidoAmountSchema, gradidoTransactionLink.amount!),

View File

@ -43,12 +43,14 @@ export type Transaction = v.InferOutput<typeof transactionSchema>
// if the account is identified by seed
export const seedAccountSchema = v.object({
communityTopicId: hieroIdSchema,
communityId: uuidv4Schema,
seed: identifierSeedSchema,
})
// if the account is identified by userUuid and accountNr
export const userAccountSchema = v.object({
communityTopicId: hieroIdSchema,
communityId: uuidv4Schema,
account: identifierCommunityAccountSchema,
})

View File

@ -8,6 +8,7 @@ import {
toAccountType,
toAddressType,
} from '../utils/typeConverter'
import { Uuidv4, uuidv4Schema } from './typeGuard.schema'
/**
* dateSchema for creating a date from string or Date object
@ -72,17 +73,23 @@ export const accountTypeSchema = v.pipe(
export const confirmedTransactionSchema = v.pipe(
v.union([
v.instance(ConfirmedTransaction, 'expect ConfirmedTransaction'),
v.pipe(
v.string('expect confirmed Transaction base64 as string type'),
v.base64('expect to be valid base64'),
),
v.object({
base64: v.pipe(
v.string('expect confirmed Transaction base64 as string type'),
v.base64('expect to be valid base64'),
),
communityId: uuidv4Schema,
}),
]),
v.transform<string | ConfirmedTransaction, ConfirmedTransaction>(
(data: string | ConfirmedTransaction) => {
v.transform<ConfirmedTransaction | { base64: string; communityId: Uuidv4 }, ConfirmedTransaction>(
(data: string | ConfirmedTransaction | { base64: string; communityId: Uuidv4 }) => {
if (data instanceof ConfirmedTransaction) {
return data
}
return confirmedTransactionFromBase64(data)
if (typeof data === 'object' && 'base64' in data && 'communityId' in data) {
return confirmedTransactionFromBase64(data.base64, data.communityId)
}
throw new Error('invalid data, community id missing, couldn\'t deserialize')
},
),
)

View File

@ -69,9 +69,10 @@ export const appRoutes = new Elysia()
// check if account exists by user, call example:
// GET /isAccountExist/by-user/0.0.21732/408780b2-59b3-402a-94be-56a4f4f4e8ec/0
.get(
'/isAccountExist/by-user/:communityTopicId/:userUuid/:accountNr',
async ({ params: { communityTopicId, userUuid, accountNr } }) => ({
'/isAccountExist/by-user/:communityId/:communityTopicId/:userUuid/:accountNr',
async ({ params: { communityId, communityTopicId, userUuid, accountNr } }) => ({
exists: await isAccountExist({
communityId,
communityTopicId,
account: { userUuid, accountNr },
}),
@ -84,9 +85,10 @@ export const appRoutes = new Elysia()
// check if account exists by seed, call example:
// GET /isAccountExist/by-seed/0.0.21732/0c4676adfd96519a0551596c
.get(
'/isAccountExist/by-seed/:communityTopicId/:seed',
async ({ params: { communityTopicId, seed } }) => ({
'/isAccountExist/by-seed/:communityId/:communityTopicId/:seed',
async ({ params: { communityId, communityTopicId, seed } }) => ({
exists: await isAccountExist({
communityId,
communityTopicId,
seed,
}),
@ -145,7 +147,7 @@ async function isAccountExist(identifierAccount: IdentifierAccountInput): Promis
// ask gradido node server for account type, if type !== NONE account exist
const addressType = await GradidoNodeClient.getInstance().getAddressType(
publicKey.convertToHex(),
identifierAccountParsed.communityTopicId,
identifierAccountParsed.communityId,
)
const exists = addressType !== AddressType_NONE
const endTime = Date.now()

View File

@ -3,6 +3,7 @@ import { t } from 'elysia'
import { hieroIdSchema, uuidv4Schema } from '../schemas/typeGuard.schema'
export const accountIdentifierUserTypeBoxSchema = t.Object({
communityId: TypeBoxFromValibot(uuidv4Schema),
communityTopicId: TypeBoxFromValibot(hieroIdSchema),
userUuid: TypeBoxFromValibot(uuidv4Schema),
accountNr: t.Number({ min: 0 }),
@ -10,6 +11,7 @@ export const accountIdentifierUserTypeBoxSchema = t.Object({
// identifier for a gradido account created by transaction link / deferred transfer
export const accountIdentifierSeedTypeBoxSchema = t.Object({
communityId: TypeBoxFromValibot(uuidv4Schema),
communityTopicId: TypeBoxFromValibot(hieroIdSchema),
seed: TypeBoxFromValibot(uuidv4Schema),
})

View File

@ -9,7 +9,7 @@ export function checkFileExist(filePath: string): boolean {
fs.accessSync(filePath, fs.constants.R_OK | fs.constants.W_OK)
return true
} catch (_err) {
// logger.debug(`file ${filePath} does not exist: ${_err}`)
logger.debug(`file ${filePath} does not exist: ${_err}`)
return false
}
}

View File

@ -6,14 +6,15 @@ import {
} from 'gradido-blockchain-js'
import { AccountType } from '../data/AccountType.enum'
import { AddressType } from '../data/AddressType.enum'
import { Uuidv4 } from '../schemas/typeGuard.schema'
export const confirmedTransactionFromBase64 = (base64: string): ConfirmedTransaction => {
export const confirmedTransactionFromBase64 = (base64: string, communityId: Uuidv4): ConfirmedTransaction => {
const confirmedTransactionBinaryPtr = MemoryBlock.createPtr(MemoryBlock.fromBase64(base64))
const deserializer = new InteractionDeserialize(
confirmedTransactionBinaryPtr,
DeserializeType_CONFIRMED_TRANSACTION,
)
deserializer.run()
deserializer.run(communityId)
const confirmedTransaction = deserializer.getConfirmedTransaction()
if (!confirmedTransaction) {
throw new Error("invalid data, couldn't deserialize")