11. Restrictions
This section describes restrictions on accounts and global restrictions on mosaics. In this chapter, we will restrict the permissions of existing accounts, so please create a new disposable account to try it out.
//Generating disposable accounts Carol
carol = sym.Account.generateNewAccount(networkType);
console.log(carol.address);
//Outlet FAUCET URL
console.log(
"https://testnet.symbol.tools/?recipient=" +
carol.address.plain() +
"&amount=100"
);
11.1 Account Restrictions
Specify addresses to restrict incoming and outgoing transactions
bob = sym.Account.generateNewAccount(networkType);
tx =
sym.AccountRestrictionTransaction.createAddressRestrictionModificationTransaction(
sym.Deadline.create(epochAdjustment),
sym.AddressRestrictionFlag.BlockIncomingAddress, //Address restriction flag
[bob.address], //Setup address
[], //Cancellation address
networkType
).setMaxFee(100);
signedTx = carol.sign(tx, generationHash);
await txRepo.announce(signedTx).toPromise();
For AddressRestrictionFlag is as follows.
{1: 'AllowIncomingAddress', 16385: 'AllowOutgoingAddress', 32769: 'BlockIncomingAddress', 49153: 'BlockOutgoingAddress'}
In addition to AllowIncomingAddress, the following flags can be used for AddressRestrictionFlag.
- AllowIncomingAddress:Allowing incoming transactions only from specific addresses
- AllowOutgoingAddress:Permitting outgoing transactions only to specific addresses
- BlockIncomingAddress:Reject incoming transactions from designated addresses
- BlockOutgoingAddress:Prohibit outgoing transactions to specific addresses
Restrictions on receiving designated mosaics
mosaicId = new sym.MosaicId("72C0212E67A08BCE"); //Testnet XYM
tx =
sym.AccountRestrictionTransaction.createMosaicRestrictionModificationTransaction(
sym.Deadline.create(epochAdjustment),
sym.MosaicRestrictionFlag.BlockMosaic, //Mosaic restriction flag
[mosaicId], //Setup mosaic
[], //Cancellation mosaic
networkType
).setMaxFee(100);
signedTx = carol.sign(tx, generationHash);
await txRepo.announce(signedTx).toPromise();
MosaicRestrictionFlag is as follows.
{2: 'AllowMosaic', 32770: 'BlockMosaic'}
- AllowMosaic:Allowing to receive only transactions containing the specified mosaic
- BlockMosaic:Rejection of incoming transactions containing specified mosaics
There is no restriction function for mosaic outgoing transactions. Please note that this should not to be confused with the global mosaic restriction, which restricts the behaviour of mosaics, described below.
Restrictions on specified transactions
tx =
sym.AccountRestrictionTransaction.createOperationRestrictionModificationTransaction(
sym.Deadline.create(epochAdjustment),
sym.OperationRestrictionFlag.AllowOutgoingTransactionType,
[sym.TransactionType.ACCOUNT_OPERATION_RESTRICTION], //Setup transaction
[], //Cancellation transaction
networkType
).setMaxFee(100);
signedTx = carol.sign(tx, generationHash);
await txRepo.announce(signedTx).toPromise();
OperationRestrictionFlag is as follows.
{16388: 'AllowOutgoingTransactionType', 49156: 'BlockOutgoingTransactionType'}
- AllowOutgoingTransactionType:Permit only for specified transaction types
- BlockOutgoingTransactionType:Prohibit only for specified transaction types
There is no restriction function for transaction receipts. The operations that can be specified are as follows.
TransactionType is as follows.
{16705: 'AGGREGATE_COMPLETE', 16707: 'VOTING_KEY_LINK', 16708: 'ACCOUNT_METADATA', 16712: 'HASH_LOCK', 16716: 'ACCOUNT_KEY_LINK', 16717: 'MOSAIC_DEFINITION', 16718: 'NAMESPACE_REGISTRATION', 16720: 'ACCOUNT_ADDRESS_RESTRICTION', 16721: 'MOSAIC_GLOBAL_RESTRICTION', 16722: 'SECRET_LOCK', 16724: 'TRANSFER', 16725: 'MULTISIG_ACCOUNT_MODIFICATION', 16961: 'AGGREGATE_BONDED', 16963: 'VRF_KEY_LINK', 16964: 'MOSAIC_METADATA', 16972: 'NODE_KEY_LINK', 16973: 'MOSAIC_SUPPLY_CHANGE', 16974: 'ADDRESS_ALIAS', 16976: 'ACCOUNT_MOSAIC_RESTRICTION', 16977: 'MOSAIC_ADDRESS_RESTRICTION', 16978: 'SECRET_PROOF', 17220: 'NAMESPACE_METADATA', 17229: 'MOSAIC_SUPPLY_REVOCATION', 17230: 'MOSAIC_ALIAS'}
Note
17232: ACCOUNT_OPERATION_RESTRICTION
restriction is not permitted. This means that if AllowOutgoingTransactionType is specified, ACCOUNT_OPERATION_RESTRICTION must be included, and If BlockOutgoingTransactionType is specified, ACCOUNT_OPERATION_RESTRICTION cannot be included.
Confirmation
Check the information on the restrictions that you have set
resAccountRepo = repo.createRestrictionAccountRepository();
res = await resAccountRepo.getAccountRestrictions(carol.address).toPromise();
console.log(res);
Sample output
> AccountRestrictions
address: Address {address: 'TBXUTAX6O6EUVPB6X7OBNX6UUXBMPPAFX7KE5TQ', networkType: 152}
> restrictions: Array(2)
0: AccountRestriction
restrictionFlags: 32770
values: Array(1)
0: MosaicId
id: Id {lower: 1360892257, higher: 309702839}
1: AccountRestriction
restrictionFlags: 49153
values: Array(1)
0: Address {address: 'TCW2ZW7LVJMS4LWUQ7W6NROASRE2G2QKSBVCIQY', networkType: 152}
11.2 Mosaic Global Restriction
Mosaic Global Restriction sets the conditions under which mosaics can be transferred.
Assigning to each account for numeric metadata dedicated to the mosaic global restriction.
The relevant mosaic can only be sent if both the incoming and outgoing accounts meet the conditions.
Firstly, setting up the necessary libraries.
nsRepo = repo.createNamespaceRepository();
resMosaicRepo = repo.createRestrictionMosaicRepository();
mosaicResService = new sym.MosaicRestrictionTransactionService(
resMosaicRepo,
nsRepo
);
Creating mosaics with global restrictions
Set restrictable to true to create a mosaic in Carol.
supplyMutable = true; //Availability of changes in supply
transferable = true; //Transferability to third parties
restrictable = true; //Availability of global restriction settings
revokable = true; //Revokability from the issuer
nonce = sym.MosaicNonce.createRandom();
mosaicDefTx = sym.MosaicDefinitionTransaction.create(
undefined,
nonce,
sym.MosaicId.createFromNonce(nonce, carol.address),
sym.MosaicFlags.create(supplyMutable, transferable, restrictable, revokable),
0, //divisibility
sym.UInt64.fromUint(0), //duration
networkType
);
//Mosaic change
mosaicChangeTx = sym.MosaicSupplyChangeTransaction.create(
undefined,
mosaicDefTx.mosaicId,
sym.MosaicSupplyChangeAction.Increase,
sym.UInt64.fromUint(1000000),
networkType
);
//Mosaic Global Restriction
key = sym.KeyGenerator.generateUInt64Key("KYC"); // restrictionKey
mosaicGlobalResTx = await mosaicResService
.createMosaicGlobalRestrictionTransaction(
undefined,
networkType,
mosaicDefTx.mosaicId,
key,
"1",
sym.MosaicRestrictionType.EQ
)
.toPromise();
aggregateTx = sym.AggregateTransaction.createComplete(
sym.Deadline.create(epochAdjustment),
[
mosaicDefTx.toAggregate(carol.publicAccount),
mosaicChangeTx.toAggregate(carol.publicAccount),
mosaicGlobalResTx.toAggregate(carol.publicAccount),
],
networkType,
[]
).setMaxFeeForAggregate(100, 0);
signedTx = carol.sign(aggregateTx, generationHash);
await txRepo.announce(signedTx).toPromise();
MosaicRestrictionType is as follows.
{0: 'NONE', 1: 'EQ', 2: 'NE', 3: 'LT', 4: 'LE', 5: 'GT', 6: 'GE'}
Operator | Abbreviation | English |
---|---|---|
= | EQ | equal to |
!= | NE | not equal to |
< | LT | less than |
<= | LE | less than or equal to |
> | GT | greater than |
<= | GE | greater than or equal to |
Applying mosaic restrictions to accounts
Add eligibility information against the Mosaic Global Restriction to Carol and Bob.
There are no restrictions on mosaics already owned, as these restrictions apply to incoming and outgoing transactions.
For a successful transfer, both sender and receiver must fulfil the conditions.
Restrictions can be placed on any account with the private key of the mosaic creator without requiring a signature of consent.
//Apply to Carol
carolMosaicAddressResTx = sym.MosaicAddressRestrictionTransaction.create(
sym.Deadline.create(epochAdjustment),
mosaicDefTx.mosaicId, // mosaicId
sym.KeyGenerator.generateUInt64Key("KYC"), // restrictionKey
carol.address, // address
sym.UInt64.fromUint(1), // newRestrictionValue
networkType,
sym.UInt64.fromHex("FFFFFFFFFFFFFFFF") //previousRestrictionValue
).setMaxFee(100);
signedTx = carol.sign(carolMosaicAddressResTx, generationHash);
await txRepo.announce(signedTx).toPromise();
//Apply to Bob
bob = sym.Account.generateNewAccount(networkType);
bobMosaicAddressResTx = sym.MosaicAddressRestrictionTransaction.create(
sym.Deadline.create(epochAdjustment),
mosaicDefTx.mosaicId, // mosaicId
sym.KeyGenerator.generateUInt64Key("KYC"), // restrictionKey
bob.address, // address
sym.UInt64.fromUint(1), // newRestrictionValue
networkType,
sym.UInt64.fromHex("FFFFFFFFFFFFFFFF") //previousRestrictionValue
).setMaxFee(100);
signedTx = carol.sign(bobMosaicAddressResTx, generationHash);
await txRepo.announce(signedTx).toPromise();
Confirmation of restriction status check
Query the node to check its restriction status.
res = await resMosaicRepo
.search({ mosaicId: mosaicDefTx.mosaicId })
.toPromise();
console.log(res);
Sample output
> data
> 0: MosaicGlobalRestriction
compositeHash: "68FBADBAFBD098C157D42A61A7D82E8AF730D3B8C3937B1088456432CDDB8373"
entryType: 1
> mosaicId: MosaicId
id: Id {lower: 2467167064, higher: 973862467}
> restrictions: Array(1)
0: MosaicGlobalRestrictionItem
key: UInt64 {lower: 2424036727, higher: 2165465980}
restrictionType: 1
restrictionValue: UInt64 {lower: 1, higher: 0}
> 1: MosaicAddressRestriction
compositeHash: "920BFD041B6D30C0799E06585EC5F3916489E2DDF47FF6C30C569B102DB39F4E"
entryType: 0
> mosaicId: MosaicId
id: Id {lower: 2467167064, higher: 973862467}
> restrictions: Array(1)
0: MosaicAddressRestrictionItem
key: UInt64 {lower: 2424036727, higher: 2165465980}
restrictionValue: UInt64 {lower: 1, higher: 0}
targetAddress: Address {address: 'TAZCST2RBXDSD3227Y4A6ZP3QHFUB2P7JQVRYEI', networkType: 152}
> 2: MosaicAddressRestriction
...
Confirmation of transfer
Check the restriction status by transferring the mosaic.
//Success (Carol to Bob)
trTx = sym.TransferTransaction.create(
sym.Deadline.create(epochAdjustment),
bob.address,
[new sym.Mosaic(mosaicDefTx.mosaicId, sym.UInt64.fromUint(1))],
sym.PlainMessage.create(""),
networkType
).setMaxFee(100);
signedTx = carol.sign(trTx, generationHash);
await txRepo.announce(signedTx).toPromise();
//Failed (Carol to Dave)
dave = sym.Account.generateNewAccount(networkType);
trTx = sym.TransferTransaction.create(
sym.Deadline.create(epochAdjustment),
dave.address,
[new sym.Mosaic(mosaicDefTx.mosaicId, sym.UInt64.fromUint(1))],
sym.PlainMessage.create(""),
networkType
).setMaxFee(100);
signedTx = carol.sign(trTx, generationHash);
await txRepo.announce(signedTx).toPromise();
Failure will result in the following error status.
{"hash":"E3402FB7AE21A6A64838DDD0722420EC67E61206C148A73B0DFD7F8C098062FA","code":"Failure_RestrictionMosaic_Account_Unauthorized","deadline":"12371602742","group":"failed"}
11.3 Tips for use
"Account restriction" and "Mosaic Global Restriction" features can be used to control the properties of Symbol accounts and mosaics. The flexibility of restrictions has the potential to fulfil practical use cases of the Symbol blockchain in real-world situations. For example, it could be necessary to place limitations on the transfer of a specific mosaic to comply with laws and regulations or to avoid specific tokens issued by a business from being traded. Accounts can also be limited to restrict incoming transactions of certain mosaics or from specific users to avoid spam or malicious transactions providing additional safety to Symbol users.
Account burn
Using "AllowIncomingAddress" to limit funds being received only from a specified address and then sending the entire XYM balance to another account a user can explicitly create an account that is difficult to operate on its own, even with the private key. (Note, it is possibly to be authorised by a node whose minimum fee is 0.)
Mosaic lock
A mosaic can be issued with non-transferable settings, if the account creator prohibits the mosaic from being received by their account then the mosaic is locked and cannot be moved from the recipient's account.
Proof of membership
Proof of ownership was explained in the chapter on mosaics. By utilising the mosaic global restriction, it is possible to create a mosaic that can only be owned and circulated between accounts that have for instance, gone through a KYC process, creating a unique economic zone to which only the owner can belong.