Skip to content

Commit 9e00f6b

Browse files
authored
Merge pull request #7 from hashed-io/feature/pallet/fund-admin/records
Feature/pallet/fund admin/records
2 parents 2bd1ade + 01620dc commit 9e00f6b

File tree

13 files changed

+677
-0
lines changed

13 files changed

+677
-0
lines changed

.github/workflows/opencommit.yml

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
name: 'OpenCommit Action'
2+
3+
on:
4+
push:
5+
# this list of branches is often enough,
6+
# but you may still ignore other public branches
7+
branches:
8+
- '!main'
9+
- '!master'
10+
- '!dev'
11+
- '!develop'
12+
13+
jobs:
14+
opencommit:
15+
name: OpenCommit
16+
runs-on: ubuntu-latest
17+
permissions: write-all
18+
steps:
19+
- name: Setup Node.js Environment
20+
uses: actions/setup-node@v2
21+
with:
22+
node-version: '16'
23+
- uses: actions/checkout@v3
24+
with:
25+
fetch-depth: 0
26+
- uses: di-sukharev/[email protected]
27+
with:
28+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
29+
30+
env:
31+
# set openAI api key in repo actions secrets,
32+
# for openAI keys go to: https://platform.openai.com/account/api-keys
33+
# for repo secret go to: <your_repo_url>/settings/secrets/actions
34+
OCO_OPENAI_API_KEY: ${{ secrets.OCO_OPENAI_API_KEY }}
35+
36+
# customization
37+
OCO_OPENAI_MAX_TOKENS: 500
38+
OCO_OPENAI_BASE_PATH: ''
39+
OCO_DESCRIPTION: true
40+
OCO_EMOJI: true
41+
OCO_MODEL: gpt-3.5-turbo
42+
OCO_LANGUAGE: en

Cargo.lock

