モザイクの制限を第三者に委任する

別のアカウントがモザイクに制限を追加できるようにします。

ユースケース

別の会社の ComfyClothingCompany は STO を実施しようとしています。このケースでは、彼らは KYC & AML に特化した会社に KYC プロセスを委任したい と考えています。

前のガイド ( モザイク転送を制限する ) に従っている場合は、グローバル モザイク制限 に一致するように異なるキー値を組み合わせて、アカウントが特定のモザイクのトランザクションを制限する方法がわかるでしょう。

../../_images/delegated-mosaic-restriction-sto.png

ユースケース図

このガイドでは、KYC プロバイダーが許可していない場合において、アカウント間の cc.shares - ComfyClothingCompany が作成したモザイク - の取引を制限します。

前提条件

  • モザイク転送の制限 ガイドを完了している

  • ComfyClothingCompany と KYC プロバイダを表現するための アカウント を作成します。

  • 両方のアカウントに手数料の支払いとモザイクの作成に十分な symbol.xym を入金してください。

方法 #01: SDK を使用する

1. Start by creating a new restrictable mosaic with the ComfyClothingCompany account account. We will refer to this mosaic from now on as cc.shares.

symbol-cli transaction mosaic --amount 1000000 --transferable --supply-mutable --restrictable --divisibility 0 --non-expiring --profile cccompany --sync

The new mosaic id is: 7cdf3b117a3c40cc
  1. KYC プロバイダは kyc という新しい名前のモザイクを登録し、そのモザイクにグローバル制限 { kyc, IsVerified, EQ, 1} をモザイクに追加します。

const networkType = NetworkType.TEST_NET;
// replace with kyc provider private key
const kycProviderPrivateKey =
  'BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB';
const kycProviderAccount = Account.createFromPrivateKey(
  kycProviderPrivateKey,
  networkType,
);

// Define KYC Mosaic Id
const mosaicNonce = MosaicNonce.createRandom();
const mosaicDefinitionTransaction = MosaicDefinitionTransaction.create(
  Deadline.create(epochAdjustment),
  mosaicNonce,
  MosaicId.createFromNonce(
    mosaicNonce,
    kycProviderAccount.publicAccount.address,
  ),
  MosaicFlags.create(true, true, true),
  0,
  UInt64.fromUint(0),
  networkType,
);
console.log('KYC MosaicId:', mosaicDefinitionTransaction.mosaicId.toHex());

// Define Mosaic global restriction Is_Verified = 1
const key = KeyGenerator.generateUInt64Key('IsVerified'.toLowerCase());
const mosaicGlobalRestrictionTransaction = MosaicGlobalRestrictionTransaction.create(
  Deadline.create(epochAdjustment),
  mosaicDefinitionTransaction.mosaicId, // mosaicId
  key, // restictionKey
  UInt64.fromUint(0), // previousRestrictionValue
  MosaicRestrictionType.NONE, // previousRestrictionType
  UInt64.fromUint(1), // newRestrictionValue
  MosaicRestrictionType.EQ, // newRestrictionType
  networkType,
);

const aggregateTransaction = AggregateTransaction.createComplete(
  Deadline.create(epochAdjustment),
  [
    mosaicDefinitionTransaction.toAggregate(kycProviderAccount.publicAccount),
    mosaicGlobalRestrictionTransaction.toAggregate(
      kycProviderAccount.publicAccount,
    ),
  ],
  networkType,
  [],
  UInt64.fromUint(2000000),
);
// replace with meta.networkGenerationHash (nodeUrl + '/node/info')
const networkGenerationHash =
  '1DFB2FAA9E7F054168B0C5FCB84F4DEB62CC2B4D317D861F3168D161F54EA78B';
const signedTransaction = kycProviderAccount.sign(
  aggregateTransaction,
  networkGenerationHash,
);
console.log(signedTransaction.hash);
// replace with node endpoint
const nodeUrl = 'NODE_URL';
const repositoryFactory = new RepositoryFactoryHttp(nodeUrl);
const transactionHttp = repositoryFactory.createTransactionRepository();

