diff --git a/package.json b/package.json index 34088cc..9135f0f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ipdw", - "version": "3.1.6", + "version": "3.1.7", "author": "humandataincome", "type": "module", "main": "./dist/node/index.js", diff --git a/src/core/storage/algorand.storage.ts b/src/core/storage/algorand.storage.ts index 4038295..43003ae 100644 --- a/src/core/storage/algorand.storage.ts +++ b/src/core/storage/algorand.storage.ts @@ -26,12 +26,14 @@ export class AlgorandStorageProvider implements StorageProvider { private rwLock = new ReadWriteLock(); private account: algosdk.Account; - private readonly applicationId: bigint; + private applicationId: bigint; private readonly client: algosdk.Algodv2; + private readonly contractName: string; - constructor(account: Account, applicationId: bigint, client: algosdk.Algodv2) { + constructor(account: Account, applicationId: bigint, contractName: string, client: algosdk.Algodv2) { this.account = account; this.applicationId = applicationId; + this.contractName = contractName; this.client = client; } @@ -42,12 +44,6 @@ export class AlgorandStorageProvider implements StorageProvider { const account = algosdk.mnemonicToSecretKey(algosdk.secretKeyToMnemonic(Buffer.from(privateKey.slice(2), 'hex'))); debug('ALGO Address is', account.addr); - const accountInfo = await client.accountInformation(account.addr).do(); - const balance = accountInfo.amount / ALGORAND_TOKEN_UNIT; - debug('ALGO Balance is', balance); - if (balance < 4) // 0.001 ALGO just for deploy - throw Error('Keep at least 4 ALGO on the wallet'); - let resApplicationId: bigint | undefined = undefined; let nextToken: string | undefined = ''; do { @@ -71,18 +67,28 @@ export class AlgorandStorageProvider implements StorageProvider { nextToken = response.nextToken; } while (nextToken); + return new AlgorandStorageProvider(account, resApplicationId!, contractName, client); + } + + public async setup() { + const accountInfo = await this.client.accountInformation(this.account.addr).do(); + + const balance = accountInfo.amount / ALGORAND_TOKEN_UNIT; + debug('ALGO Balance is', balance); + if (balance < 4) // 0.001 ALGO just for deploy + throw Error('Keep at least 4 ALGO on the wallet'); - if (resApplicationId === undefined) { + if (this.applicationId === undefined) { const appArgs = [ - new TextEncoder().encode(contractName) + new TextEncoder().encode(this.contractName) ]; - const compiledApprovalProgram = await client.compile(Buffer.from(ALGORAND_STORAGE_APPROVAL_CODE, 'base64')).do(); - const compiledClearProgram = await client.compile(Buffer.from(ALGORAND_STORAGE_CLEAR_CODE, 'base64')).do(); - const suggestedParams = await client.getTransactionParams().do(); + const compiledApprovalProgram = await this.client.compile(Buffer.from(ALGORAND_STORAGE_APPROVAL_CODE, 'base64')).do(); + const compiledClearProgram = await this.client.compile(Buffer.from(ALGORAND_STORAGE_CLEAR_CODE, 'base64')).do(); + const suggestedParams = await this.client.getTransactionParams().do(); const txn = algosdk.makeApplicationCreateTxnFromObject({ - sender: account.addr, + sender: this.account.addr, suggestedParams: suggestedParams, onComplete: algosdk.OnApplicationComplete.NoOpOC, approvalProgram: new Uint8Array(Buffer.from(compiledApprovalProgram.result, "base64")), @@ -94,33 +100,31 @@ export class AlgorandStorageProvider implements StorageProvider { appArgs: appArgs }); - const signedTxn = txn.signTxn(account.sk); - const {txid} = await client.sendRawTransaction(signedTxn).do(); - const confirmedTxn = await algosdk.waitForConfirmation(client, txid, 4); + const signedTxn = txn.signTxn(this.account.sk); + const {txid} = await this.client.sendRawTransaction(signedTxn).do(); + const confirmedTxn = await algosdk.waitForConfirmation(this.client, txid, 4); - resApplicationId = confirmedTxn.applicationIndex; - debug("Created Application ID:", resApplicationId); + this.applicationId = confirmedTxn.applicationIndex!; + debug("Created Application ID:", this.applicationId); } - const applicationAddress = algosdk.getApplicationAddress(resApplicationId!); - const applicationAccountInfo = await client.accountInformation(applicationAddress).do(); + const applicationAddress = algosdk.getApplicationAddress(this.applicationId!); + const applicationAccountInfo = await this.client.accountInformation(applicationAddress).do(); const applicationBalance = applicationAccountInfo.amount / ALGORAND_TOKEN_UNIT; debug('Application ALGO Balance is', applicationBalance); if (applicationBalance < 1) { const totalCost = 3n * ALGORAND_TOKEN_UNIT; const txn = algosdk.makePaymentTxnWithSuggestedParamsFromObject({ - sender: account.addr, + sender: this.account.addr, receiver: applicationAddress, amount: totalCost, - suggestedParams: await client.getTransactionParams().do(), + suggestedParams: await this.client.getTransactionParams().do(), }) - const signedTxn = txn.signTxn(account.sk); - const {txid} = await client.sendRawTransaction(signedTxn).do(); - await algosdk.waitForConfirmation(client, txid, 4); + const signedTxn = txn.signTxn(this.account.sk); + const {txid} = await this.client.sendRawTransaction(signedTxn).do(); + await algosdk.waitForConfirmation(this.client, txid, 4); } - - return new AlgorandStorageProvider(account, resApplicationId!, client); } private static hashKey(key: string): Uint8Array { diff --git a/src/core/storage/bnbgreenfield.storage.ts b/src/core/storage/bnbgreenfield.storage.ts index 0cfdac2..3de394d 100644 --- a/src/core/storage/bnbgreenfield.storage.ts +++ b/src/core/storage/bnbgreenfield.storage.ts @@ -42,50 +42,56 @@ export class BNBGreenfieldStorageProvider implements StorageProvider { const address = web3.eth.accounts.privateKeyToAccount(privateKey).address; - const balance = await client.account.getAccountBalance({ - address: address, + // To check buckets go to https://testnet.dcellar.io/buckets + return new BNBGreenfieldStorageProvider(privateKey, address, bucketName, primarySP.endpoint, client); + } + + public async setup() { + const balance = await this.client.account.getAccountBalance({ + address: this.address, denom: 'BNB', }); - // To check buckets go to https://testnet.dcellar.io/buckets if (BigInt(balance.balance!.amount) < 10 ** (18 - 2)) { throw Error('Keep at least 0.01 BNB on the wallet on Greenfield network, use https://greenfield.bnbchain.org/en/bridge?type=transfer-in'); } - const quota = await client.bucket.getBucketReadQuota({ - bucketName: bucketName + const quota = await this.client.bucket.getBucketReadQuota({ + bucketName: this.bucketName }, { type: 'ECDSA', - privateKey: privateKey, + privateKey: this.privateKey, }); if (quota.body) { const availableQuota = (quota.body!.freeQuota - quota.body!.freeConsumedSize) + (quota.body!.readQuota - quota.body!.consumedQuota) + (quota.body!.monthlyFreeQuota - quota.body!.monthlyQuotaConsumedSize); if (availableQuota < 1024 * 1024 * 128) { // 128 Mb - const updateBucketTx = await client.bucket.updateBucketInfo({ - bucketName: bucketName, - operator: address, + const updateBucketTx = await this.client.bucket.updateBucketInfo({ + bucketName: this.bucketName, + operator: this.address, chargedReadQuota: Long.fromNumber(1024 * 1024 * 512).toString(), // 512 Mb visibility: VisibilityType.VISIBILITY_TYPE_PRIVATE, - paymentAddress: address, + paymentAddress: this.address, }); - await BNBGreenfieldStorageProvider.SendTransaction(updateBucketTx, privateKey); + await BNBGreenfieldStorageProvider.SendTransaction(updateBucketTx, this.privateKey); } } else { - const createBucketTx = await client.bucket.createBucket({ - bucketName: bucketName, - creator: address, + const sps = await this.client.sp.getStorageProviders(); + const sortedSps = sps.sort((a, b) => a.id - b.id); + const primarySP = sortedSps[0]; + + const createBucketTx = await this.client.bucket.createBucket({ + bucketName: this.bucketName, + creator: this.address, visibility: VisibilityType.VISIBILITY_TYPE_PRIVATE, chargedReadQuota: Long.fromNumber(1024 * 1024 * 512), // 512 Gb primarySpAddress: primarySP.operatorAddress, - paymentAddress: address, + paymentAddress: this.address, }, ); - await BNBGreenfieldStorageProvider.SendTransaction(createBucketTx, privateKey); + await BNBGreenfieldStorageProvider.SendTransaction(createBucketTx, this.privateKey); } - - return new BNBGreenfieldStorageProvider(privateKey, address, bucketName, primarySP.endpoint, client); } private static async SendTransaction(transaction: TxResponse, privateKey: string): Promise { diff --git a/src/core/storage/cere.storage.ts b/src/core/storage/cere.storage.ts index 81a8288..4811350 100644 --- a/src/core/storage/cere.storage.ts +++ b/src/core/storage/cere.storage.ts @@ -1,7 +1,7 @@ import {DdcClient, File, FileUri, Signer} from '@cere-ddc-sdk/ddc-client'; import {CnsRecord, NodeInterface} from '@cere-ddc-sdk/ddc'; import {StorageProvider} from "./"; -import {Blockchain} from "@cere-ddc-sdk/blockchain"; +import {Blockchain, Cluster} from "@cere-ddc-sdk/blockchain"; import {Bucket} from "@cere-ddc-sdk/blockchain/src/types"; import Debug from "debug"; @@ -21,12 +21,16 @@ export const CERE_TOKEN_UNIT = 10_000_000_000n; export class CereStorageProvider implements StorageProvider { private ddcClient: DdcClient; private ddcNode: NodeInterface; - private readonly bucketId: bigint; + private bucketId: bigint; + private cluster: Cluster; + private bucketName: string; - private constructor(ddcClient: DdcClient, ddcNode: NodeInterface, bucketId: bigint) { + private constructor(ddcClient: DdcClient, ddcNode: NodeInterface, cluster: Cluster, bucketId: bigint, bucketName: string) { this.ddcClient = ddcClient; this.ddcNode = ddcNode; + this.cluster = cluster; this.bucketId = bucketId; + this.bucketName = bucketName; } public static async Init(privateKey: string, rpcUrl: string = CERE_MAINNET_RPC_URL, indexerUrl: string = CERE_MAINNET_INDEXER_URL, bucketName: string = CERE_DEFAULT_BUCKET_NAME): Promise { @@ -56,24 +60,28 @@ export class CereStorageProvider implements StorageProvider { break; } } - const deposit = await ddcClient.getDeposit(); + + + return new CereStorageProvider(ddcClient, ddcNode, selectedCluster, resBucketId, bucketName); + } + + public async setup() { + const deposit = await this.ddcClient.getDeposit(); if (deposit < 1n * CERE_TOKEN_UNIT) { - const balance = await ddcClient.getBalance(); + const balance = await this.ddcClient.getBalance(); if (balance < 5n * CERE_TOKEN_UNIT) throw Error('Keep at least 5 CERE on the wallet, they will be automatically deposited for storage when needed. Use https://bridge.cere.network/transfer'); - await ddcClient.depositBalance(5n * CERE_TOKEN_UNIT); + await this.ddcClient.depositBalance(5n * CERE_TOKEN_UNIT); } - if (resBucketId === 0n) { - resBucketId = await ddcClient.createBucket(selectedCluster.clusterId, {isPublic: false}); - debug('Bucket created with id', resBucketId) - const bucketNameFileUri = await ddcClient.store(resBucketId, new File(new TextEncoder().encode(bucketName))) - await ddcNode.storeCnsRecord(resBucketId, new CnsRecord(bucketNameFileUri.cid, '__name__')); + if (this.bucketId === 0n) { + this.bucketId = await this.ddcClient.createBucket(this.cluster.clusterId, {isPublic: false}); + debug('Bucket created with id', this.bucketId) + const bucketNameFileUri = await this.ddcClient.store(this.bucketId, new File(new TextEncoder().encode(this.bucketName))) + await this.ddcNode.storeCnsRecord(this.bucketId, new CnsRecord(bucketNameFileUri.cid, '__name__')); } - - return new CereStorageProvider(ddcClient, ddcNode, resBucketId); } private static async GetBucketList(indexerUrl: string, ownerId: string): Promise { diff --git a/test/algorand.test.ts b/test/algorand.test.ts index cbe8bbb..62cd747 100644 --- a/test/algorand.test.ts +++ b/test/algorand.test.ts @@ -3,12 +3,20 @@ import {ALGORAND_TESTNET_INDEXER_URL, ALGORAND_TESTNET_SERVER_URL, AlgorandStora async function main(): Promise { const provider = await AlgorandStorageProvider.Init('0xb577c4367d79f1a7a0c8353f7937d601758d92c35df958781d72d70f9177e52f', ALGORAND_TESTNET_SERVER_URL, ALGORAND_TESTNET_INDEXER_URL); - console.log('set', await provider.set("myKey", new TextEncoder().encode("myValue"))) - console.log('get', new TextDecoder().decode(await provider.get("myKey"))); - console.log('has', await provider.has("myKey")); - console.log('ls', await provider.ls()); - console.log('clear', await provider.clear()); - console.log('has not', await provider.has("myKey")); + try { + await provider.setup(); + + console.log('set', await provider.set("myKey", new TextEncoder().encode("myValue"))) + console.log('get', new TextDecoder().decode(await provider.get("myKey"))); + console.log('has', await provider.has("myKey")); + console.log('ls', await provider.ls()); + console.log('clear', await provider.clear()); + console.log('has not', await provider.has("myKey")); + } catch (e) { + console.log(e); + + console.log('getAccountInfo', await provider.getAccountInfo()) + } } main() diff --git a/test/bnbgreenfield.test.ts b/test/bnbgreenfield.test.ts index b8ddfdd..40fcf8e 100644 --- a/test/bnbgreenfield.test.ts +++ b/test/bnbgreenfield.test.ts @@ -3,12 +3,21 @@ import {BNBGreenfieldStorageProvider, GREENFIELD_TESTNET_CHAIN_ID, GREENFIELD_TE async function main(): Promise { const provider = await BNBGreenfieldStorageProvider.Init('0xb577c4367d79f1a7a0c8353f7937d601758d92c35df958781d72d70f9177e52f', GREENFIELD_TESTNET_CHAIN_RPC_URL, GREENFIELD_TESTNET_CHAIN_ID); - console.log('set', await provider.set("myKey", new TextEncoder().encode("myValue"))) - console.log('get', new TextDecoder().decode(await provider.get("myKey"))); - console.log('has', await provider.has("myKey")); - console.log('ls', await provider.ls()); - console.log('clear', await provider.clear()); - console.log('has not', await provider.has("myKey")); + try { + await provider.setup(); + + console.log('set', await provider.set("myKey", new TextEncoder().encode("myValue"))) + console.log('get', new TextDecoder().decode(await provider.get("myKey"))); + console.log('has', await provider.has("myKey")); + console.log('ls', await provider.ls()); + console.log('clear', await provider.clear()); + console.log('has not', await provider.has("myKey")); + } catch (e) { + console.error(e); + + console.log('getAccountInfo', await provider.getAccountInfo()) + } + } main() diff --git a/test/cere.test.ts b/test/cere.test.ts index cb7e72e..baa402f 100644 --- a/test/cere.test.ts +++ b/test/cere.test.ts @@ -3,12 +3,21 @@ import {CERE_TESTNET_INDEXER_URL, CERE_TESTNET_RPC_URL, CereStorageProvider} fro async function main(): Promise { const provider = await CereStorageProvider.Init('hybrid label reunion only dawn maze asset draft cousin height flock nation', CERE_TESTNET_RPC_URL, CERE_TESTNET_INDEXER_URL); - console.log('set', await provider.set("myKey", new TextEncoder().encode("myValue"))) - console.log('get', new TextDecoder().decode(await provider.get("myKey"))); - console.log('has', await provider.has("myKey")); - console.log('ls', await provider.ls()); - console.log('clear', await provider.clear()); - console.log('has not', await provider.has("myKey")); + try { + await provider.setup(); + + console.log('set', await provider.set("myKey", new TextEncoder().encode("myValue"))) + console.log('get', new TextDecoder().decode(await provider.get("myKey"))); + console.log('has', await provider.has("myKey")); + console.log('ls', await provider.ls()); + console.log('clear', await provider.clear()); + console.log('has not', await provider.has("myKey")); + } catch (e) { + console.error(e); + + console.log('getAccountInfo', await provider.getAccountInfo()) + } + } main()