Skip to content

Commit

Permalink
update
Browse files Browse the repository at this point in the history
  • Loading branch information
lidangzzz committed Feb 15, 2024
1 parent f09c712 commit d1b1ea5
Show file tree
Hide file tree
Showing 6 changed files with 295 additions and 17 deletions.
93 changes: 85 additions & 8 deletions darc-docs/docs/By-law Script/Getting Started.md
Original file line number Diff line number Diff line change
Expand Up @@ -101,15 +101,92 @@ This script encapsulates all the operations into a single program, ensuring that
Plugin is the core mechanism of DARC and serves as its legal framework. All rules within DARC are based on the plugin system. By-law Script supports operator overload to make the composition and design of plugins simpler and more convenient. In By-law Script, each plugin is an object body. Below is the simplest example:

```javascript
const plugin_0 ={
returnType: NO, // return type: NO
level: 3, // level 3
const plugin_0 = {
returnType: NO, // return type: NO
level: 3, // level 3
votingRuleIndex: 0, // voting rule index, if voting is required
notes: "disable all operations", // the notes of the plugin
bIsEnabled: true, // the plugin is enabled. this is the default value
bIsBeforeOperation: true, // if the plugin is executed before the operation
conditionNodes: new TRUE() // condition: always true
},
```

In the above plugin, we define conditionNodes with only one node, which is the object TRUE() we created. This plugin signifies that before any program or operation is executed, this plugin will be triggered. The returnType of this plugin is NO, indicating that whenever this plugin is triggered, it will be rejected. Therefore, when this plugin is successfully deployed in DARC, if no plugin of a higher level than level 3 is triggered to allow execution, then any operation will be rejected.

Below is another example of a plugin:

```javascript
const plugin_before_op_1 = {
returnType: SANDBOX_NEEDED, // return type: SANDBOX_NEEDED
level: 4, // level 3
votingRuleIndex: 0, // voting rule index, if voting is required
notes: "minting tokens should be checked", // the notes of the plugin
bIsEnabled: true, // the plugin is enabled. this is the default value
bIsBeforeOperation: true, // if the plugin is executed before the operation
conditionNodes:
// if the operation is minting tokens or creating token classes
(operation_equals(EnumOpcode.BATCH_MINT_TOKENS) |
operation_equals(EnumOpcode.BATCH_PAY_TO_MINT_TOKENS))

// and the token index is in range [0, 3], which means the token index is 0, 1, 2, or 3
& batch_op_any_token_class_in_range(0, 3)
}

const plugin_after_op_1 = {
returnType: NO,
level: 6,
votingRuleIndex: 0,
notes: "disable all program",
notes: "address_A must holds at least 20% of total voting and dividend weight",
bIsEnabled: true,
bIsBeforeOperation: true,
conditionNodes: new TRUE() // always true
},
bIsBeforeOperation: false, // after-operation plugin
conditionNodes:

// if the address_A's voting weight percentage is less than 20%
// or the address_A's dividend weight percentage is less than 20%
address_voting_weight_percenrage_less_than(address_A, 20)
| address_dividend_weight_percenrage_less_than(address_A, 20)
}

const plugin_before_op_2 = {
returnType: NO,
level: 6,
votingRuleIndex: 0,
notes: "no one can disable before-op plugin 1,2,3 or after-op plugin 1",
bIsEnabled: true,
bIsBeforeOperation: true, // before-operation plugin
conditionNodes:

operation_equals(EnumOpcode.BATCH_DISABLE_PLUGINS)
&
disable_any_before_op_plugin_index_in_list([1,2,3])
| disable_any_after_op_plugin_index_in_list([1])
& not(operator_address_equals(address_A))
}

const plugin_before_op_3 = {
returnType: YES_AND_SKIP_SANDBOX,
level: 7,
votingRuleIndex: 0,
notes: "only address_A can disable before-op plugin 1,2,3 and after-op plugin 1",
bIsEnabled: true,
bIsBeforeOperation: true, // before-operation plugin
conditionNodes:
operation_equals(EnumOpcode.BATCH_DISABLE_PLUGINS)
&
disable_any_before_op_plugin_index_in_list([1,2,3])
| disable_any_after_op_plugin_index_in_list([1])
& operator_address_equals(address_A)
}
```