transactionHttp.announce(signedTransaction).subscribe(
  (x) => console.log(x),
  (err) => console.error(err),
);
const networkType = symbol_sdk_1.NetworkType.TEST_NET;
// replace with kyc provider private key
const kycProviderPrivateKey =
  'BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB';
const kycProviderAccount = symbol_sdk_1.Account.createFromPrivateKey(
  kycProviderPrivateKey,
  networkType,
);
// Define KYC Mosaic Id
const mosaicNonce = symbol_sdk_1.MosaicNonce.createRandom();
const mosaicDefinitionTransaction = symbol_sdk_1.MosaicDefinitionTransaction.create(
  symbol_sdk_1.Deadline.create(epochAdjustment),
  mosaicNonce,
  symbol_sdk_1.MosaicId.createFromNonce(
    mosaicNonce,
    kycProviderAccount.publicAccount.address,
  ),
  symbol_sdk_1.MosaicFlags.create(true, true, true),
  0,
  symbol_sdk_1.UInt64.fromUint(0),
  networkType,
);
console.log('KYC MosaicId:', mosaicDefinitionTransaction.mosaicId.toHex());
// Define Mosaic global restriction Is_Verified = 1
const key = symbol_sdk_1.KeyGenerator.generateUInt64Key(
  'IsVerified'.toLowerCase(),
);
const mosaicGlobalRestrictionTransaction = symbol_sdk_1.MosaicGlobalRestrictionTransaction.create(
  symbol_sdk_1.Deadline.create(epochAdjustment),
  mosaicDefinitionTransaction.mosaicId, // mosaicId
  key, // restictionKey
  symbol_sdk_1.UInt64.fromUint(0), // previousRestrictionValue
  symbol_sdk_1.MosaicRestrictionType.NONE, // previousRestrictionType
  symbol_sdk_1.UInt64.fromUint(1), // newRestrictionValue
  symbol_sdk_1.MosaicRestrictionType.EQ, // newRestrictionType
  networkType,
);
const aggregateTransaction = symbol_sdk_1.AggregateTransaction.createComplete(
  symbol_sdk_1.Deadline.create(epochAdjustment),
  [
    mosaicDefinitionTransaction.toAggregate(kycProviderAccount.publicAccount),
    mosaicGlobalRestrictionTransaction.toAggregate(
      kycProviderAccount.publicAccount,
    ),
  ],
  networkType,
  [],
  symbol_sdk_1.UInt64.fromUint(2000000),
);
// replace with meta.networkGenerationHash (nodeUrl + '/node/info')
const networkGenerationHash =
  '1DFB2FAA9E7F054168B0C5FCB84F4DEB62CC2B4D317D861F3168D161F54EA78B';
const signedTransaction = kycProviderAccount.sign(
  aggregateTransaction,
  networkGenerationHash,
);
console.log(signedTransaction.hash);
// replace with node endpoint
const nodeUrl = 'NODE_URL';
const repositoryFactory = new symbol_sdk_1.RepositoryFactoryHttp(nodeUrl);
const transactionHttp = repositoryFactory.createTransactionRepository();
transactionHttp.announce(signedTransaction).subscribe(
  (x) => console.log(x),
  (err) => console.error(err),
);

KYC プロバイダは次の権限層を定義します。

キー

操作者

説明

IsVerified

EQ

1

クライアントが有効なパスポートを発行しました。

IsVerified

EQ

2

クライアントは有効な住所証明とパスポートを発行しました。

ComfyClothingCompany は制限 {cc.shares, kyc::IsVerified, EQ = 2} 付きのアカウントのみが株式を譲渡できるように決定します。このため、同社はモザイクのグローバル制限 {kyc::IsVerified, EQ, 2} をモザイクの ccf.shares に追加します。別のモザイクから制限を実装するにはフィールド referenceId を使用します。

  1. MosaicGlobalRestrictionTransaction をアナウンスして cc.sharestargetMosaicIdkycreferenceMosaicIdIsVerified をキーとして設定します。

