Qucik Learning Symbol Section 11

Chapter 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.


//使い捨てアカウントCarolの生成
$carolKey = $facade->createAccount(PrivateKey::random());

echo "https://testnet.symbol.tools/?recipient=" . $carolKey->address . "&amount=20" . PHP_EOL;

11.1 Account Restrictions

11.1.1 Specify addresses to restrict incoming and outgoing transactions



$bobKey = $facade->createAccount(new PrivateKey('7CBA79757479402DDCDE6577F938CDE6FD9035ACADC1E343AE155EFA679D462A') );
$bobAddress = $bobKey->address;
echo 'Bob' . PHP_EOL;
echo 'Address: ' . $bobAddress . PHP_EOL;

// 制限設定
$f = AccountRestrictionFlags::ADDRESS; // アドレス制限
$f += AccountRestrictionFlags::BLOCK; // ブロック
$flags = new AccountRestrictionFlags($f);

// アドレス制限設定Tx作成
$tx = new AccountAddressRestrictionTransactionV1(
  network: new NetworkType(NetworkType::TESTNET),
  signerPublicKey: $carolKey->publicKey,
  deadline: new Timestamp($facade->now()->addHours(2)),
  restrictionFlags: $flags, // 制限フラグ
  restrictionAdditions:[
    $bobAddress
  ],  // 設定アドレス
  restrictionDeletions:[] // 削除アドレス
);
$facade->setMaxFee($tx, 100);

// 署名
$sig = $carolKey->signTransaction($tx);
$jsonPayload = $facade->attachSignature($tx, $sig);

try {
  $result = $apiInstance->announceTransaction($jsonPayload);
  echo $result . PHP_EOL;
} catch (Exception $e) {
  echo 'Exception when calling TransactionRoutesApi->announceTransaction: ', $e->getMessage(), PHP_EOL;
}

RestrictionFlags corresponds to AddressRestrictionFlag in v2.For AddressRestrictionFlag is as follows.

  • AllowIncomingAddress:Allowing incoming transactions only from specific addresses
    – symbolSdk.symbol.AccountRestrictionFlags.ADDRESS
  • AllowOutgoingAddress:Permitting outgoing transactions only to specific addresses
    – symbolSdk.symbol.AccountRestrictionFlags.ADDRESS + symbolSdk.symbol.AccountRestrictionFlags.OUTGOING
  • BlockIncomingAddress:Reject incoming transactions from designated addresses
    – symbolSdk.symbol.AccountRestrictionFlags.ADDRESS + symbolSdk.symbol.AccountRestrictionFlags.BLOCK
  • BlockOutgoingAddress:Prohibit outgoing transactions to specific addresses
    – symbolSdk.symbol.AccountRestrictionFlags.ADDRESS + symbolSdk.symbol.AccountRestrictionFlags.BLOCK + symbolSdk.symbol.AccountRestrictionFlags.OUTGOING

11.1.2 Restrictions on receiving designated mosaics


$f = AccountRestrictionFlags::MOSAIC_ID; // モザイク制限
$f += AccountRestrictionFlags::BLOCK; // ブロック
$flags = new AccountRestrictionFlags($f);

$tx = new AccountMosaicRestrictionTransactionV1(
  network: new NetworkType(NetworkType::TESTNET),
  signerPublicKey: $carolKey->publicKey,
  deadline: new Timestamp($facade->now()->addHours(2)),
  restrictionFlags: $flags, // 制限フラグ
  restrictionAdditions:[
    new UnresolvedMosaicId($namespaceId)
  ],  // 設定モザイク
  restrictionDeletions:[] // 削除モザイク
);
$facade->setMaxFee($tx, 1000);

// 署名
$sig = $carolKey->signTransaction($tx);
$jsonPayload = $facade->attachSignature($tx, $sig);

try {
  $result = $apiInstance->announceTransaction($jsonPayload);
  echo $result . PHP_EOL;
} catch (Exception $e) {
  echo 'Exception when calling TransactionRoutesApi->announceTransaction: ', $e->getMessage(), PHP_EOL;
}

As with account restrictions, restrictionFlags corresponds to MosaicRestrictionFlag in v2.MosaicRestrictionFlag is as follows.

  • AllowMosaic:Allowing to receive only transactions containing the specified mosaic
    – symbolSdk.symbol.AccountRestrictionFlags.MOSAIC_ID
  • BlockMosaic:Rejection of incoming transactions containing specified mosaics
    - symbolSdk.symbol.AccountRestrictionFlags.MOSAIC_ID + symbolSdk.symbol.AccountRestrictionFlags.BLOCK
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.