In the plugin

In the example provided, we have defined four plugins:

1. The first plugin marks any operation as SANDBOX_NEEDED if it is either batch_mint_tokens or batch_pay_to_mint_tokens, and the token level is 0, 1, 2, or 3. This plugin ensures that any addition to the supply of tokens at these levels must undergo sandbox checks.

2. The second plugin marks any operation as NO if, after the execution of any program, the total voting or total dividend rights of address_A fall below 20% in the sandbox. This ensures that address_A retains anti-dilution ownership of 20% of the total shares, regardless of how other operators increase share issuance.

3. The third plugin directly rejects any operation that is batch_disable_plugins, and the disabled plugin indexes are 1, 2, 3 in the before-operation plugin list, or 1 in the after-operation plugin list, and the operator address is not equal to address_A. This plugin ensures that no one other than address_A can disable this set of four plugins, thereby securing the 20% non-dilutable ownership of address_A.

4. The fourth plugin allows any operation that is batch_disable_plugins, and the disabled plugin indexes are 1, 2, 3 in the before-operation plugin list, or 1 in the after-operation plugin list, and the operator address is equal to address_A. This plugin ensures that this set of four plugins can be disabled by anyone other than address_A, allowing address_A to waive the anti-dilution feature of its ownership by disabling these four plugins.
63 changes: 62 additions & 1 deletion darc-js/src/SDK/conditionNodes/Condition_MachineState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -446,6 +446,61 @@ function token_in_list_amount_equals(tokenClassList: number[], amount: number) {
});
}

function address_voting_weight_percenrage_greater_than(amount: number, address: string) {
return expression(95, {
STRING_ARRAY: [],
UINT256_2DARRAY: [[amount]],
ADDRESS_2DARRAY: [[address]],
BYTES: []
});
}

function address_voting_weight_percenrage_less_than(amount: number, address: string) {
return expression(96, {
STRING_ARRAY: [],
UINT256_2DARRAY: [[amount]],
ADDRESS_2DARRAY: [[address]],
BYTES: []
});
}

function address_voting_weight_percenrage_in_range(amount: number, address: string) {
return expression(97, {
STRING_ARRAY: [],
UINT256_2DARRAY: [[amount]],
ADDRESS_2DARRAY: [[address]],
BYTES: []
});
}

function address_dividend_weight_percenrage_greater_than(amount: number, address: string) {
return expression(98, {
STRING_ARRAY: [],
UINT256_2DARRAY: [[amount]],
ADDRESS_2DARRAY: [[address]],
BYTES: []
});
}

function address_dividend_weight_percenrage_less_than(amount: number, address: string) {
return expression(99, {
STRING_ARRAY: [],
UINT256_2DARRAY: [[amount]],
ADDRESS_2DARRAY: [[address]],
BYTES: []
});
}

function address_dividend_weight_percenrage_in_range(amount: number, address: string) {
return expression(100, {
STRING_ARRAY: [],
UINT256_2DARRAY: [[amount]],
ADDRESS_2DARRAY: [[address]],
BYTES: []
});
}


