1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758
#![cfg_attr(not(feature = "std"), no_std)]
pub use pallet::*;
#[cfg(test)]
mod mock;
#[cfg(test)]
mod tests;
mod functions;
pub mod migration;
mod types;
#[frame_support::pallet]
pub mod pallet {
use frame_support::{
pallet_prelude::{ValueQuery, *},
traits::{Currency, Time},
BoundedVec,
};
use frame_system::pallet_prelude::*;
use scale_info::prelude::vec;
use sp_runtime::sp_std::vec::Vec;
use sp_runtime::traits::Scale;
const STORAGE_VERSION: StorageVersion = StorageVersion::new(1);
use crate::types::*;
use pallet_rbac::types::RoleBasedAccessControl;
pub type BalanceOf<T> =
<<T as Config>::Currency as Currency<<T as frame_system::Config>::AccountId>>::Balance;
#[pallet::config]
pub trait Config: frame_system::Config {
type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
type Moment: Parameter
+ Default
+ Scale<Self::BlockNumber, Output = Self::Moment>
+ Copy
+ MaxEncodedLen
+ scale_info::StaticTypeInfo
+ Into<u64>;
type Timestamp: Time<Moment = Self::Moment>;
type Rbac: RoleBasedAccessControl<Self::AccountId>;
type RemoveOrigin: EnsureOrigin<Self::RuntimeOrigin>;
type Currency: Currency<Self::AccountId>;
#[pallet::constant]
type MaxDocuments: Get<u32>;
#[pallet::constant]
type MaxProjectsPerUser: Get<u32>;
#[pallet::constant]
type MaxUserPerProject: Get<u32>;
#[pallet::constant]
type MaxBuildersPerProject: Get<u32>;
#[pallet::constant]
type MaxInvestorsPerProject: Get<u32>;
#[pallet::constant]
type MaxIssuersPerProject: Get<u32>;
#[pallet::constant]
type MaxRegionalCenterPerProject: Get<u32>;
#[pallet::constant]
type MaxDrawdownsPerProject: Get<u32>;
#[pallet::constant]
type MaxTransactionsPerDrawdown: Get<u32>;
#[pallet::constant]
type MaxRegistrationsAtTime: Get<u32>;
#[pallet::constant]
type MaxExpendituresPerProject: Get<u32>;
#[pallet::constant]
type MaxProjectsPerInvestor: Get<u32>;
#[pallet::constant]
type MaxBanksPerProject: Get<u32>;
#[pallet::constant]
type MaxJobEligiblesByProject: Get<u32>;
#[pallet::constant]
type MaxRevenuesByProject: Get<u32>;
#[pallet::constant]
type MaxTransactionsPerRevenue: Get<u32>;
#[pallet::constant]
type MaxStatusChangesPerDrawdown: Get<u32>;
#[pallet::constant]
type MaxStatusChangesPerRevenue: Get<u32>;
#[pallet::constant]
type MaxRecoveryChanges: Get<u32>;
#[pallet::constant]
type MinAdminBalance: Get<BalanceOf<Self>>;
#[pallet::constant]
type TransferAmount: Get<BalanceOf<Self>>;
}
#[pallet::pallet]
#[pallet::storage_version(STORAGE_VERSION)]
#[pallet::generate_store(pub(super) trait Store)]
pub struct Pallet<T>(_);
/* --- Onchain storage section --- */
#[pallet::storage]
#[pallet::getter(fn global_scope)]
pub(super) type GlobalScope<T> = StorageValue<
_,
[u8; 32], // Value global scope id
ValueQuery,
>;
#[pallet::storage]
#[pallet::getter(fn users_info)]
pub(super) type UsersInfo<T: Config> = StorageMap<
_,
Blake2_128Concat,
T::AccountId, // Key account_id
UserData<T>, // Value UserData<T>
OptionQuery,
>;
#[pallet::storage]
#[pallet::getter(fn projects_info)]
pub(super) type ProjectsInfo<T: Config> = StorageMap<
_,
Identity,
ProjectId, // Key project_id
ProjectData<T>, // Value ProjectData<T>
OptionQuery,
>;
#[pallet::storage]
#[pallet::getter(fn users_by_project)]
pub(super) type UsersByProject<T: Config> = StorageMap<
_,
Identity,
ProjectId, // Key project_id
BoundedVec<T::AccountId, T::MaxUserPerProject>, // Value users
ValueQuery,
>;
#[pallet::storage]
#[pallet::getter(fn projects_by_user)]
pub(super) type ProjectsByUser<T: Config> = StorageMap<
_,
Blake2_128Concat,
T::AccountId, // Key account_id
BoundedVec<[u8; 32], T::MaxProjectsPerUser>, // Value projects
ValueQuery,
>;
#[pallet::storage]
#[pallet::getter(fn expenditures_info)]
pub(super) type ExpendituresInfo<T: Config> = StorageMap<
_,
Identity,
ExpenditureId, // Key expenditure_id
ExpenditureData, // Value ExpenditureData<T>
OptionQuery,
>;
#[pallet::storage]
#[pallet::getter(fn expenditures_by_project)]
pub(super) type ExpendituresByProject<T: Config> = StorageMap<
_,
Identity,
ProjectId, // Key project_id
BoundedVec<[u8; 32], T::MaxExpendituresPerProject>, // Value expenditures
ValueQuery,
>;
#[pallet::storage]
#[pallet::getter(fn drawdowns_info)]
pub(super) type DrawdownsInfo<T: Config> = StorageMap<
_,
Identity,
DrawdownId, // Key drawdown id
DrawdownData<T>, // Value DrawdownData<T>
OptionQuery,
>;
#[pallet::storage]
#[pallet::getter(fn drawdowns_by_project)]
pub(super) type DrawdownsByProject<T: Config> = StorageMap<
_,
Identity,
ProjectId, // Key project_id
BoundedVec<DrawdownId, T::MaxDrawdownsPerProject>, // Value Drawdowns
ValueQuery,
>;
#[pallet::storage]
#[pallet::getter(fn transactions_info)]
pub(super) type TransactionsInfo<T: Config> = StorageMap<
_,
Identity,
TransactionId, // Key transaction id
TransactionData<T>, // Value TransactionData<T>
OptionQuery,
>;
#[pallet::storage]
#[pallet::getter(fn transactions_by_drawdown)]
pub(super) type TransactionsByDrawdown<T: Config> = StorageDoubleMap<
_,
Identity,
ProjectId, //K1: project id
Identity,
DrawdownId, //K2: drawdown id
BoundedVec<TransactionId, T::MaxTransactionsPerDrawdown>, // Value transactions
ValueQuery,
>;
#[pallet::storage]
#[pallet::getter(fn job_eligibles_info)]
pub(super) type JobEligiblesInfo<T: Config> = StorageMap<
_,
Identity,
JobEligibleId, // Key transaction id
JobEligibleData, // Value JobEligibleData
OptionQuery,
>;
#[pallet::storage]
#[pallet::getter(fn job_eligibles_by_project)]
pub(super) type JobEligiblesByProject<T: Config> = StorageMap<
_,
Identity,
ProjectId, // Key project_id
BoundedVec<JobEligibleId, T::MaxJobEligiblesByProject>, // Value job eligibles
ValueQuery,
>;
#[pallet::storage]
#[pallet::getter(fn revenues_info)]
pub(super) type RevenuesInfo<T: Config> = StorageMap<
_,
Identity,
RevenueId, // Key revenue id
RevenueData<T>, // Value RevenueData<T>
OptionQuery,
>;
#[pallet::storage]
#[pallet::getter(fn revenues_by_project)]
pub(super) type RevenuesByProject<T: Config> = StorageMap<
_,
Identity,
ProjectId, // Key project_id
BoundedVec<RevenueId, T::MaxDrawdownsPerProject>, // Value Revenues
ValueQuery,
>;
#[pallet::storage]
#[pallet::getter(fn revenue_transactions_info)]
pub(super) type RevenueTransactionsInfo<T: Config> = StorageMap<
_,
Identity,
RevenueTransactionId, // Key revenue transaction id
RevenueTransactionData<T>, // Value RevenueTransactionData<T>
OptionQuery,
>;
#[pallet::storage]
#[pallet::getter(fn transactions_by_revenue)]
pub(super) type TransactionsByRevenue<T: Config> = StorageDoubleMap<
_,
Identity,
ProjectId, //K1: project id
Identity,
RevenueId, //K2: revenue id
BoundedVec<RevenueTransactionId, T::MaxTransactionsPerRevenue>, // Value revenue transactions
ValueQuery,
>;
// E V E N T S
// ------------------------------------------------------------------------------------------------------------
#[pallet::event]
#[pallet::generate_deposit(pub(super) fn deposit_event)]
pub enum Event<T: Config> {
/// Proxy initial setup completed using the sudo pallet
ProxySetupCompleted,
/// Project was created successfully
ProjectCreated(T::AccountId, ProjectId),
/// The selected roject was edited successfully
ProjectEdited(T::AccountId, ProjectId),
/// The selected project was deleted successfully
ProjectDeleted(T::AccountId, ProjectId),
/// Administrator was registered successfully using the sudo pallet
AdministratorAssigned(T::AccountId),
/// Administrator was removed successfully using the sudo pallet
AdministratorRemoved(T::AccountId),
/// The user was assigned to the selected project
UserAssignmentCompleted(T::AccountId, ProjectId),
/// The user was unassigned to the selected project
UserUnassignmentCompleted(T::AccountId, ProjectId),
/// Users extrinsic was executed, individual CUDActions were applied
UsersExecuted(T::AccountId),
/// A new user account was created successfully
UserCreated(T::AccountId),
/// The selected user was edited successfully
UserUpdated(T::AccountId),
/// The selected user was deleted successfully
UserDeleted(T::AccountId),
/// An array of expenditures was executed depending on the CUDAction
ExpendituresExecuted(T::AccountId, ProjectId),
/// Expenditure was created successfully
ExpenditureCreated(ProjectId, ExpenditureId),
/// Expenditure was updated successfully
ExpenditureUpdated(ProjectId, ExpenditureId),
/// Expenditure was deleted successfully
ExpenditureDeleted(ProjectId, ExpenditureId),
/// An array of transactions was executed depending on the CUDAction
TransactionsExecuted(ProjectId, DrawdownId),
/// Transaction was created successfully
TransactionCreated(ProjectId, DrawdownId, TransactionId),
/// Transaction was edited successfully
TransactionEdited(ProjectId, DrawdownId, TransactionId),
/// Transaction was deleted successfully
TransactionDeleted(ProjectId, DrawdownId, TransactionId),
/// Assign users extrinsic was completed successfully
UsersAssignationExecuted(T::AccountId, ProjectId),
/// Drawdowns were initialized successfully at the beginning of the project
DrawdownsInitialized(T::AccountId, ProjectId),
/// Drawdown was created successfully
DrawdownCreated(ProjectId, DrawdownId),
/// Drawdown was submitted successfully
DrawdownSubmitted(ProjectId, DrawdownId),
/// Drawdown was approved successfully
DrawdownApproved(ProjectId, DrawdownId),
/// Drawdown was rejected successfully
DrawdownRejected(ProjectId, DrawdownId),
/// Drawdown was cancelled successfully
DrawdownSubmissionCancelled(ProjectId, DrawdownId),
/// Bulkupload drawdown was submitted successfully
BulkUploadSubmitted(ProjectId, DrawdownId),
/// An array of adjustments was executed depending on the CUDAction
InflationRateAdjusted(T::AccountId),
/// An array of job eligibles was executed depending on the CUDAction
JobEligiblesExecuted(T::AccountId, ProjectId),
/// Job eligible was created successfully
JobEligibleCreated(ProjectId, JobEligibleId),
/// Job eligible was updated successfully
JobEligibleUpdated(ProjectId, JobEligibleId),
/// Job eligible was deleted successfully
JobEligibleDeleted(ProjectId, JobEligibleId),
/// Revenue transaction was created successfully
RevenueTransactionCreated(ProjectId, RevenueId, RevenueTransactionId),
/// Revenue transaction was updated successfully
RevenueTransactionUpdated(ProjectId, RevenueId, RevenueTransactionId),
/// Revenue transaction was deleted successfully
RevenueTransactionDeleted(ProjectId, RevenueId, RevenueTransactionId),
/// An array of revenue transactions was executed depending on the CUDAction
RevenueTransactionsExecuted(ProjectId, RevenueId),
/// Revenue was created successfully
RevenueCreated(ProjectId, RevenueId),
/// Revenue was submitted successfully
RevenueSubmitted(ProjectId, RevenueId),
/// Revenue was approved successfully
RevenueApproved(ProjectId, RevenueId),
/// Revenue was rejected successfully
RevenueRejected(ProjectId, RevenueId),
/// Bank's confirming documents were uploaded successfully
BankDocumentsUploaded(ProjectId, DrawdownId),
/// Bank's confirming documents were updated successfully
BankDocumentsUpdated(ProjectId, DrawdownId),
/// Bank's confirming documents were deleted successfully
BankDocumentsDeleted(ProjectId, DrawdownId),
/// Error recovery for revenues was executed successfully
RevenueErrorRecoveryExecuted(ProjectId, RevenueId),
/// Error recovery for drawdowns was executed successfully
DrawdownErrorRecoveryExecuted(ProjectId, DrawdownId),
}
// E R R O R S
// ------------------------------------------------------------------------------------------------------------
#[pallet::error]
pub enum Error<T> {
/// FieldName is empty
EmptyFieldName,
/// FieldDescription is empty
EmptyFieldDescription,
/// FieldName is too long
FieldNameTooLong,
/// Array of users is empty
EmptyUsers,
/// CID is empty
EmptyFieldCID,
/// Array of banks is empty
EmptyFieldBanks,
/// The private group id is empty
PrivateGroupIdEmpty,
/// Array of users to be assigned to a project is empty
EmptyUsersAssignation,
/// Field address project is empty
EmptyProjectAddress,
/// No value was found for the global scope
NoGlobalScopeValueWasFound,
/// Project ID is already in use
ProjectIdAlreadyInUse,
/// Timestamp was not genereated correctly
TimestampError,
/// Completion date must be later than creation date
CompletionDateMustBeLater,
/// User is already registered in the site
UserAlreadyRegistered,
/// Project was not found
ProjectNotFound,
/// Project is not active anymore
ProjectIsAlreadyCompleted,
/// Project has no drawdowns
ProjectHasNoDrawdowns,
/// Project has no expenditures
ProjectHasNoExpenditures,
/// Project has no users
ProjectHasNoUsers,
/// Project has no job eligibles
ProjectHasNoJobEligibles,
/// Project has no revenues
ProjectHasNoRevenues,
/// Can not delete a completed project
CannotDeleteCompletedProject,
/// User is not registered
UserNotRegistered,
/// User has been already added to the project
UserAlreadyAssignedToProject,
/// Max number of users per project reached
MaxUsersPerProjectReached,
/// Max number of projects per user reached
MaxProjectsPerUserReached,
/// User is not assigned to the project
UserNotAssignedToProject,
/// Can not register administrator role
CannotRegisterAdminRole,
/// Max number of builders per project reached
MaxBuildersPerProjectReached,
/// Max number of investors per project reached
MaxInvestorsPerProjectReached,
/// Max number of issuers per project reached
MaxIssuersPerProjectReached,
/// Max number of regional centers per project reached
MaxRegionalCenterPerProjectReached,
/// Can not remove administrator role
CannotRemoveAdminRole,
/// Can not add admin role at user project assignment
CannotAddAdminRole,
/// User can not have more than one role at the same time
UserCannotHaveMoreThanOneRole,
/// Expenditure not found
ExpenditureNotFound,
/// Expenditure not found for the selected project_id
ExpenditureNotFoundForSelectedProjectId,
/// Expenditure already exist
ExpenditureAlreadyExists,
/// Expenditure is already in a transaction
ExpenditureHasNonZeroTransactions,
/// Max number of expenditures per project reached
MaxExpendituresPerProjectReached,
/// Field name can not be empty
EmptyExpenditureName,
/// Expenditure does not belong to the project
ExpenditureDoesNotBelongToProject,
/// Drawdown id is not found
DrawdownNotFound,
/// Invalid amount
InvalidAmount,
/// Documents field is empty
DocumentsEmpty,
/// Transaction id is not found
TransactionNotFound,
/// Transaction was not found for the selected Drawdown_id
TransactionNotFoundForSelectedDrawdownId,
/// Transaction already exist
TransactionAlreadyExists,
/// Transaction is already in a drawdown
TransactionInUse,
/// Max number of transactions per drawdown reached
MaxTransactionsPerDrawdownReached,
/// Drawdown already exist
DrawdownAlreadyExists,
/// Max number of drawdowns per project reached
MaxDrawdownsPerProjectReached,
/// Max number of status changes per drawdown reached
MaxStatusChangesPerDrawdownReached,
/// Max number of recovery chnages per drawdown reached
MaxRecoveryChangesReached,
/// Can not modify a completed drawdown
CannotEditDrawdown,
/// Can not perform any action on a submitted transaction
CannotPerformActionOnSubmittedTransaction,
/// Can not perform any action on a approved transaction
CannotPerformActionOnApprovedTransaction,
/// Can not perform any action on a confirmed transaction
CannotPerformActionOnConfirmedTransaction,
/// Can not perform any action on a submitted drawdown
CannotPerformActionOnSubmittedDrawdown,
/// Can not perform any action on a approved drawdown
CannotPerformActionOnApprovedDrawdown,
/// Can not perform any action on a confirmed drawdown
CannotPerformActionOnConfirmedDrawdown,
/// Transaction is already completed
TransactionIsAlreadyCompleted,
/// User does not have the specified role
UserDoesNotHaveRole,
/// Transactions vector is empty
EmptyTransactions,
/// Transactions are required for the current workflow
TransactionsRequired,
/// Transaction ID was not found in do_execute_transaction
TransactionIdRequired,
/// Drawdown can not be submitted if does not has any transactions
DrawdownHasNoTransactions,
/// Cannot submit transaction
CannotSubmitTransaction,
/// Drawdown can not be approved if is not in submitted status
DrawdownIsNotInSubmittedStatus,
/// Transactions is not in submitted status
TransactionIsNotInSubmittedStatus,
/// Array of expenditures is empty
EmptyExpenditures,
/// Expenditure name is required
ExpenditureNameRequired,
/// Expenditure type is required
ExpenditureTypeRequired,
/// Expenditure amount is required
ExpenditureAmountRequired,
/// Expenditure id is required
ExpenditureIdRequired,
/// User name is required
UserNameRequired,
/// User role is required
UserRoleRequired,
/// User image is required
UserImageRequired,
/// User email is required
UserEmailRequired,
/// Amount is required
AmountRequired,
/// Can not delete a user if the user is assigned to a project
UserHasAssignedProjects,
/// User has no projects assigned
UserHasNoProjects,
/// Can not send a drawdown to submitted status if it has no transactions
NoTransactionsToSubmit,
/// Bulk upload description is required
BulkUploadDescriptionRequired,
/// Bulk upload documents are required
BulkUploadDocumentsRequired,
/// Administrator can not delete themselves
AdministratorsCannotDeleteThemselves,
/// No feedback was provided for bulk upload
NoFeedbackProvidedForBulkUpload,
/// Bulkupload feedback is empty
EmptyBulkUploadFeedback,
/// NO feedback for EN5 drawdown was provided
EB5MissingFeedback,
/// EB5 feedback is empty
EmptyEb5Feedback,
/// Inflation rate extrinsic is missing an array of project ids
ProjectsInflationRateEmpty,
/// Inflation rate was not provided
InflationRateRequired,
/// Inflation rate has been already set for the selected project
InflationRateAlreadySet,
/// Inflation rate was not set for the selected project
InflationRateNotSet,
/// Bulkupload drawdowns are only allowed for Construction Loan & Developer Equity
DrawdownTypeNotSupportedForBulkUpload,
/// Cannot edit user role if the user is assigned to a project
UserHasAssignedProjectsCannotUpdateRole,
/// Cannot delete user if the user is assigned to a project
UserHasAssignedProjectsCannotDelete,
/// Cannot send a bulkupload drawdown if the drawdown status isn't in draft or rejected
DrawdownStatusNotSupportedForBulkUpload,
/// Cannot submit a drawdown if the drawdown status isn't in draft or rejected
DrawdownIsNotInDraftOrRejectedStatus,
/// Only investors can update/edit their documents
UserIsNotAnInvestor,
/// Max number of projects per investor has been reached
MaxProjectsPerInvestorReached,
/// Jobs eligibles array is empty
JobEligiblesEmpty,
/// JOb eligible name is empty
JobEligiblesNameRequired,
/// Job eligible id already exists
JobEligibleIdAlreadyExists,
/// Max number of job eligibles per project reached
MaxJobEligiblesPerProjectReached,
/// Job eligible id not found
JobEligibleNotFound,
/// Jopb eligible does not belong to the project
JobEligibleDoesNotBelongToProject,
/// Job eligible name is required
JobEligibleNameRequired,
/// Job eligible amount is required
JobEligibleAmountRequired,
/// Job eligible id is required
JobEligibleIdRequired,
/// Job eligible not found for the given project id
JobEligibleNotFoundForSelectedProjectId,
/// Job eligible has non zero transactions
JobEligibleHasNonZeroTransactions,
/// Revenue id was not found
RevenueNotFound,
/// Transactions revenue array is empty
RevenueTransactionsEmpty,
/// An array of revenue transactions is required
RevenueTransactionsRequired,
/// Revenue transaction is not in submitted status
RevenueTransactionNotSubmitted,
/// Revenue can not be edited
CannotEditRevenue,
/// Revenue transaction id already exists
RevenueTransactionIdAlreadyExists,
/// Max number of transactions per revenue reached
MaxTransactionsPerRevenueReached,
/// Revenue transaction id not found
RevenueTransactionNotFound,
/// Revenue transaction was not found for the selected revenue_id
RevenueTransactionNotFoundForSelectedRevenueId,
/// Revenue transaction can not be edited
CannotEditRevenueTransaction,
/// Max number of status changes per revenue reached
MaxStatusChangesPerRevenueReached,
/// Can not perform any action on a submitted revenue
CannotPerformActionOnSubmittedRevenue,
/// Can not perform any action on a approved revenue
CannotPerformActionOnApprovedRevenue,
/// Can not perform any action on a submitted revenue transaction
CannotPerformActionOnApprovedRevenueTransaction,
/// Can not perform any action on a approved revenue transaction
CannotPerformActionOnSubmittedRevenueTransaction,
/// Revenue amoun is required
RevenueAmountRequired,
/// Revenue transaction id is required
RevenueTransactionIdRequired,
/// Revenue Id already exists
RevenueIdAlreadyExists,
/// Maximun number of revenues per project reached
MaxRevenuesPerProjectReached,
/// Can not send a revenue to submitted status if it has no transactions
RevenueHasNoTransactions,
/// Revenue is not in submitted status
RevenueIsNotInSubmittedStatus,
/// Revenue transaction is not in submitted status
RevenueTransactionIsNotInSubmittedStatus,
/// Revenue transactions feedback is empty
RevenueTransactionsFeedbackEmpty,
/// The revenue is not in submitted status
RevenueNotSubmitted,
/// The revenue id does not belong to the project
RevenueDoesNotBelongToProject,
/// Can not upload bank confirming documents if the drawdown is not in Approved status
DrawdowMustBeInApprovedStatus,
/// Drawdown is not in Confirmed status
DrawdowMustBeInConfirmedStatus,
/// Drawdown is not in Submitted status
DrawdownNotSubmitted,
/// Can not insert (CUDAction: Create) bank confmirng documents if the drawdown has already bank confirming documents
DrawdownHasAlreadyBankConfirmingDocuments,
/// Drawdown has no bank confirming documents (CUDAction: Update or Delete)
DrawdownHasNoBankConfirmingDocuments,
/// Drawdown id does not belong to the selected project
DrawdownDoesNotBelongToProject,
/// Bank confirming documents are required
BankConfirmingDocumentsNotProvided,
/// Banck confirming documents array is empty
BankConfirmingDocumentsEmpty,
/// Only eb5 drawdowns are allowed to upload bank documentation
OnlyEB5DrawdownsCanUploadBankDocuments,
/// Maximun number of registrations at a time reached
MaxRegistrationsAtATimeReached,
/// Administrator account has insuficiente balance to register a new user
AdminHasNoFreeBalance,
/// Administrator account has insuficiente balance to register a new user
InsufficientFundsToTransfer,
}
// E X T R I N S I C S
// ------------------------------------------------------------------------------------------------------------
#[pallet::call]
impl<T: Config> Pallet<T> {
// I N I T I A L
// --------------------------------------------------------------------------------------------
/// Initialize the pallet by setting the permissions for each role
/// & the global scope
///
/// # Considerations:
/// - This function can only be called once
/// - This function can only be called usinf the sudo pallet
#[pallet::call_index(1)]
#[pallet::weight(Weight::from_ref_time(10_000) + T::DbWeight::get().writes(10))]
pub fn initial_setup(origin: OriginFor<T>) -> DispatchResult {
T::RemoveOrigin::ensure_origin(origin.clone())?;
Self::do_initial_setup()?;
Ok(())
}
/// Adds an administrator account to the site
///
/// # Parameters:
/// - origin: The sudo account
/// - admin: The administrator account to be added
/// - name: The name of the administrator account
///
/// # Considerations:
/// - This function can only be called using the sudo pallet
/// - This function is used to add the first administrator to the site
/// - If the user is already registered, the function will return an error: UserAlreadyRegistered
/// - This function grants administrator permissions to the user from the rbac pallet
/// - administrator role have global scope permissions
#[pallet::call_index(2)]
#[pallet::weight(Weight::from_ref_time(10_000) + T::DbWeight::get().writes(10))]
pub fn sudo_add_administrator(
origin: OriginFor<T>,
admin: T::AccountId,
name: FieldName,
) -> DispatchResult {
T::RemoveOrigin::ensure_origin(origin.clone())?;
Self::do_sudo_add_administrator(admin, name)?;
Ok(())
}
/// Removes an administrator account from the site
///
/// # Parameters:
/// - origin: The sudo account
/// - admin: The administrator account to be removed
///
/// # Considerations:
/// - This function can only be called using the sudo pallet
/// - This function is used to remove any administrator from the site
/// - If the user is not registered, the function will return an error: UserNotFound
/// - This function removes administrator permissions of the user from the rbac pallet
///
/// # Note:
/// WARNING: Administrators can remove themselves from the site,
/// but they can add themselves back
#[pallet::call_index(3)]
#[pallet::weight(Weight::from_ref_time(10_000) + T::DbWeight::get().writes(10))]
pub fn sudo_remove_administrator(origin: OriginFor<T>, admin: T::AccountId) -> DispatchResult {
T::RemoveOrigin::ensure_origin(origin.clone())?;
Self::do_sudo_remove_administrator(admin)?;
Ok(())
}
// U S E R S
// --------------------------------------------------------------------------------------------
/// This extrinsic is used to create, update, or delete a user account
///
/// # Parameters:
/// - origin: The administrator account
/// - user: The target user account to be registered, updated, or deleted.
/// It is an array of user accounts where each entry it should be a tuple of the following:
/// - 0: The user account
/// - 1: The user name
/// - 2: The user role
/// - 3: The CUD operation to be performed on the user account. CUD action is ALWAYS
/// required.
///
/// # Considerations:
/// - Users parameters are optional because depends on the CUD action as follows:
/// * **Create**: The user account, user name, user role & CUD action are required
/// * **Update**: The user account & CUD action are required. The user name & user role are
/// optionals.
/// * **Delete**: The user account & CUD action are required.
/// - This function can only be called by an administrator account
/// - Multiple users can be registered, updated, or deleted at the same time, but
/// the user account must be unique. Multiple actions over the same user account
/// in the same call, it could result in an unexpected behavior.
/// - If the user is already registered, the function will return an error:
/// UserAlreadyRegistered
/// - If the user is not registered, the function will return an error: UserNotFound
///
/// # Note:
/// - WARNING: It is possible to register, update, or delete administrators accounts using
/// this extrinsic,
/// but administrators can not delete themselves.
/// - WARNING: This function only registers, updates, or deletes users from the site.
/// - WARNING: The only way to grant or remove permissions of a user account is assigning or
/// unassigning
/// a user from a selected project.
#[pallet::call_index(4)]
#[pallet::weight(Weight::from_ref_time(10_000) + T::DbWeight::get().writes(10))]
pub fn users(origin: OriginFor<T>, users: Users<T>) -> DispatchResult {
let who = ensure_signed(origin)?; // origin need to be an admin
Self::do_execute_users(who, users)
}
/// Edits an user account
///
/// # Parameters:
/// - origin: The user account which is being edited
/// - name: The name of the user account which is being edited
/// - image: The image of the user account which is being edited
/// - email: The email of the user account which is being edited
/// - documents: The documents of the user account which is being edited.
/// ONLY available for the investor role.
///
/// # Considerations:
/// - If the user is not registered, the function will return an error: UserNotFound
/// - This function can only be called by a registered user account
/// - This function will be called by the user account itself
/// - ALL parameters are optional because depends on what is being edited
/// - ONLY the investor role can edit or update the documents
#[pallet::call_index(5)]
#[pallet::weight(Weight::from_ref_time(10_000) + T::DbWeight::get().writes(10))]
pub fn users_edit_user(
origin: OriginFor<T>,
name: Option<FieldName>,
image: Option<CID>,
email: Option<FieldName>,
documents: Option<Documents<T>>,
) -> DispatchResult {
let who = ensure_signed(origin)?;
Self::do_edit_user(who, name, image, email, documents)
}
// P R O J E C T S
// --------------------------------------------------------------------------------------------
/// Registers a new project.
///
/// # Parameters:
/// - origin: The administrator account
/// - title: The title of the project
/// - description: The description of the project
/// - image: The image of the project (CID)
/// - address: The address of the project
/// - creation_date: The creation date of the project
/// - completion_date: The completion date of the project
/// - expenditures: The expenditures of the project. It is an array of tuples where each
/// entry
/// is a tuple of the following:
/// * 0: The expenditure name
/// * 1: The expenditure type
/// * 2: The expenditure amount
/// * 3: The expenditure NAICS code
/// * 4: The expenditure jobs multiplier
/// * 5: The CUD action to be performed on the expenditure. CUD action is ALWAYS required.
/// * 6: The expenditure id. It is optional because it is only required when updating or
/// deleting
/// - job_eligibles: The job eligibles to be created/updated/deleted. This is a vector of
/// tuples
/// where each entry is composed by:
/// * 0: The job eligible name
/// * 1: The amount of the job eligible
/// * 2: The NAICS code of the job eligible
/// * 3: The jobs multiplier of the job eligible
/// * 4: The job eligible action to be performed. (Create, Update or Delete)
/// * 5: The job eligible id. This is only used when updating or deleting a job eligible.
/// - users: The users who will be assigned to the project. It is an array of tuples where
/// each entry
/// is a tuple of the following:
/// * 0: The user account
/// * 1: The user role
/// * 2: The AssignAction to be performed on the user.
///
/// # Considerations:
/// - This function can only be called by an administrator account
/// - For users assignation, the user account must be registered. If the user is not
/// registered,
/// the function will return an error. ALL parameters are required.
/// - For expenditures, apart from the expenditure id, naics code & jopbs multiplier, ALL
/// parameters are required because for this
/// flow, the expenditures are always created. The naics code & the jobs multiplier
/// can be added later by the administrator.
/// - Creating a project will automatically create a scope for the project.
///
/// # Note:
/// WARNING: If users are provided, the function will assign the users to the project,
/// granting them permissions in the rbac pallet.
#[pallet::call_index(6)]
#[pallet::weight(Weight::from_ref_time(10_000) + T::DbWeight::get().writes(10))]
pub fn projects_create_project(
origin: OriginFor<T>,
title: FieldName,
description: FieldDescription,
image: Option<CID>,
address: FieldName,
banks: Option<BoundedVec<(BankName, BankAddress), T::MaxBanksPerProject>>,
creation_date: CreationDate,
completion_date: CompletionDate,
expenditures: Expenditures<T>,
job_eligibles: Option<JobEligibles<T>>,
users: Option<UsersAssignation<T>>,
private_group_id: PrivateGroupId,
) -> DispatchResult {
let who = ensure_signed(origin)?; // origin need to be an admin
Self::do_create_project(
who,
title,
description,
image,
address,
banks,
creation_date,
completion_date,
expenditures,
job_eligibles,
users,
private_group_id,
)
}
/// Edits a project.
///
/// # Parameters:
/// - origin: The administrator account
/// - project_id: The selected project id that will be edited
/// - title: The title of the project to be edited
/// - description: The description of the project to be edited
/// - image: The image of the project to be edited
/// - address: The address of the project to be edited
/// - creation_date: The creation date of the project to be edited
/// - completion_date: The completion date of the project to be edited
///
/// # Considerations:
/// - This function can only be called by an administrator account
/// - ALL parameters are optional because depends on what is being edited
/// - The project id is required because it is the only way to identify the project
/// - The project id must be registered. If the project is not registered,
/// the function will return an error: ProjectNotFound
/// - It is not possible to edit the expenditures or the users assigned to the project
/// through this function. For that, the administrator must use the extrinsics:
/// * expenditures
/// * projects_assign_user
/// - Project can only be edited in the Started status
/// - Completion date must be greater than creation date
#[pallet::call_index(7)]
#[pallet::weight(Weight::from_ref_time(10_000) + T::DbWeight::get().writes(10))]
pub fn projects_edit_project(
origin: OriginFor<T>,
project_id: ProjectId,
title: Option<FieldName>,
description: Option<FieldDescription>,
image: Option<CID>,
address: Option<FieldName>,
banks: Option<BoundedVec<(BankName, BankAddress), T::MaxBanksPerProject>>,
creation_date: Option<CreationDate>,
completion_date: Option<CompletionDate>,
) -> DispatchResult {
let who = ensure_signed(origin)?; // origin need to be an admin
Self::do_edit_project(
who,
project_id,
title,
description,
image,
address,
banks,
creation_date,
completion_date,
)
}
/// Deletes a project.
///
/// # Parameters:
/// - origin: The administrator account
/// - project_id: The selected project id that will be deleted
///
/// # Considerations:
/// - This function can only be called by an administrator account
/// - The project id is required because it is the only way to identify the project
/// - The project id must be registered. If the project is not registered,
/// the function will return an error: ProjectNotFound
///
/// # Note:
/// - WARNING: Deleting a project will also delete ALL stored information associated with
/// the project.
/// BE CAREFUL.
#[pallet::call_index(8)]
#[pallet::weight(Weight::from_ref_time(10_000) + T::DbWeight::get().writes(10))]
pub fn projects_delete_project(origin: OriginFor<T>, project_id: ProjectId) -> DispatchResult {
let who = ensure_signed(origin)?; // origin need to be an admin
Self::do_delete_project(who, project_id)
}
/// Assigns a user to a project.
///
/// # Parameters:
/// - origin: The administrator account
/// - project_id: The selected project id where user will be assigned
/// - users: The users to be assigned to the project. This is a vector of tuples
/// where each entry is composed by:
/// * 0: The user account id
/// * 1: The user role
/// * 2: The AssignAction to be performed. (Assign or Unassign)
///
/// # Considerations:
/// - This function can only be called by an administrator account
/// - This extrinsic allows multiple users to be assigned/unassigned at the same time.
/// - The project id is required because it is the only way to identify the project
/// - This extrinsic is used for both assigning and unassigning users to a project
/// depending on the AssignAction.
/// - After a user is assigned to a project, the user will be able to perform actions
/// in the project depending on the role assigned to the user.
/// - After a user is unassigned from a project, the user will not be able to perform
/// actions
/// in the project anymore.
/// - If the user is already assigned to the project, the function will return an error.
///
/// # Note:
/// - WARNING: ALL provided users needs to be registered in the site. If any of the users
/// is not registered, the function will return an error.
/// - Assigning or unassigning a user to a project will add or remove permissions to the
/// user
/// from the RBAC pallet.
/// - Warning: Cannot assign a user to a project with a different role than the one they
/// have in UsersInfo. If the user has a different role, the function will return an error.
/// - Warning: Cannot unassign a user from a project with a different role than the one they
/// have in UsersInfo. If the user has a different role, the function will return an error.
/// - Warning: Do not perform multiple actions over the same user in the same call, it could
/// result in an unexpected behavior.
#[pallet::call_index(9)]
#[pallet::weight(Weight::from_ref_time(10_000) + T::DbWeight::get().writes(10))]
pub fn projects_assign_user(
origin: OriginFor<T>,
project_id: ProjectId,
users: UsersAssignation<T>,
) -> DispatchResult {
let who = ensure_signed(origin)?; // origin need to be an admin
Self::do_execute_assign_users(who, project_id, users)
}
// B U D G E T E X P E N D I T U R E & J O B E L I G I B L E S
// --------------------------------------------------------------------------------------------
/// This extrinsic is used to create, update or delete expenditures & job eligibles.
///
/// # Parameters:
/// - origin: The administrator account
/// - project_id: The selected project id where the expenditures will be
/// created/updated/deleted
/// - expenditures: The expenditures to be created/updated/deleted. This is a vector of
/// tuples
/// where each entry is composed by:
/// * 0: The name of the expenditure
/// * 1: The expenditure type
/// * 2: The amount of the expenditure
/// * 3: The naics code of the expenditure
/// * 4: The jobs multiplier of the expenditure
/// * 5: The expenditure action to be performed. (Create, Update or Delete)
/// * 6: The expenditure id. This is only used when updating or deleting an expenditure.
/// - job_eligibles: The job eligibles to be created/updated/deleted. This is a vector of
/// tuples
/// where each entry is composed by:
/// * 0: The job eligible name
/// * 1: The amount of the job eligible
/// * 2: The NAICS code of the job eligible
/// * 3: The jobs multiplier of the job eligible
/// * 4: The job eligible action to be performed. (Create, Update or Delete)
/// * 5: The job eligible id. This is only used when updating or deleting a job eligible.
///
/// # Considerations:
/// - Naics code and jobs multiplier are always optional.
/// - This function can only be called by an administrator account
/// - This extrinsic allows multiple expenditures to be created/updated/deleted at the same
/// time.
/// - The project id is required because it is the only way to identify the project
/// - Expenditure parameters are optional because depends on the action to be performed:
/// * **Create**: Name, Type & Amount are required. Nacis code & Jobs multiplier are
/// optional.
/// * **Update**: Except for the expenditure id & action, all parameters are optional.
/// * **Delete**: Only the expenditure id & action is required.
/// - Multiple actions can be performed at the same time. For example, you can create a new
/// expenditure and update another one at the same time.
/// - Do not perform multiple actions over the same expenditure in the same call, it could
/// result in an unexpected behavior.
#[pallet::call_index(10)]
#[pallet::weight(Weight::from_ref_time(10_000) + T::DbWeight::get().writes(10))]
pub fn expenditures_and_job_eligibles(
origin: OriginFor<T>,
project_id: ProjectId,
expenditures: Option<Expenditures<T>>,
job_eligibles: Option<JobEligibles<T>>,
) -> DispatchResult {
let who = ensure_signed(origin)?; // origin need to be an admin
if let Some(mod_expenditures) = expenditures {
Self::do_execute_expenditures(who.clone(), project_id, mod_expenditures)?;
}
if let Some(mod_job_eligibles) = job_eligibles {
Self::do_execute_job_eligibles(who, project_id, mod_job_eligibles)?;
}
Ok(())
}
// T R A N S A C T I O N S & D R A W D O W N S
// --------------------------------------------------------------------------------------------
/// Submit a drawdown
/// This extrinsic is used to create, update or delete transactions.
/// It also allows that an array of transactions to be saved as a draft or as submitted.
///
/// # Parameters:
/// - origin: The user account who is creating the transactions
/// - project_id: The selected project id where the transactions will be created
/// - drawdown_id: The selected drawdown id where the transactions will be created
/// - transactions: The transactions to be created/updated/deleted. This entry is a vector
/// of tuples
/// where each entry is composed by:
/// * 0: The expenditure id where the transaction will be created
/// * 1: The amount of the transaction
/// * 2: Documents associated to the transaction
/// * 3: The action to be performed on the transaction. (Create, Update or Delete)
/// * 4: The transaction id. This is only used when updating or deleting a transaction.
/// - submit: If true, transactions associated to the selected
/// drawdown will be submitted to the administrator.
/// If false, the array of transactions will be saved as a draft.
///
/// # Considerations:
/// - This function is only callable by a builder role account
/// - This extrinsic allows multiple transactions to be created/updated/deleted at the same
/// time.
/// - The project id and drawdown id are required for the reports.
/// - Transaction parameters are optional because depends on the action to be performed:
/// * **Create**: Expenditure id, Amount, Documents & action are required.
/// * **Update**: Except for the transaction id & action, all other parameters are optional.
/// * **Delete**: Only the transaction id & action are required.
/// - Multiple actions can be performed at the same time, but each must be performed on
/// a different transaction. For example, you can create a new
/// transaction and update another one at the same time.
/// - Do not perform multiple actions over the same transaction in the same call, it could
/// result in an unexpected behavior.
/// - If a drawdown is submitted, all transactions must be submitted too. If the drawdown do
/// not contain
/// any transaction, it will return an error.
/// - After a drawdown is submitted, it can not be updated or deleted.
/// - After a drawdown is rejected, builders will use again this extrinsic to update the
/// transactions associated to a given drawdown.
#[pallet::call_index(11)]
#[pallet::weight(Weight::from_ref_time(10_000) + T::DbWeight::get().writes(10))]
pub fn submit_drawdown(
origin: OriginFor<T>,
project_id: ProjectId,
drawdown_id: DrawdownId,
transactions: Option<Transactions<T>>,
submit: bool,
) -> DispatchResult {
let who = ensure_signed(origin)?; // origin need to be an admin
match submit {
// Save transactions as draft
false => {
// Do execute transactions
Self::do_execute_transactions(
who,
project_id,
drawdown_id,
transactions.ok_or(Error::<T>::TransactionsRequired)?,
)
},
// Submit transactions
true => {
// Check if there are transactions to execute
if let Some(mod_transactions) = transactions {
// Ensure transactions are not empty
ensure!(!mod_transactions.is_empty(), Error::<T>::EmptyTransactions);
// Do execute transactions
Self::do_execute_transactions(who.clone(), project_id, drawdown_id, mod_transactions)?;
}
// Do submit drawdown
Self::do_submit_drawdown(who, project_id, drawdown_id)
},
}
}
/// Approve a drawdown
///
/// # Parameters:
/// ### For EB5 drawdowns:
/// - origin: The administrator account who is approving the drawdown
/// - project_id: The selected project id where the drawdown will be approved
/// - drawdown_id: The selected drawdown id to be approved
///
/// ### For Construction Loan & Developer Equity (bulk uploads) drawdowns:
/// - origin: The administrator account who is approving the drawdown
/// - project_id: The selected project id where the drawdown will be approved
/// - drawdown_id: The selected drawdown id to be approved.
/// - bulkupload: Optional bulkupload parameter. If true, the drawdown will be saved in a
/// pseudo
/// draft status. If false, the drawdown will be approved directly.
/// - transactions: The transactions to be created/updated/deleted. This is a vector of
/// tuples
/// where each entry is composed by:
/// * 0: The expenditure id where the transaction will be created
/// * 1: The transaction amount
/// * 2: Documents associated to the transaction
/// * 3: The transaction action to be performed. (Create, Update or Delete)
/// * 4: The transaction id. This is only used when updating or deleting a transaction.
/// - This extrinsic allows multiple transactions to be created/updated/deleted at the same
/// time
/// (only for Construction Loan & Developer Equity drawdowns).
/// - Transaction parameters are optional because depends on the action to be performed:
/// * **Create**: Expenditure id, Amount, Documents & action are required.
/// * **Update**: Except for the transaction id & action, all parameters are optional.
/// * **Delete**: Only the transaction id & action are required.
/// - Multiple actions can be performed at the same time. For example, you can create a new
/// transaction and update another one at the same time (only for Construction Loan &
/// Developer Equity drawdowns).
/// - Do not perform multiple actions over the same transaction in the same call, it could
/// result in an unexpected behavior (only for Construction Loan & Developer Equity
/// drawdowns).
///
/// # Considerations:
/// - This function is only callable by an administrator account
/// - All transactions associated to the drawdown will be approved too. It's
/// not possible to approve a drawdown without approving all of its transactions.
/// - After a drawdown is approved, it can not be updated or deleted.
/// - After a drawdown is approved, the next drawdown will be automatically created.
/// - The drawdown status will be updated to "Approved" after the extrinsic is executed.
/// - After a drawdown is rejected, administrators will use again this extrinsic to approve
/// the
/// new drawdown version uploaded by the builder.
#[pallet::call_index(12)]
#[pallet::weight(Weight::from_ref_time(10_000) + T::DbWeight::get().writes(10))]
pub fn approve_drawdown(
origin: OriginFor<T>,
project_id: ProjectId,
drawdown_id: DrawdownId,
bulkupload: Option<bool>,
transactions: Option<Transactions<T>>,
) -> DispatchResult {
let who = ensure_signed(origin)?; // origin need to be an admin
// Match bulkupload parameter
match bulkupload {
Some(approval) => {
// Ensure admin permissions
Self::is_authorized(who.clone(), &project_id, ProxyPermission::ApproveDrawdown)?;
// Execute bulkupload flow (construction loan & developer equity)
match approval {
false => {
// 1. Do execute transactions
Self::do_execute_transactions(
who.clone(),
project_id,
drawdown_id,
transactions.ok_or(Error::<T>::TransactionsRequired)?,
)?;
// 2. Do submit drawdown
Self::do_submit_drawdown(who, project_id, drawdown_id)
},
true => {
// 1.Execute transactions if provided
if let Some(mod_transactions) = transactions {
// Ensure transactions are not empty
ensure!(!mod_transactions.is_empty(), Error::<T>::EmptyTransactions);
// Do execute transactions
Self::do_execute_transactions(
who.clone(),
project_id,
drawdown_id,
mod_transactions,
)?;
// 2. Submit drawdown
Self::do_submit_drawdown(who.clone(), project_id, drawdown_id)?;
}
// 3. Approve drawdown
Self::do_approve_drawdown(who, project_id, drawdown_id)
},
}
},
None => {
// Execute normal flow (EB5)
Self::do_approve_drawdown(who, project_id, drawdown_id)
},
}
}
/// Reject a drawdown
///
/// # Parameters:
/// - origin: The administrator account who is rejecting the drawdown
/// - project_id: The selected project id where the drawdown will be rejected
/// - drawdown_id: The selected drawdown id to be rejected
///
/// Then the next two feedback parameters are optional because depends on the drawdown type:
/// #### EB5 drawdowns:
/// - transactions_feedback: Administrator will provide feedback for each rejected
/// transacion. This is a vector of tuples where each entry is composed by:
/// * 0: The transaction id
/// * 1: The transaction feedback
///
/// #### Construction Loan & Developer Equity drawdowns:
/// - drawdown_feedback: Administrator will provide feedback for the WHOLE drawdown.
///
/// # Considerations:
/// - This function can only be called by an administrator account
/// - All transactions associated to the drawdown will be rejected too. It's
/// not possible to reject a drawdown without rejecting all of its transactions.
/// (only for EB5 drawdowns).
/// - For EB5 drawdowns, the administrator needs to provide feedback for
/// each rejected transaction.
/// - For Construction Loan & Developer Equity drawdowns, the administrator can provide
/// feedback for the WHOLE drawdown.
/// - After a builder re-submits a drawdown, the administrator will have to review
/// the drawdown again.
/// - After a builder re-submits a drawdown, the feedback field will be cleared
/// automatically.
/// - If a single EB5 transaction is wrong, the administrator WILL reject the WHOLE
/// drawdown.
/// There is no way to reject a single transaction.
#[pallet::call_index(13)]
#[pallet::weight(Weight::from_ref_time(10_000) + T::DbWeight::get().writes(10))]
pub fn reject_drawdown(
origin: OriginFor<T>,
project_id: ProjectId,
drawdown_id: DrawdownId,
transactions_feedback: Option<TransactionsFeedback<T>>,
drawdown_feedback: Option<FieldDescription>,
) -> DispatchResult {
let who = ensure_signed(origin)?; // origin need to be an admin
Self::do_reject_drawdown(
who,
project_id,
drawdown_id,
transactions_feedback,
drawdown_feedback,
)
}
/// Bulk upload drawdowns.
///
/// # Parameters:
/// - origin: The administrator account who is uploading the drawdowns
/// - project_id: The selected project id where the drawdowns will be uploaded
/// - drawdown_id: The drawdowns to be uploaded
/// - description: The description of the drawdown provided by the builder
/// - total_amount: The total amount of the drawdown
/// - documents: The documents provided by the builder for the drawdown
///
/// # Considerations:
/// - This function can only be called by a builder account
/// - This extrinsic allows only one drawdown to be uploaded at the same time.
/// - The drawdown will be automatically submitted.
/// - Only available for Construction Loan & Developer Equity drawdowns.
/// - After a builder uploads a drawdown, the administrator will have to review it.
/// - After a builder re-submits a drawdown, the feedback field will be cleared
/// automatically.
/// - Bulkuploads does not allow individual transactions.
/// - After a builder uploads a drawdown, the administrator will have to
/// insert each transaction manually.
#[pallet::call_index(14)]
#[pallet::weight(Weight::from_ref_time(10_000) + T::DbWeight::get().writes(10))]
pub fn up_bulkupload(
origin: OriginFor<T>,
project_id: ProjectId,
drawdown_id: DrawdownId,
description: FieldDescription,
total_amount: TotalAmount,
documents: Documents<T>,
) -> DispatchResult {
let who = ensure_signed(origin)?; // origin need to be a builder
Self::do_up_bulk_upload(who, project_id, drawdown_id, description, total_amount, documents)
}
/// Modifies the inflation rate of a project.
///
/// # Parameters:
/// - origin: The administrator account who is modifying the inflation rate
/// - projects: The projects where the inflation rate will be modified.
/// This is a vector of tuples where each entry is composed by:
/// * 0: The project id
/// * 1: The inflation rate
/// * 2: The action to be performed (Create, Update or Delete)
///
/// # Considerations:
/// - This function can only be called by an administrator account
/// - This extrinsic allows multiple projects to be modified at the same time.
/// - The inflation rate can be created, updated or deleted.
/// - The inflation rate is optional because depends on the CUDAction parameter:
/// * **Create**: The inflation rate will be created. Project id, inflation rate and action
/// are required.
/// * **Update**: The inflation rate will be updated. Project id, inflation rate and action
/// are required.
/// * **Delete**: The inflation rate will be deleted. Project id and action are required.
/// - The inflation rate can only be modified if the project is in the "started" status.
#[pallet::call_index(15)]
#[pallet::weight(Weight::from_ref_time(10_000) + T::DbWeight::get().writes(10))]
pub fn inflation_rate(origin: OriginFor<T>, projects: ProjectsInflation<T>) -> DispatchResult {
let who = ensure_signed(origin)?;
Self::do_execute_inflation_adjustment(who, projects)
}
// R E V E N U E S
// --------------------------------------------------------------------------------------------
/// This extrinsic is used to create, update or delete revenue transactions.
/// It also allows that an array of revenue transactions
/// to be saved as a draft or as submitted.
///
/// # Parameters:
/// */ - origin: The user account who is creating the revenue transactions
/// - project_id: The selected project id where the revenue transactions will be created
/// - revenue_id: The selected revenue id where the revenue transactions will be created
/// - revenue_transactions: The revenue transactions to be created/updated/deleted.
/// This entry is a vector of tuples where each entry is composed by:
/// * 0: The job eligible id where the revenue transaction will be created
/// * 1: The amount of the revenue transaction
/// * 2: Documents associated to the revenue transaction
/// * 3: The action to be performed on the revenue transaction (Create, Update or Delete)
/// * 4: The revenue transaction id. This is required only if the action is being updated or
/// deleted.
/// - submit: If true, the array of revenue transactions will be submitted to the
/// administrator.
/// If false, the array of revenue transactions will be saved as a draft.
///
/// # Considerations:
/// - This function is only callable by a builder role account
/// - This extrinsic allows multiple revenue transactions to be created/updated/deleted at
/// the same time.
/// - The project id and revenue id are required for the reports.
/// - revenue_transactions parameters are optional because depends on the action to be
/// performed:
/// * **Create**: Job eligible id, Amount, Documents & action are required.
/// * **Update**: Except for the revenue transaction id & action, all other parameters are
/// optional.
/// * **Delete**: Only the revenue transaction id & action are required.
/// - Multiple actions can be performed at the same time, but each must be performed on
/// a different transaction. For example, you can create a new
/// transaction and update another one at the same time.
/// - Do not perform multiple actions over the same transaction in the same call, it could
/// result in an unexpected behavior.
/// - If a revenue is submitted, all transactions must be submitted too. If the revenue do
/// not contain
/// any transaction, it will return an error.
/// - After a revenue is submitted, it can not be updated or deleted.
/// - After a revenue is rejected, builders will use again this extrinsic to update the
/// transactions associated to a given revenue.
#[pallet::call_index(16)]
#[pallet::weight(Weight::from_ref_time(10_000) + T::DbWeight::get().writes(10))]
pub fn submit_revenue(
origin: OriginFor<T>,
project_id: ProjectId,
revenue_id: RevenueId,
revenue_transactions: Option<RevenueTransactions<T>>,
submit: bool,
) -> DispatchResult {
let who = ensure_signed(origin)?;
match submit {
// Save revenue transactions as draft
false => {
// Do execute transactions
Self::do_execute_revenue_transactions(
who,
project_id,
revenue_id,
revenue_transactions.ok_or(Error::<T>::RevenueTransactionsRequired)?,
)
},
// Submit revenue transactions
true => {
// Check if there are transactions to execute
if let Some(mod_revenue_transactions) = revenue_transactions {
// Ensure transactions are not empty
ensure!(!mod_revenue_transactions.is_empty(), Error::<T>::RevenueTransactionsEmpty);
// Do execute transactions
Self::do_execute_revenue_transactions(
who.clone(),
project_id,
revenue_id,
mod_revenue_transactions,
)?;
}
// Do submit revenue
Self::do_submit_revenue(who, project_id, revenue_id)
},
}
}
/// Approve a revenue
///
/// # Parameters:
/// - origin: The administrator account who is approving the revenue
/// - project_id: The selected project id where the revenue will be approved
/// - revenue_id: The selected revenue id to be approved
///
/// # Considerations:
/// - This function is only callable by an administrator role account
/// - All transactions associated to the revenue will be approved too. It's
/// not possible to approve a revenue without approving all of its transactions.
/// - After a revenue is approved, it can not be updated or deleted.
/// - After a revenue is approved, the next revenue will be created automatically.
/// - After a revenue is rejected, administrators will use again this extrinsic to approve
/// the rejected revenue
/// new revenue version uploaded by the builder.
/// - The revenue status will be updated to Approved.
#[pallet::call_index(17)]
#[pallet::weight(Weight::from_ref_time(10_000) + T::DbWeight::get().writes(10))]
pub fn approve_revenue(
origin: OriginFor<T>,
project_id: ProjectId,
revenue_id: RevenueId,
) -> DispatchResult {
let who = ensure_signed(origin)?;
Self::do_approve_revenue(who, project_id, revenue_id)
}
/// Reject a revenue
///
/// # Parameters:
/// - origin: The administrator account who is rejecting the revenue
/// - project_id: The selected project id where the revenue will be rejected
/// - revenue_id: The selected revenue id to be rejected
/// - revenue_transactions_feedback: Administrator will provide feedback for each rejected
/// transacion. This is a vector of tuples where each entry is composed by:
/// * 0: The revenue transaction id
/// * 1: The revenue transaction feedback
///
/// # Considerations:
/// - This function is only callable by an administrator role account
/// - All transactions associated to the revenue will be rejected too. It's
/// not possible to reject a revenue without rejecting all of its transactions.
/// - Administrator needs to provide a feedback for each rejected transaction.
/// - After a builder re-submits a revenue, the feedback field will be cleared
/// automatically.
/// - If a single revenue transaction is wrong, the administrator WILL reject the WHOLE
/// revenue.
/// There is no way to reject a single revenue transaction.
#[pallet::call_index(18)]
#[pallet::weight(Weight::from_ref_time(10_000) + T::DbWeight::get().writes(10))]
pub fn reject_revenue(
origin: OriginFor<T>,
project_id: ProjectId,
revenue_id: RevenueId,
revenue_transactions_feedback: TransactionsFeedback<T>,
) -> DispatchResult {
let who = ensure_signed(origin)?;
Self::do_reject_revenue(who, project_id, revenue_id, revenue_transactions_feedback)
}
/// The following extrinsic is used to upload the bank confirming documents
/// for a given drawdown.
///
/// # Parameters:
/// - origin: The administrator account who is uploading the confirming documents
/// - project_id: The selected project id where the drawdown exists
/// - drawdown_id: The selected drawdown id where the confirming documents will be uploaded
/// - confirming_documents: The confirming documents to be uploaded. This field is optional
/// because are required only when the action is Create or Update.
/// - action: The action to be performed. It can be Create, Update or Delete
/// * Create: project_id, drawdown_id and confirming_documents are required
/// * Update: project_id, drawdown_id and confirming_documents are required
/// * Delete: project_id and drawdown_id are required
///
/// # Considerations:
/// - This function is only callable by an administrator role account
/// - The confirming documents are required only when the action is Create or Update.
/// - The confirming documents are optional when the action is Delete.
/// - After the confirming documents are uploaded, the drawdown status will be updated to
/// "Confirmed". It will also update the status of all of its transactions to "Confirmed".
/// - Update action will replace the existing confirming documents with the new ones.
/// - Delete action will remove the existing confirming documents. It will also update the
/// drawdown status to "Approved" and the status of all of its transactions to "Approved".
/// It does a rollback of the drawdown.
#[pallet::call_index(19)]
#[pallet::weight(Weight::from_ref_time(10_000) + T::DbWeight::get().writes(10))]
pub fn bank_confirming_documents(
origin: OriginFor<T>,
project_id: ProjectId,
drawdown_id: DrawdownId,
confirming_documents: Option<Documents<T>>,
action: CUDAction,
) -> DispatchResult {
let who = ensure_signed(origin)?;
Self::do_bank_confirming_documents(who, project_id, drawdown_id, confirming_documents, action)
}
/// The following extrinsic is used to cancel a drawdown submission.
///
/// # Parameters:
/// - origin: The builder account who is cancelling the drawdown submission
/// - project_id: The selected project id where the drawdown exists
/// - drawdown_id: The selected drawdown id to be cancelled
///
/// # Considerations:
/// - This function is only callable by a builder role account
/// - The drawdown status will be rolled back to "Draft".
/// - All of its transactions will be deleted.
/// - The whole drawdown will be reset to its initial state, so be careful when using this
#[pallet::call_index(20)]
#[pallet::weight(Weight::from_ref_time(10_000) + T::DbWeight::get().writes(10))]
pub fn reset_drawdown(
origin: OriginFor<T>,
project_id: ProjectId,
drawdown_id: DrawdownId,
) -> DispatchResult {
let who = ensure_signed(origin)?;
Self::do_reset_drawdown(who, project_id, drawdown_id)
}
/// Execute a recovery drawdown on a project. This function can only be called by an admin.
///
/// Parameters:
/// - `origin`: The administrator account who is executing the recovery drawdown
/// - `project_id`: The ID of the project from which the recovery drawdown will be executed
/// - `drawdown_id`: The ID of the drawdown from which the recovery drawdown will be executed
/// - `transactions`: The list of transactions that will be executed in the recovery drawdown
///
/// # Errors
///
/// This function returns an error if:
///
/// - The transaction origin is not a signed message from an admin account.
/// - The project with the given ID does not exist.
/// - The drawdown with the given ID does not exist.
///
/// # Considerations:
/// - This function is only callable by an administrator role account
/// - The drawdown status won't be changed
#[pallet::call_index(21)]
#[pallet::weight(Weight::from_ref_time(10_000) + T::DbWeight::get().writes(10))]
pub fn recovery_drawdown(
origin: OriginFor<T>,
project_id: ProjectId,
drawdown_id: DrawdownId,
transactions: Transactions<T>,
) -> DispatchResult {
let who = ensure_signed(origin)?; // origin need to be an admin
Self::do_recovery_drawdown(who, project_id, drawdown_id, transactions)
}
/// Execute a recovery revenue on a project. This function can only be called by an admin.
///
/// Parameters:
/// - `origin`: The administrator account who is executing the recovery revenue
/// - `project_id`: The ID of the project from which the recovery revenue will be executed
/// - `revenue_id`: The ID of the revenue from which the recovery revenue will be executed
/// - `transactions`: The list of transactions that will be executed in the recovery revenue
///
/// # Errors
///
/// This function returns an error if:
///
/// - The transaction origin is not a signed message from an admin account.
/// - The project with the given ID does not exist.
/// - The revenue with the given ID does not exist.
///
/// ### Considerations:
/// - This function is only callable by an administrator role account
/// - The revenue status won't be changed
#[pallet::call_index(22)]
#[pallet::weight(Weight::from_ref_time(10_000) + T::DbWeight::get().writes(10))]
pub fn recovery_revenue(
origin: OriginFor<T>,
project_id: ProjectId,
revenue_id: RevenueId,
transactions: Transactions<T>,
) -> DispatchResult {
let who = ensure_signed(origin)?; // origin need to be an admin
Self::do_recovery_revenue(who, project_id, revenue_id, transactions)
}
/// Kill all the stored data.
///
/// This function is used to kill ALL the stored data.
/// Use it with caution!
///
/// ### Parameters:
/// - `origin`: The user who performs the action.
///
/// ### Considerations:
/// - This function is only available to the `admin` with sudo access.
#[pallet::call_index(23)]
#[pallet::weight(Weight::from_ref_time(10_000) + T::DbWeight::get().writes(10))]
pub fn kill_storage(origin: OriginFor<T>) -> DispatchResult {
T::RemoveOrigin::ensure_origin(origin.clone())?;
let _ = <GlobalScope<T>>::kill();
let _ = <UsersInfo<T>>::clear(1000, None);
let _ = <ProjectsInfo<T>>::clear(1000, None);
let _ = <UsersByProject<T>>::clear(1000, None);
let _ = <ProjectsByUser<T>>::clear(1000, None);
let _ = <ExpendituresInfo<T>>::clear(1000, None);
let _ = <ExpendituresByProject<T>>::clear(1000, None);
let _ = <DrawdownsInfo<T>>::clear(1000, None);
let _ = <DrawdownsByProject<T>>::clear(1000, None);
let _ = <TransactionsInfo<T>>::clear(1000, None);
let _ = <TransactionsByDrawdown<T>>::clear(1000, None);
let _ = <JobEligiblesInfo<T>>::clear(1000, None);
let _ = <JobEligiblesByProject<T>>::clear(1000, None);
let _ = <RevenuesInfo<T>>::clear(1000, None);
let _ = <RevenuesByProject<T>>::clear(1000, None);
let _ = <RevenueTransactionsInfo<T>>::clear(1000, None);
let _ = <TransactionsByRevenue<T>>::clear(1000, None);
T::Rbac::remove_pallet_storage(Self::pallet_id())?;
Ok(())
}
#[pallet::call_index(24)]
#[pallet::weight(Weight::from_ref_time(10_000) + T::DbWeight::get().writes(10))]
pub fn set_new_admin_permissions(origin: OriginFor<T>) -> DispatchResult {
T::RemoveOrigin::ensure_origin(origin.clone())?;
// New permissions for fund admin administrator role
let admin_id: [u8; 32] = ProxyRole::Administrator.id();
let pallet_id = Self::pallet_id();
let new_admin_permissions: Vec<Vec<u8>> = vec![
ProxyPermission::RecoveryDrawdown.to_vec(),
ProxyPermission::RecoveryRevenue.to_vec(),
ProxyPermission::RecoveryTransaction.to_vec(),
ProxyPermission::RecoveryRevenueTransaction.to_vec(),
ProxyPermission::BulkUploadTransaction.to_vec(),
];
T::Rbac::create_and_set_permissions(pallet_id.clone(), admin_id, new_admin_permissions)?;
Ok(())
}
}
}