Lines changed: 17 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ members = [
88
'pallets/fruniques',
99
'pallets/gated-marketplace',
1010
# 'parachain-runtime',
11+
'pallets/fund-admin',
12+
'pallets/fund-admin-records',
1113
'runtime',
1214
]
1315
[profile.release]
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
[package]
2+
name = "pallet-fund-admin-records"
3+
version = "4.0.0-dev"
4+
description = "Proxy Financial Pallet Records"
5+
authors = ["Hashed <https://github.com/hashed-io"]
6+
homepage = "https://hashed.io"
7+
edition = "2021"
8+
license = "Unlicense"
9+
publish = false
10+
repository = "https://github.com/hashed-io/hashed-substrate"
11+
12+
[package.metadata.docs.rs]
13+
targets = ["x86_64-unknown-linux-gnu"]
14+
15+
[dependencies]
16+
log = "0.4"
17+
codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [
18+
"derive",
19+
] }
20+
scale-info = { version = "2.0.1", default-features = false, features = [
21+
"derive"
22+
] }
23+
frame-support = { default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.38" }
24+
frame-system = { default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.38" }
25+
frame-benchmarking = { default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.38", optional = true }
26+
sp-runtime = { default-features = false, version = "7.0.0", git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.38" }
27+
pallet-timestamp = { default-features = false, version = "4.0.0-dev", git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.38" }
28+
29+
[dev-dependencies]
30+
sp-core = { default-features = false, version = "7.0.0", git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.38" }
31+
sp-io = { default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.38" }
32+
33+
[features]
34+
default = ["std"]
35+
std = [
36+
"codec/std",
37+
"scale-info/std",
38+
"frame-support/std",
39+
"frame-system/std",
40+
"frame-benchmarking/std",
41+
"pallet-timestamp/std"
42+
]
43+
44+
runtime-benchmarks = ["frame-benchmarking/runtime-benchmarks"]
45+
try-runtime = ["frame-support/try-runtime"]
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
# Fund Admin Records
2+
3+
The Fund Admin Records pallet is a Substrate-based blockchain pallet for recording and controlling different project records. It is written using Rust.
4+
5+
## Overview
6+
7+
The Fund Admin Pallet provides functionalities to store, retrieve, and manage project records. Each record contains a project id, hashed information of the data stored, table type indicating the table it belongs to, record type reflecting the type of operation performed, and creation date.
8+
9+
The unique record id is generated using a record's project id and its creation timestamp, ensuring the uniqueness of each data entry. Records are internally stored in a double map structure using the tuple (ProjectId, TableType) as the first key and the generated record ID as the second key.
10+
11+
## Terminology
12+
13+
- **ProjectId:** A unique identifier for each project. It's a bounded vector with a maximum length of 50 bytes.
14+
- **CreationDate:** Unix timestamp representing the creation time of a record.
15+
- **TableType:** This enum determines the type of table that the record belongs to. It can be Drawdown, RecoveryDrawdown, Revenue, or RecoveryRevenue.
16+
- **RecordType:** This enum determines the type of operation performed for the record. It can be Creation, Submit, Approve, Reject, Recovery, or Cancel.
17+
- **Records:** The storage item containing all the records. They are organized in a double map structure, which uses (ProjectId, TableType) as the first key and record ID as a second.
18+
19+
## Interface
20+
21+
### Types
22+
- **HashedInfo**: The hashed information related to the data stored.
23+
- **RecordCollection<T>**: A collection of records with maximum entries defined by the MaxRecordsAtTime parameter. Each record is a tuple (ProjectId, HashedInfo, TableType, RecordType).
24+
- **RecordData**: Structure stored in the double map for each record containing project_id, hashed_info, table_type, record_type, and creation_date.
25+
26+
### Helper functions
27+
- **do_add_record:** A function responsible for validating and inserting a new record into the storage, also ensures the uniqueness of the record id.
28+
- **get_timestamp_in_milliseconds:** A utility function to get the current timestamp in milliseconds.
29+
30+
### Callable functions
31+
- **set_signer_account:** To set the Signer account for making transactions.
32+
- **add_record:** Function to add a record(s) into storage.
33+
- **kill_storage:** Utility destructor for wiping out all the storage. Only intended for use in testing scenarios.
34+
35+
### Errors
36+
- **SignerAccountNotSet:** When signer account is not set for making transactions.
37+
- **SenderIsNotTheSignerAccount:** The sender of the transaction is not the same as the signer account.
38+
- **ProjectIdIsEmpty:** If project id is empty.
39+
- **HashedInfoIsEmpty:** If hashed information is empty.
40+
- **ProjectIdExceededMaxLength:** If project id has exceeded its maximum length of 50 bytes.
41+
- **HashedInfoExceededMaxLength:** If hashed information has exceeded its maximum length of 400 bytes.
42+
- **MaxRegistrationsAtATimeReached:** If the number of added records exceeds the limit specified in the Config trait.
43+
44+
### Events
45+
- **RecordAdded:** An event indicating a candidate was added, which emits the project id, table type, record type, and the generated unique record id.
46+
47+
## Usage
48+
49+
### Rust Developers
50+
To leverage this pallet, developers can either add records using the `add_record` callable function or retrieve them using the Records getter by providing the keys.
51+
52+
### Polkadot-js Users
53+
The stored records can be queried through Polkadot-js CLI by providing suitable keys.
54+
55+
## Conclusion
56+
57+
The Fund Admin Records pallet delivers an essential set of tools to aid tracking a project's crucial records on the Substrate-based blockchain efficiently and securely. Be aware the `kill_storage` function provides irreversible data deletion, and it should only be used in testing scenarios or with extreme caution. This pallet ensures that all interactions are safeguarded with necessary permissions, ensuring stored data's integrity.
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
//! Benchmarking setup for pallet-template
2+
3+
use super::*;
4+
5+
#[allow(unused)]
6+
use crate::Pallet as Template;
7+
use frame_benchmarking::{benchmarks, whitelisted_caller};
8+
use frame_system::RawOrigin;
9+
10+
benchmarks! {
11+
do_something {
12+
let s in 0 .. 100;
13+
let caller: T::AccountId = whitelisted_caller();
14+
}: _(RawOrigin::Signed(caller), s)
15+
verify {
16+
assert_eq!(Something::<T>::get(), Some(s));
17+
}
18+
19+
impl_benchmark_test_suite!(Template, crate::mock::new_test_ext(), crate::mock::Test);
20+
}
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
use super::*;
2+
use frame_support::pallet_prelude::*;
3+
use frame_support::traits::Time;
4+
use frame_support::sp_io::hashing::blake2_256;
5+
6+
use crate::types::*;
7+
8+
impl<T: Config> Pallet<T> {
9+
/*---- Offchain extrinsics ----*/
10+
pub fn do_add_record(
11+
records: RecordCollection<T>,
12+
) -> DispatchResult{
13+
for record in records.iter().cloned() {
14+
// Validations
15+
ensure!(!record.0.is_empty(), Error::<T>::ProjectIdIsEmpty);
16+
ensure!(!record.1.is_empty(), Error::<T>::HashedInfoIsEmpty);
17+
18+
let project_id_validated = ProjectId::try_from(record.0.clone())
19+
.map_err(|_| Error::<T>::ProjectIdExceededMaxLength)?;
20+
21+
let hashed_info_validated = HashedInfo::try_from(record.1.clone())
22+
.map_err(|_| Error::<T>::HashedInfoExceededMaxLength)?;
23+
24+
// Get timestamp
25+
let creation_date: CreationDate = Self::get_timestamp_in_milliseconds().ok_or(Error::<T>::TimestampError)?;
26+
27+
let record_id: Id = (
28+
record.0.clone(),
29+
record.1.clone(),
30+
record.2,
31+
record.3,
32+
creation_date.clone()
33+
).using_encoded(blake2_256);
34+
35+
// Ensure the generated id is unique
36+
ensure!(!Records::<T>::contains_key((record.0.clone(), record.2), record_id), Error::<T>::IdAlreadyExists);
37+
38+
let record_data = RecordData {
39+
project_id: project_id_validated,
40+
hashed_info: hashed_info_validated,
41+
table_type: record.2,
42+
record_type: record.3,
43+
creation_date,
44+
};
45+
46+
// Insert the record into the storage
47+
<Records<T>>::insert(
48+
(record.0.clone(), record.2),
49+
&record_id,
50+
record_data
51+
);
52+
53+
Self::deposit_event(Event::RecordAdded(record.0, record.2, record.3, record_id));
54+
}
55+
Ok(())
56+
}
57+
58+
fn get_timestamp_in_milliseconds() -> Option<u64> {
59+
let timestamp: u64 = T::Timestamp::now().into();
60+
61+
Some(timestamp)
62+
}
63+
64+
}

0 commit comments

Comments
 (0)