11.1.3 Restrictions on specified transactions


$f = AccountRestrictionFlags::TRANSACTION_TYPE; // トランザクション制限
$f += AccountRestrictionFlags::OUTGOING; // 送信
$flags = new AccountRestrictionFlags($f);

$tx = new AccountOperationRestrictionTransactionV1(
  network: new NetworkType(NetworkType::TESTNET),
  signerPublicKey: $carolKey->publicKey,
  deadline: new Timestamp($facade->now()->addHours(2)),
  restrictionFlags: $flags, // 制限フラグ
  restrictionAdditions:[
    new TransactionType(TransactionType::ACCOUNT_OPERATION_RESTRICTION)
  ],  // 設定トランザクション
  restrictionDeletions:[] // 削除トランザクション
);
$facade->setMaxFee($tx, 100);

// 署名
$sig = $carolKey->signTransaction($tx);
$jsonPayload = $facade->attachSignature($tx, $sig);

try {
  $result = $apiInstance->announceTransaction($jsonPayload);
  echo $result . PHP_EOL;
} catch (Exception $e) {
  echo 'Exception when calling TransactionRoutesApi->announceTransaction: ', $e->getMessage(), PHP_EOL;
}

As with account restrictions and mosaic restrictions, restrictionFlags corresponds to v2's OperationRestrictionFlag.OperationRestrictionFlag is as follows.

  • AllowOutgoingTransactionType:Permit only for specified transaction types
    – symbolSdk.symbol.AccountRestrictionFlags.TRANSACTION_TYPE + symbolSdk.symbol.AccountRestrictionFlags.OUTGOING
  • BlockOutgoingTransactionType:Prohibit only for specified transaction types
  • - symbolSdk.symbol.AccountRestrictionFlags.TRANSACTION_TYPE + symbolSdk.symbol.AccountRestrictionFlags.OUTGOING + symbolSdk.symbol.AccountRestrictionFlags.BLOCK
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: 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.

11.1.4 Confirmation

Check the information on the restrictions that you have set


$restrictionAipInstance = new RestrictionAccountRoutesApi($client, $config);
$res = $restrictionAipInstance->getAccountRestrictions($carolKey->address);
echo $res . PHP_EOL;

Sample output


{
    "accountRestrictions": {
        "version": 1,
        "address": "98070C726161DEDAC6642EB41583016DC936053BA43E050B",
        "restrictions": [
            {
                "restrictionFlags": 32769,
                "values": [
                    "98B00F753CF2564075CC94721E3BCFC4B99E38E8A3DCBBC7"
                ]
            },
            {
                "restrictionFlags": 32770,
                "values": [
                    "72C0212E67A08BCE"
                ]
            },
            {
                "restrictionFlags": 16388,
                "values": [
                    "17232"
                ]
            }
        ]
    }
}

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.

11.2.1 Creating mosaics with global restrictions

Set restrictable to true to create a mosaic in Carol.



// モザイクフラグ設定
$f = MosaicFlags::NONE;
$f += MosaicFlags::SUPPLY_MUTABLE; // 供給量変更可能
$f += MosaicFlags::TRANSFERABLE; // 第三者への譲渡可否
$f += MosaicFlags::RESTRICTABLE; //制限設定の可否
$f += MosaicFlags::REVOKABLE; //発行者からの還収可否
$flags = new MosaicFlags($f);

$mosaicId = IdGenerator::generateMosaicId($carolKey->address);

// モザイク定義
$mosaicDefTx = new EmbeddedMosaicDefinitionTransactionV1(
  network: new NetworkType(NetworkType::TESTNET),
  signerPublicKey: $carolKey->publicKey, // 署名者公開鍵
  id: new MosaicId($mosaicId['id']), // モザイクID
  divisibility: 2, // 分割可能性
  duration: new BlockDuration(0), //duration:有効期限
  nonce: new MosaicNonce($mosaicId['nonce']),
  flags: $flags,
);

// モザイク変更
$mosaicChangeTx = new EmbeddedMosaicSupplyChangeTransactionV1(
  network: new NetworkType(NetworkType::TESTNET),
  signerPublicKey: $carolKey->publicKey, // 署名者公開鍵
  mosaicId: new UnresolvedMosaicId($mosaicId['id']),
  delta: new Amount(10000),
  action: new MosaicSupplyChangeAction(MosaicSupplyChangeAction::INCREASE),
);