// replace with cc.shares mosaic id
const sharesIdHex = '7cdf3b117a3c40cc';
const sharesId = new MosaicId(sharesIdHex);
// replace with kyc mosaic id
const kycIdHex = '183D0802BCDB97AF';
const kycId = new MosaicId(kycIdHex);
// replace with network type
const networkType = NetworkType.TEST_NET;

const key = KeyGenerator.generateUInt64Key('IsVerified'.toLowerCase());

const transaction = MosaicGlobalRestrictionTransaction.create(
  Deadline.create(epochAdjustment),
  sharesId, // mosaicId
  key, // restictionKey
  UInt64.fromUint(0), // previousRestrictionValue
  MosaicRestrictionType.NONE, // previousRestrictionType
  UInt64.fromUint(2), // newRestrictionValue
  MosaicRestrictionType.EQ, // newRestrictionType
  networkType,
  kycId, // referenceMosaicId
  UInt64.fromUint(2000000),
);

const comfyClothingCompanyPrivateKey =
  'FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF';
const comfyClothingCompanyAccount = Account.createFromPrivateKey(
  comfyClothingCompanyPrivateKey,
  networkType,
);
// replace with meta.networkGenerationHash (nodeUrl + '/node/info')
const networkGenerationHash =
  '1DFB2FAA9E7F054168B0C5FCB84F4DEB62CC2B4D317D861F3168D161F54EA78B';
const signedTransaction = comfyClothingCompanyAccount.sign(
  transaction,
  networkGenerationHash,
);
console.log(signedTransaction.hash);
// replace with node endpoint
const nodeUrl = 'NODE_URL';
const repositoryFactory = new RepositoryFactoryHttp(nodeUrl);
const transactionHttp = repositoryFactory.createTransactionRepository();

transactionHttp.announce(signedTransaction).subscribe(
  (x) => console.log(x),
  (err) => console.error(err),
);
// replace with cc.shares mosaic id
const sharesIdHex = '7cdf3b117a3c40cc';
const sharesId = new symbol_sdk_1.MosaicId(sharesIdHex);
// replace with kyc mosaic id
const kycIdHex = '183D0802BCDB97AF';
const kycId = new symbol_sdk_1.MosaicId(kycIdHex);
// replace with network type
const networkType = symbol_sdk_1.NetworkType.TEST_NET;
const key = symbol_sdk_1.KeyGenerator.generateUInt64Key(
  'IsVerified'.toLowerCase(),
);
const transaction = symbol_sdk_1.MosaicGlobalRestrictionTransaction.create(
  symbol_sdk_1.Deadline.create(epochAdjustment),
  sharesId, // mosaicId
  key, // restictionKey
  symbol_sdk_1.UInt64.fromUint(0), // previousRestrictionValue
  symbol_sdk_1.MosaicRestrictionType.NONE, // previousRestrictionType
  symbol_sdk_1.UInt64.fromUint(2), // newRestrictionValue
  symbol_sdk_1.MosaicRestrictionType.EQ, // newRestrictionType
  networkType,
  kycId, // referenceMosaicId
  symbol_sdk_1.UInt64.fromUint(2000000),
);
const comfyClothingCompanyPrivateKey =
  'FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF';
const comfyClothingCompanyAccount = symbol_sdk_1.Account.createFromPrivateKey(
  comfyClothingCompanyPrivateKey,
  networkType,
);
// replace with meta.networkGenerationHash (nodeUrl + '/node/info')
const networkGenerationHash =
  '1DFB2FAA9E7F054168B0C5FCB84F4DEB62CC2B4D317D861F3168D161F54EA78B';
const signedTransaction = comfyClothingCompanyAccount.sign(
  transaction,
  networkGenerationHash,
);
console.log(signedTransaction.hash);
// replace with node endpoint
const nodeUrl = 'NODE_URL';
const repositoryFactory = new symbol_sdk_1.RepositoryFactoryHttp(nodeUrl);
const transactionHttp = repositoryFactory.createTransactionRepository();
transactionHttp.announce(signedTransaction).subscribe(
  (x) => console.log(x),
  (err) => console.error(err),
);
  1. KYC プロバイダーは 3 人の潜在的投資家と出会いました。

  • Alice は有効なパスポートを提供しますがアドレスの証明は提供しません。KYC プロバイダは Alice のアカウントにモザイク制限の {kyc, IsVerified, 1} を授与します。

  • Bob は有効なパスポートと住所証明を提供します。KYC プロバイダは Bob のアカウントにモザイク制限の {kyc, IsVerified, 2} を授与します。

  • Carol は有効なパスポートと住所証明を提供します。KYC プロバイダは Carol のアカウントにモザイク制限の {kyc, IsVerified, 2} を授与します。