export {
timestamp_greater_than,
timestamp_less_than,
Expand Down Expand Up @@ -490,5 +545,11 @@ export {
token_in_list_amount_greater_than,
token_in_list_amount_less_than,
token_in_list_amount_in_range,
token_in_list_amount_equals
token_in_list_amount_equals,
address_voting_weight_percenrage_greater_than,
address_voting_weight_percenrage_less_than,
address_voting_weight_percenrage_in_range,
address_dividend_weight_percenrage_greater_than,
address_dividend_weight_percenrage_less_than,
address_dividend_weight_percenrage_in_range
};
8 changes: 7 additions & 1 deletion darc-js/src/SDK/includes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -391,7 +391,13 @@ export {
token_in_list_amount_greater_than,
token_in_list_amount_less_than,
token_in_list_amount_in_range,
token_in_list_amount_equals
token_in_list_amount_equals,
address_voting_weight_percenrage_greater_than,
address_voting_weight_percenrage_less_than,
address_voting_weight_percenrage_in_range,
address_dividend_weight_percenrage_greater_than,
address_dividend_weight_percenrage_less_than,
address_dividend_weight_percenrage_in_range
} from "./conditionNodes/Condition_MachineState";

export { change_member_role_to_any_role_equals, change_member_role_to_any_role_in_list, change_member_role_to_any_role_in_range, change_member_name_to_any_string_in_list, change_member_name_to_any_string_contains } from "./conditionNodes/Condition_MembershipOp";
Expand Down
8 changes: 7 additions & 1 deletion darc-js/src/darcjs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -426,7 +426,13 @@ export {
token_in_list_amount_greater_than,
token_in_list_amount_less_than,
token_in_list_amount_in_range,
token_in_list_amount_equals
token_in_list_amount_equals,
address_voting_weight_percenrage_greater_than,
address_voting_weight_percenrage_less_than,
address_voting_weight_percenrage_in_range,
address_dividend_weight_percenrage_greater_than,
address_dividend_weight_percenrage_less_than,
address_dividend_weight_percenrage_in_range
} from "./SDK/conditionNodes/Condition_MachineState";

export { change_member_role_to_any_role_equals, change_member_role_to_any_role_in_list, change_member_role_to_any_role_in_range, change_member_name_to_any_string_in_list, change_member_name_to_any_string_contains } from "./SDK/conditionNodes/Condition_MembershipOp";
Expand Down
128 changes: 128 additions & 0 deletions darc-protocol/contracts/protocol/Plugin/Condition_MachineState.sol
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import "../MachineStateManager.sol";
import "../Utilities/StringUtils.sol";
import "../Utilities/OpcodeMap.sol";
import "../Plugin.sol";
import "@openzeppelin/contracts-upgradeable/utils/math/SafeMathUpgradeable.sol";
//import "./Conditions";

contract Condition_MachineState is MachineStateManager {
Expand Down Expand Up @@ -69,6 +70,13 @@ contract Condition_MachineState is MachineStateManager {
else if (id==92) return ID_92_TOKEN_IN_LIST_AMOUNT_LESS_THAN(bIsBeforeOperation, param);
else if (id==93) return ID_93_TOKEN_IN_LIST_AMOUNT_IN_RANGE(bIsBeforeOperation, param);
else if (id==94) return ID_94_TOKEN_IN_LIST_AMOUNT_EQUALS(bIsBeforeOperation, param);

else if (id==95) return ID_95_ADDRESS_VOTING_WEIGHT_PERCENTAGE_GREATER_THAN(bIsBeforeOperation, param);
else if (id==96) return ID_96_ADDRESS_VOTING_WEIGHT_PERCENTAGE_LESS_THAN(bIsBeforeOperation, param);
else if (id==97) return ID_97_ADDRESS_VOTING_WEIGHT_PERCENTAGE_IN_RANGE(bIsBeforeOperation, param);
else if (id==98) return ID_98_ADDRESS_DIVIDEND_WEIGHT_PERCENTAGE_GREATER_THAN(bIsBeforeOperation, param);
else if (id==99) return ID_99_ADDRESS_DIVIDEND_WEIGHT_PERCENTAGE_LESS_THAN(bIsBeforeOperation, param);
else if (id==100) return ID_100_ADDRESS_DIVIDEND_WEIGHT_PERCENTAGE_IN_RANGE(bIsBeforeOperation, param);
else return false;
}

Expand Down Expand Up @@ -543,6 +551,72 @@ contract Condition_MachineState is MachineStateManager {
return totalAmount == param.UINT256_2DARRAY[1][0];
}

function ID_95_ADDRESS_VOTING_WEIGHT_PERCENTAGE_GREATER_THAN(bool bIsBeforeOp, NodeParam memory param) private view returns (bool) {
require(param.ADDRESS_2DARRAY.length == 1, "CE ID_95: ADDRESS_2DARRAY must have 1 element");
require(param.UINT256_2DARRAY.length == 1, "CE ID_95: UINT256_2DARRAY must have 1 element");
require(param.UINT256_2DARRAY[0].length == 1, "CE ID_95: UINT256_2DARRAY[0] must have 1 element");
if (bIsBeforeOp) {
return getAddressTotalVotingWeightPercentage(false, param.ADDRESS_2DARRAY[0][0]) > param.UINT256_2DARRAY[0][0];
} else {
return getAddressTotalVotingWeightPercentage(true, param.ADDRESS_2DARRAY[0][0]) > param.UINT256_2DARRAY[0][0];
}
}

function ID_96_ADDRESS_VOTING_WEIGHT_PERCENTAGE_LESS_THAN(bool bIsBeforeOp, NodeParam memory param) private view returns (bool) {
require(param.ADDRESS_2DARRAY.length == 1, "CE ID_96: ADDRESS_2DARRAY must have 1 element");
require(param.UINT256_2DARRAY.length == 1, "CE ID_96: UINT256_2DARRAY must have 1 element");
require(param.UINT256_2DARRAY[0].length == 1, "CE ID_96: UINT256_2DARRAY[0] must have 1 element");
if (bIsBeforeOp) {
return getAddressTotalVotingWeightPercentage(false, param.ADDRESS_2DARRAY[0][0]) < param.UINT256_2DARRAY[0][0];
} else {
return getAddressTotalVotingWeightPercentage(true, param.ADDRESS_2DARRAY[0][0]) < param.UINT256_2DARRAY[0][0];
}
}

function ID_97_ADDRESS_VOTING_WEIGHT_PERCENTAGE_IN_RANGE(bool bIsBeforeOp, NodeParam memory param) private view returns (bool) {
require(param.ADDRESS_2DARRAY.length == 1, "CE ID_97: ADDRESS_2DARRAY must have 1 element");
require(param.UINT256_2DARRAY.length == 1, "CE ID_97: UINT256_2DARRAY must have 1 element");
require(param.UINT256_2DARRAY[0].length == 2, "CE ID_97: UINT256_2DARRAY[0] must have 2 elements");
if (bIsBeforeOp) {
return getAddressTotalVotingWeightPercentage(false, param.ADDRESS_2DARRAY[0][0]) >= param.UINT256_2DARRAY[0][0] && getAddressTotalVotingWeightPercentage(false, param.ADDRESS_2DARRAY[0][0]) <= param.UINT256_2DARRAY[0][1];
} else {
return getAddressTotalVotingWeightPercentage(true, param.ADDRESS_2DARRAY[0][0]) >= param.UINT256_2DARRAY[0][0] && getAddressTotalVotingWeightPercentage(true, param.ADDRESS_2DARRAY[0][0]) <= param.UINT256_2DARRAY[0][1];
}
}

function ID_98_ADDRESS_DIVIDEND_WEIGHT_PERCENTAGE_GREATER_THAN(bool bIsBeforeOp, NodeParam memory param) private view returns (bool) {
require(param.ADDRESS_2DARRAY.length == 1, "CE ID_98: ADDRESS_2DARRAY must have 1 element");
require(param.UINT256_2DARRAY.length == 1, "CE ID_98: UINT256_2DARRAY must have 1 element");
require(param.UINT256_2DARRAY[0].length == 1, "CE ID_98: UINT256_2DARRAY[0] must have 1 element");
if (bIsBeforeOp) {
return getAddressTotalDividendWeightPercentage(false, param.ADDRESS_2DARRAY[0][0]) > param.UINT256_2DARRAY[0][0];
} else {
return getAddressTotalDividendWeightPercentage(true, param.ADDRESS_2DARRAY[0][0]) > param.UINT256_2DARRAY[0][0];
}
}

function ID_99_ADDRESS_DIVIDEND_WEIGHT_PERCENTAGE_LESS_THAN(bool bIsBeforeOp, NodeParam memory param) private view returns (bool) {
require(param.ADDRESS_2DARRAY.length == 1, "CE ID_99: ADDRESS_2DARRAY must have 1 element");
require(param.UINT256_2DARRAY.length == 1, "CE ID_99: UINT256_2DARRAY must have 1 element");
require(param.UINT256_2DARRAY[0].length == 1, "CE ID_99: UINT256_2DARRAY[0] must have 1 element");
if (bIsBeforeOp) {
return getAddressTotalDividendWeightPercentage(false, param.ADDRESS_2DARRAY[0][0]) < param.UINT256_2DARRAY[0][0];
} else {
return getAddressTotalDividendWeightPercentage(true, param.ADDRESS_2DARRAY[0][0]) < param.UINT256_2DARRAY[0][0];
}
}

function ID_100_ADDRESS_DIVIDEND_WEIGHT_PERCENTAGE_IN_RANGE(bool bIsBeforeOp, NodeParam memory param) private view returns (bool) {
require(param.ADDRESS_2DARRAY.length == 1, "CE ID_100: ADDRESS_2DARRAY must have 1 element");
require(param.UINT256_2DARRAY.length == 1, "CE ID_100: UINT256_2DARRAY must have 1 element");
require(param.UINT256_2DARRAY[0].length == 2, "CE ID_100: UINT256_2DARRAY[0] must have 2 elements");
if (bIsBeforeOp) {
return getAddressTotalDividendWeightPercentage(false, param.ADDRESS_2DARRAY[0][0]) >= param.UINT256_2DARRAY[0][0] && getAddressTotalDividendWeightPercentage(false, param.ADDRESS_2DARRAY[0][0]) <= param.UINT256_2DARRAY[0][1];
} else {
return getAddressTotalDividendWeightPercentage(true, param.ADDRESS_2DARRAY[0][0]) >= param.UINT256_2DARRAY[0][0] && getAddressTotalDividendWeightPercentage(true, param.ADDRESS_2DARRAY[0][0]) <= param.UINT256_2DARRAY[0][1];
}
}


//below are the helper functions
function getDateTime(uint256 timestamp) public pure returns (uint256 year, uint256 month, uint256 day, uint256 hour, uint256 minute, uint256 second) {
Expand Down Expand Up @@ -584,4 +658,58 @@ contract Condition_MachineState is MachineStateManager {

return (_year, _month + 1, _day, _hour, _minute, _second);
}

/**
* @dev Get the total voting weight for a token class
*/
function getAddressTotalVotingWeightPercentage(bool bIsBeforeOp, address addr) private view returns (uint256) {
if (bIsBeforeOp) {
bool bIsValid = false;
uint256 result = 0;

// multiply by 100 to get percentage
(bIsValid, result) = SafeMathUpgradeable.tryMul(addressTotalVotingWeight(false, addr), 100);
require(bIsValid, "CE getAddressTotalVotingWeightPercentage: SafeMathUpgradeable multiplication error");
(bIsValid, result) = SafeMathUpgradeable.tryDiv(result, totalVotingWeights(false));
require(bIsValid, "CE getAddressTotalVotingWeightPercentage: SafeMathUpgradeable division error");
return result;
} else {
bool bIsValid = false;
uint256 result = 0;

// multiply by 100 to get percentage
(bIsValid, result) = SafeMathUpgradeable.tryMul(addressTotalVotingWeight(true, addr), 100);
require(bIsValid, "CE getAddressTotalVotingWeightPercentage: SafeMathUpgradeable multiplication error");
(bIsValid, result) = SafeMathUpgradeable.tryDiv(result, totalVotingWeights(true));
require(bIsValid, "CE getAddressTotalVotingWeightPercentage: SafeMathUpgradeable division error");
return result;
}
}

/**
* @dev Get the total dividend weight for a token class
*/
function getAddressTotalDividendWeightPercentage(bool bIsBeforeOp, address addr) private view returns (uint256) {
if (bIsBeforeOp) {
bool bIsValid = false;
uint256 result = 0;

// multiply by 100 to get percentage
(bIsValid, result) = SafeMathUpgradeable.tryMul(addressTotalDividendWeight(false, addr), 100);
require(bIsValid, "CE getAddressTotalDividendWeightPercentage: SafeMathUpgradeable multiplication error");
(bIsValid, result) = SafeMathUpgradeable.tryDiv(result, totalDividendWeights(false));
require(bIsValid, "CE getAddressTotalDividendWeightPercentage: SafeMathUpgradeable division error");
return result;
} else {
bool bIsValid = false;
uint256 result = 0;

// multiply by 100 to get percentage
(bIsValid, result) = SafeMathUpgradeable.tryMul(addressTotalDividendWeight(true, addr), 100);
require(bIsValid, "CE getAddressTotalDividendWeightPercentage: SafeMathUpgradeable multiplication error");
(bIsValid, result) = SafeMathUpgradeable.tryDiv(result, totalDividendWeights(true));
require(bIsValid, "CE getAddressTotalDividendWeightPercentage: SafeMathUpgradeable division error");
return result;
}
}
}
12 changes: 6 additions & 6 deletions darc-specs/condition_expression.md
Original file line number Diff line number Diff line change
Expand Up @@ -129,12 +129,12 @@ For more details, please refer to [DARC Instruction Set Opcode Table(opcode.md)]
| 92 | TOKEN_IN_LIST_AMOUNT_LESS_THAN | UINT256_2DARRAY[0] tokenClassList, UINT256_2DARRAY[1][0] amount ||
| 93 | TOKEN_IN_LIST_AMOUNT_IN_RANGE | UINT256_2DARRAY[0] tokenClassList, UINT256_2DARRAY[1][0] amount ||
| 94 | TOKEN_IN_LIST_AMOUNT_EQUALS| UINT256_2DARRAY[0] tokenClassList, UINT256_2DARRAY[1][0] amount ||
| 95 | Placeholder95 | | |
| 96 | Placeholder96 | | |
| 97 | Placeholder97 | | |
| 98 | Placeholder98 | | |
| 99 | Placeholder99 | | |
| 100 | Placeholder100 | | |
| 95 | ADDRESS_VOTING_WEIGHT_PERCENTAGE_GREATER_THAN| UINT256_2DARRAY[0][0] amount, ADDRESS_2DARRAY[0][0] address ||
| 96 | ADDRESS_VOTING_WEIGHT_PERCENTAGE_LESS_THAN | UINT256_2DARRAY[0][0] amount, ADDRESS_2DARRAY[0][0] address ||
| 97 | ADDRESS_VOTING_WEIGHT_PERCENTAGE_IN_RANGE | UINT256_2DARRAY[0][0] amount, ADDRESS_2DARRAY[0][0] address ||
| 98 | ADDRESS_DIVIDEND_WEIGHT_PERCENTAGE_GREATER_THAN | UINT256_2DARRAY[0][0] amount, ADDRESS_2DARRAY[0][0] address ||
| 99 | ADDRESS_DIVIDEND_WEIGHT_PERCENTAGE_LESS_THAN| UINT256_2DARRAY[0][0] amount, ADDRESS_2DARRAY[0][0] address ||
| 100 | ADDRESS_DIVIDEND_WEIGHT_PERCENTAGE_IN_RANGE | UINT256_2DARRAY[0][0] amount, ADDRESS_2DARRAY[0][0] address ||
| 101 | Placeholder101 | | |
| 102 | Placeholder102 | | |
| 103 | Placeholder103 | | |
Expand Down

0 comments on commit d1b1ea5

Please sign in to comment.