// キーの値と設定
$keyId = Metadata::metadataGenerateKey("KYC"); // restrictionKey

// グローバルモザイク制限
$mosaicGlobalResTx = new EmbeddedMosaicGlobalRestrictionTransactionV1(
  network: new NetworkType(NetworkType::TESTNET),
  signerPublicKey: $carolKey->publicKey,
  mosaicId: new UnresolvedMosaicId($mosaicId['id']),
  restrictionKey: $keyId,
  newRestrictionValue: 1,
  newRestrictionType: new MosaicRestrictionType(MosaicRestrictionType::EQ),
);
// 更新する場合は以下も設定する必要あり
//   - mosaicGlobalResTx.previousRestrictionValue
//   - mosaicGlobalResTx.previousRestrictionType

// マークルハッシュの算出
$embeddedTransactions = [$mosaicDefTx, $mosaicChangeTx, $mosaicGlobalResTx];
$merkleHash = $facade->hashEmbeddedTransactions($embeddedTransactions);

// アグリゲートTx作成
$aggregateTx = new AggregateCompleteTransactionV2(
  network: new NetworkType(NetworkType::TESTNET),
  signerPublicKey: $carolKey->publicKey,
  deadline: new Timestamp($facade->now()->addHours(2)),
  transactionsHash: $merkleHash,
  transactions: $embeddedTransactions
);
$facade->setMaxFee($aggregateTx, 100);  // 手数料

// 署名
$sig = $carolKey->signTransaction($aggregateTx);
$payload = $facade->attachSignature($aggregateTx, $sig);

try {
  $result = $apiInstance->announceTransaction($payload);
  echo $result . PHP_EOL;
} catch (Exception $e) {
  echo 'Exception when calling TransactionRoutesApi->announceTransaction: ', $e->getMessage(), PHP_EOL;
}

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

11.2.2 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.


// carolに適用
$carolMosaicAddressResTx = new MosaicAddressRestrictionTransactionV1(
  network: new NetworkType(NetworkType::TESTNET),
  signerPublicKey: $carolKey->publicKey,
  deadline: new Timestamp($facade->now()->addHours(2)),
  mosaicId: new UnresolvedMosaicId('0x10FE6A79F72DB356'),
  restrictionKey: $keyId,
  previousRestrictionValue: -1, // 以前のリストリクション値がなく、新規に値を設定する場合
  newRestrictionValue: 1,
  targetAddress: $carolKey->address,
);
$facade->setMaxFee($carolMosaicAddressResTx, 100);


// 署名
$sig = $carolKey->signTransaction($carolMosaicAddressResTx);
$jsonPayload = $facade->attachSignature($carolMosaicAddressResTx, $sig);

try {
  $result = $apiInstance->announceTransaction($jsonPayload);
  echo $result . PHP_EOL;
} catch (Exception $e) {
  echo 'Exception when calling TransactionRoutesApi->announceTransaction: ', $e->getMessage(), PHP_EOL;
}

// bobに適用
$bobMosaicAddressResTx = new MosaicAddressRestrictionTransactionV1(
  network: new NetworkType(NetworkType::TESTNET),
  signerPublicKey: $carolKey->publicKey,
  deadline: new Timestamp($facade->now()->addHours(2)),
  mosaicId: new UnresolvedMosaicId('0x10FE6A79F72DB356'),
  restrictionKey: $keyId,
  previousRestrictionValue: -1, // 以前のリストリクション値がなく、新規に値を設定する場合
  newRestrictionValue: 1,
  targetAddress: $bobKey->address,
);
$facade->setMaxFee($bobMosaicAddressResTx, 100);

// 署名
$sig = $carolKey->signTransaction($bobMosaicAddressResTx);
$jsonPayload = $facade->attachSignature($bobMosaicAddressResTx, $sig);

try {
  $result = $apiInstance->announceTransaction($jsonPayload);
  echo $result . PHP_EOL;
} catch (Exception $e) {
  echo 'Exception when calling TransactionRoutesApi->announceTransaction: ', $e->getMessage(), PHP_EOL;
}

11.2.3 Confirmation of restriction status check

Query the node to check its restriction status.


$restrictionAipInstance = new RestrictionMosaicRoutesApi($client, $config);
$res = $restrictionAipInstance->searchMosaicRestrictions(
  mosaic_id: '10FE6A79F72DB356'
);
echo 'MosaicRestrictions' . PHP_EOL;
echo $res . PHP_EOL;