KYC プロバイダーはモザイクアドレス制限を送信するアカウントに応じたタグを付ける必要があります。

// replace with kyc mosaic id
const mosaicIdHex = '183D0802BCDB97AF';
const mosaicId = new MosaicId(mosaicIdHex);
// replace with alice address
const aliceRawAddress = 'TCHBDE-NCLKEB-ILBPWP-3JPB2X-NY64OE-7PYHHE-32I';
const aliceAddress = Address.createFromRawAddress(aliceRawAddress);
// replace with bob address
const bobRawAddress = 'TB6Q5E-YACWBP-CXKGIL-I6XWCH-DRFLTB-KUK34I-YJQ';
const bobAddress = Address.createFromRawAddress(bobRawAddress);
// replace with carol address
const carolRawAddress = 'TCF7MK-FL6QYF-UHWVRZ-6UUCLN-YBDWLQ-ZZC37A-2O6R';
const carolAddress = Address.createFromRawAddress(carolRawAddress);
// replace with network type
const networkType = NetworkType.TEST_NET;

const key = KeyGenerator.generateUInt64Key('IsVerified'.toLowerCase());

const aliceMosaicAddressRestrictionTransaction = MosaicAddressRestrictionTransaction.create(
  Deadline.create(epochAdjustment),
  mosaicId, // mosaicId
  key, // restrictionKey
  aliceAddress, // address
  UInt64.fromUint(1), // newRestrictionValue
  networkType,
);

const bobMosaicAddressRestrictionTransaction = MosaicAddressRestrictionTransaction.create(
  Deadline.create(epochAdjustment),
  mosaicId, // mosaicId
  key, // restrictionKey
  bobAddress, // address
  UInt64.fromUint(2), // newRestrictionValue
  networkType,
);

const carolMosaicAddressRestrictionTransaction = MosaicAddressRestrictionTransaction.create(
  Deadline.create(epochAdjustment),
  mosaicId, // mosaicId
  key, // restrictionKey
  carolAddress, // address
  UInt64.fromUint(2), // newRestrictionValue
  networkType,
);

// replace with kyc provider private key
const kycProviderPrivateKey =
  'BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB';
const kycProviderAccount = Account.createFromPrivateKey(
  kycProviderPrivateKey,
  networkType,
);

const aggregateTransaction = AggregateTransaction.createComplete(
  Deadline.create(epochAdjustment),
  [
    aliceMosaicAddressRestrictionTransaction.toAggregate(
      kycProviderAccount.publicAccount,
    ),
    bobMosaicAddressRestrictionTransaction.toAggregate(
      kycProviderAccount.publicAccount,
    ),
    carolMosaicAddressRestrictionTransaction.toAggregate(
      kycProviderAccount.publicAccount,
    ),
  ],
  networkType,
  [],
  UInt64.fromUint(2000000),
);

// replace with meta.networkGenerationHash (nodeUrl + '/node/info')
const networkGenerationHash =
  '1DFB2FAA9E7F054168B0C5FCB84F4DEB62CC2B4D317D861F3168D161F54EA78B';
const signedTransaction = kycProviderAccount.sign(
  aggregateTransaction,
  networkGenerationHash,
);
console.log(signedTransaction.hash);
// replace with node endpoint
const nodeUrl = 'NODE_URL';
const repositoryFactory = new RepositoryFactoryHttp(nodeUrl);
const transactionHttp = repositoryFactory.createTransactionRepository();