Sample output


{
    "data": [
        {
            "id": "66A5B8E584E82060AFC8F4DD",
            "mosaicRestrictionEntry": {
                "version": 1,
                "compositeHash": "D2F056476C118C5CB1C15978B23603D404CE91629BA2DB82A3D91CEA9D6E9422",
                "entryType": 1,
                "mosaicId": "10FE6A79F72DB356",
                "restrictions": [
                    {
                        "key": "9300605567124626807",
                        "restriction": {
                            "referenceMosaicId": "0000000000000000",
                            "restrictionValue": "1",
                            "restrictionType": 1
                        }
                    }
                ]
            }
        },
        {
            "id": "66A5C05484E82060AFC900C0",
            "mosaicRestrictionEntry": {
                "version": 1,
                "compositeHash": "0E562A82F14DB98C1831B570F3D96FE7939AED5AF110FE54EC995DCE8408629F",
                "entryType": 0,
                "mosaicId": "10FE6A79F72DB356",
                "restrictions": [
                    {
                        "key": "9300605567124626807"
                    }
                ]
            }
        },
        {
            "id": "66A5C0F384E82060AFC90244",
            "mosaicRestrictionEntry": {
                "version": 1,
                "compositeHash": "164CE57733CEEFE0D8E46B05750C1209B04E96696F46204676B631A63BE005A9",
                "entryType": 0,
                "mosaicId": "10FE6A79F72DB356",
                "restrictions": [
                    {
                        "key": "9300605567124626807"
                    }
                ]
            }
        }
    ],
    "pagination": {
        "pageNumber": 1,
        "pageSize": 10
    }
}

11.2.4 Confirmation of transfer

Check the restriction status by transferring the mosaic.


// 成功(CarolからBobに送信)
$tx = new TransferTransactionV1(
  network: new NetworkType(NetworkType::TESTNET),
  signerPublicKey: $carolKey->publicKey,  // 署名者公開鍵
  deadline: new Timestamp($facade->now()->addHours(2)), // 有効期限
  recipientAddress: $bobKey->address, // 受信者アドレス
  mosaics: [
    new UnresolvedMosaic(
      mosaicId: new UnresolvedMosaicId('0x51E212A3D485C85F'),  // モザイクID
      amount: new Amount(1) // 金額
    )
  ],
  message: '',
);
$facade->setMaxFee($tx, 100);  // 手数料
$sig = $carolKey->signTransaction($tx);
$payload = $facade->attachSignature($tx, $sig);
try {
  $result = $apiInstance->announceTransaction($payload);
  echo $result . PHP_EOL;
} catch (Exception $e) {
  echo 'Exception when calling TransactionRoutesApi->announceTransaction: ', $e->getMessage(), PHP_EOL;
}
echo 'TxHash' . PHP_EOL;
echo $facade->hashTransaction($tx) . PHP_EOL;

// 失敗(CarolからDaveに送信)
$daveKey = $facade->createAccount(PrivateKey::random());

$tx = new TransferTransactionV1(
  network: new NetworkType(NetworkType::TESTNET),
  signerPublicKey: $carolKey->publicKey,  // 署名者公開鍵
  deadline: new Timestamp($facade->now()->addHours(2)), // 有効期限
  recipientAddress: $daveKey->address, // 受信者アドレス
  mosaics: [
    new UnresolvedMosaic(
      mosaicId: new UnresolvedMosaicId('0x51E212A3D485C85F'),  // モザイクID
      amount: new Amount(1) // 金額
    )
  ],
  message: '',
);
$facade->setMaxFee($tx, 100);  // 手数料
$sig = $carolKey->signTransaction($tx);
$payload = $facade->attachSignature($tx, $sig);
try {
  $result = $apiInstance->announceTransaction($payload);
  echo $result . PHP_EOL;
} catch (Exception $e) {
  echo 'Exception when calling TransactionRoutesApi->announceTransaction: ', $e->getMessage(), PHP_EOL;
}
echo 'TxHash' . PHP_EOL;
echo $facade->hashTransaction($tx) . PHP_EOL;

Failure will result in the following error status.


{"hash":"C7E0EAF9941D9030E055BE87F0F79805582CA1713680BA546837042EA3DEDBCD","code":"Failure_RestrictionMosaic_Account_Unauthorized","deadline":"54911200734","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.

11.3.1 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.)

11.3.2 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.

11.3.3 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.