transactionHttp.announce(signedTransaction).subscribe(
  (x) => console.log(x),
  (err) => console.error(err),
);
// replace with kyc mosaic id
const mosaicIdHex = '183D0802BCDB97AF';
const mosaicId = new symbol_sdk_1.MosaicId(mosaicIdHex);
// replace with alice address
const aliceRawAddress = 'TCHBDE-NCLKEB-ILBPWP-3JPB2X-NY64OE-7PYHHE-32I';
const aliceAddress = symbol_sdk_1.Address.createFromRawAddress(aliceRawAddress);
// replace with bob address
const bobRawAddress = 'TB6Q5E-YACWBP-CXKGIL-I6XWCH-DRFLTB-KUK34I-YJQ';
const bobAddress = symbol_sdk_1.Address.createFromRawAddress(bobRawAddress);
// replace with carol address
const carolRawAddress = 'TCF7MK-FL6QYF-UHWVRZ-6UUCLN-YBDWLQ-ZZC37A-2O6R';
const carolAddress = symbol_sdk_1.Address.createFromRawAddress(carolRawAddress);
// replace with network type
const networkType = symbol_sdk_1.NetworkType.TEST_NET;
const key = symbol_sdk_1.KeyGenerator.generateUInt64Key(
  'IsVerified'.toLowerCase(),
);
const aliceMosaicAddressRestrictionTransaction = symbol_sdk_1.MosaicAddressRestrictionTransaction.create(
  symbol_sdk_1.Deadline.create(epochAdjustment),
  mosaicId, // mosaicId
  key, // restrictionKey
  aliceAddress, // address
  symbol_sdk_1.UInt64.fromUint(1), // newRestrictionValue
  networkType,
);
const bobMosaicAddressRestrictionTransaction = symbol_sdk_1.MosaicAddressRestrictionTransaction.create(
  symbol_sdk_1.Deadline.create(epochAdjustment),
  mosaicId, // mosaicId
  key, // restrictionKey
  bobAddress, // address
  symbol_sdk_1.UInt64.fromUint(2), // newRestrictionValue
  networkType,
);
const carolMosaicAddressRestrictionTransaction = symbol_sdk_1.MosaicAddressRestrictionTransaction.create(
  symbol_sdk_1.Deadline.create(epochAdjustment),
  mosaicId, // mosaicId
  key, // restrictionKey
  carolAddress, // address
  symbol_sdk_1.UInt64.fromUint(2), // newRestrictionValue
  networkType,
);
// replace with kyc provider private key
const kycProviderPrivateKey =
  'BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB';
const kycProviderAccount = symbol_sdk_1.Account.createFromPrivateKey(
  kycProviderPrivateKey,
  networkType,
);
const aggregateTransaction = symbol_sdk_1.AggregateTransaction.createComplete(
  symbol_sdk_1.Deadline.create(epochAdjustment),
  [
    aliceMosaicAddressRestrictionTransaction.toAggregate(
      kycProviderAccount.publicAccount,
    ),
    bobMosaicAddressRestrictionTransaction.toAggregate(
      kycProviderAccount.publicAccount,
    ),
    carolMosaicAddressRestrictionTransaction.toAggregate(
      kycProviderAccount.publicAccount,
    ),
  ],
  networkType,
  [],
  symbol_sdk_1.UInt64.fromUint(2000000),
);
// replace with meta.networkGenerationHash (nodeUrl + '/node/info')
const networkGenerationHash =
  '1DFB2FAA9E7F054168B0C5FCB84F4DEB62CC2B4D317D861F3168D161F54EA78B';
const signedTransaction = kycProviderAccount.sign(
  aggregateTransaction,
  networkGenerationHash,
);
console.log(signedTransaction.hash);
// replace with node endpoint
const nodeUrl = 'NODE_URL';
const repositoryFactory = new symbol_sdk_1.RepositoryFactoryHttp(nodeUrl);
const transactionHttp = repositoryFactory.createTransactionRepository();
transactionHttp.announce(signedTransaction).subscribe(
  (x) => console.log(x),
  (err) => console.error(err),
);

5. After the restrictions get confirmed, Bob and Carol will be able to buy and send the cc.shares units to each other. But Alice⁠—who has not provided valid proof of address⁠—will not be able to receive shares.