git.delta.rocks / unique-network / refs/commits / abe0498b88a3

difftreelog

test other chains can spend only up to balance

Daniel Shiposha2023-04-12parent: #c319502.patch.diff
in: master

4 files changed

modifiedtests/src/util/playgrounds/unique.dev.tsdiffbeforeafterboth
--- a/tests/src/util/playgrounds/unique.dev.ts
+++ b/tests/src/util/playgrounds/unique.dev.ts
@@ -420,6 +420,63 @@
 
     return capture;
   }
+
+  makeXcmProgramWithdrawDeposit(beneficiary: Uint8Array, amount: bigint | string) {
+    return {
+      V2: [
+        {
+          WithdrawAsset: [
+            {
+              id: {
+                Concrete: {
+                  parents: 0,
+                  interior: 'Here',
+                },
+              },
+              fun: {
+                Fungible: amount,
+              },
+            },
+          ],
+        },
+        {
+          BuyExecution: {
+            fees: {
+              id: {
+                Concrete: {
+                  parents: 0,
+                  interior: 'Here',
+                },
+              },
+              fun: {
+                Fungible: amount,
+              },
+            },
+            weightLimit: 'Unlimited'
+          },
+        },
+        {
+          DepositAsset: {
+            assets: {
+              Wild: 'All'
+            },
+            maxAssets: 1,
+            beneficiary: {
+              parents: 0,
+              interior: {
+                X1: {
+                  AccountId32: {
+                    network: 'Any',
+                    id: beneficiary
+                  },
+                },
+              },
+            },
+          }
+        },
+      ],
+    };
+  }
 }
 
 class MoonbeamAccountGroup {
modifiedtests/src/util/playgrounds/unique.tsdiffbeforeafterboth
--- a/tests/src/util/playgrounds/unique.ts
+++ b/tests/src/util/playgrounds/unique.ts
@@ -2446,6 +2446,10 @@
     return this.ethBalanceGroup.getEthereum(address);
   }
 
+  async setBalanceSubstrate(signer: TSigner, address: TSubstrateAccount, amount: bigint | string, reservedAmount: bigint | string = 0n) {
+    await this.helper.executeExtrinsic(signer, 'api.tx.balances.setBalance', [address, amount, reservedAmount], true);
+  }
+
   /**
    * Transfer tokens to substrate address
    * @param signer keyring of signer
modifiedtests/src/xcm/xcmQuartz.test.tsdiffbeforeafterboth
--- a/tests/src/xcm/xcmQuartz.test.ts
+++ b/tests/src/xcm/xcmQuartz.test.ts
@@ -642,6 +642,84 @@
     console.log('[Karura -> Quartz] transaction fees on Quartz: %s QTZ', helper.util.bigIntToDecimals(qtzFees));
     expect(qtzFees == 0n).to.be.true;
   });
+
+  itSub('Karura can send only up to its balance', async ({helper}) => {
+    // set Karura's sovereign account's balance
+    const karuraBalance = 10000n * (10n ** QTZ_DECIMALS);
+    const karuraSovereignAccount = helper.address.paraSiblingSovereignAccount(KARURA_CHAIN);
+    await helper.getSudo().balance.setBalanceSubstrate(alice, karuraSovereignAccount, karuraBalance);
+
+    const moreThanKaruraHas = karuraBalance * 2n;
+
+    let targetAccountBalance = 0n;
+    const [targetAccount] = await helper.arrange.createAccounts([targetAccountBalance], alice);
+
+    const quartzMultilocation = {
+      V1: {
+        parents: 1,
+        interior: {
+          X1: {Parachain: QUARTZ_CHAIN},
+        },
+      },
+    };
+
+    const maliciousXcmProgram = helper.arrange.makeXcmProgramWithdrawDeposit(targetAccount.addressRaw, moreThanKaruraHas);
+
+    // Try to trick Quartz
+    await usingKaruraPlaygrounds(karuraUrl, async (helper) => {
+      await helper.getSudo().executeExtrinsic(
+        alice,
+        'api.tx.polkadotXcm.send',
+        [
+          quartzMultilocation,
+          maliciousXcmProgram,
+        ],
+        true,
+      );
+    });
+
+    const maxWaitBlocks = 3;
+
+    const xcmpQueueFailEvent = await helper.wait.eventOutcome<XcmV2TraitsError>(
+      maxWaitBlocks,
+      'xcmpQueue',
+      'Fail',
+    );
+
+    expect(
+      xcmpQueueFailEvent != null,
+      `'xcmpQueue.FailEvent' event is expected`,
+    ).to.be.true;
+
+    expect(
+      xcmpQueueFailEvent!.isFailedToTransactAsset,
+      `The XCM error should be 'FailedToTransactAsset'`,
+    ).to.be.true;
+
+    targetAccountBalance = await helper.balance.getSubstrate(targetAccount.address);
+    expect(targetAccountBalance).to.be.equal(0n);
+
+    // But Karura still can send the correct amount
+    const validTransferAmount = karuraBalance / 2n;
+    const validXcmProgram = helper.arrange.makeXcmProgramWithdrawDeposit(targetAccount.addressRaw, validTransferAmount);
+
+    await usingKaruraPlaygrounds(karuraUrl, async (helper) => {
+      await helper.getSudo().executeExtrinsic(
+        alice,
+        'api.tx.polkadotXcm.send',
+        [
+          quartzMultilocation,
+          validXcmProgram,
+        ],
+        true,
+      );
+    });
+
+    await helper.wait.newBlocks(maxWaitBlocks);
+
+    targetAccountBalance = await helper.balance.getSubstrate(targetAccount.address);
+    expect(targetAccountBalance).to.be.equal(validTransferAmount);
+  });
 });
 
 // These tests are relevant only when
@@ -1060,6 +1138,10 @@
     console.log('[Moonriver -> Quartz] transaction fees on Quartz: %s QTZ', helper.util.bigIntToDecimals(qtzFees));
     expect(qtzFees == 0n).to.be.true;
   });
+
+  itSub.skip('Moonriver can send only up to its balance', async ({helper}) => {
+    throw Error("Not yet implemented");
+  });
 });
 
 describeXCM('[XCM] Integration test: Exchanging tokens with Shiden', () => {
@@ -1272,4 +1354,82 @@
     console.log(`QTZ Balance on Quartz after XCM is: ${balanceQTZ}`);
     expect(balanceQTZ).to.eq(balanceAfterQuartzToShidenXCM + qtzFromShidenTransfered);
   });
+
+  itSub('Shiden can send only up to its balance', async ({helper}) => {
+    // set Shiden's sovereign account's balance
+    const shidenBalance = 10000n * (10n ** QTZ_DECIMALS);
+    const shidenSovereignAccount = helper.address.paraSiblingSovereignAccount(SHIDEN_CHAIN);
+    await helper.getSudo().balance.setBalanceSubstrate(alice, shidenSovereignAccount, shidenBalance);
+
+    const moreThanShidenHas = shidenBalance * 2n;
+
+    let targetAccountBalance = 0n;
+    const [targetAccount] = await helper.arrange.createAccounts([targetAccountBalance], alice);
+
+    const quartzMultilocation = {
+      V1: {
+        parents: 1,
+        interior: {
+          X1: {Parachain: QUARTZ_CHAIN},
+        },
+      },
+    };
+
+    const maliciousXcmProgram = helper.arrange.makeXcmProgramWithdrawDeposit(targetAccount.addressRaw, moreThanShidenHas);
+
+    // Try to trick Quartz
+    await usingShidenPlaygrounds(shidenUrl, async (helper) => {
+      await helper.getSudo().executeExtrinsic(
+        alice,
+        'api.tx.polkadotXcm.send',
+        [
+          quartzMultilocation,
+          maliciousXcmProgram,
+        ],
+        true,
+      );
+    });
+
+    const maxWaitBlocks = 3;
+
+    const xcmpQueueFailEvent = await helper.wait.eventOutcome<XcmV2TraitsError>(
+      maxWaitBlocks,
+      'xcmpQueue',
+      'Fail',
+    );
+
+    expect(
+      xcmpQueueFailEvent != null,
+      `'xcmpQueue.FailEvent' event is expected`,
+    ).to.be.true;
+
+    expect(
+      xcmpQueueFailEvent!.isFailedToTransactAsset,
+      `The XCM error should be 'FailedToTransactAsset'`,
+    ).to.be.true;
+
+    targetAccountBalance = await helper.balance.getSubstrate(targetAccount.address);
+    expect(targetAccountBalance).to.be.equal(0n);
+
+    // But Shiden still can send the correct amount
+    const validTransferAmount = shidenBalance / 2n;
+    const validXcmProgram = helper.arrange.makeXcmProgramWithdrawDeposit(targetAccount.addressRaw, validTransferAmount);
+
+    await usingShidenPlaygrounds(shidenUrl, async (helper) => {
+      await helper.getSudo().executeExtrinsic(
+        alice,
+        'api.tx.polkadotXcm.send',
+        [
+          quartzMultilocation,
+          validXcmProgram,
+        ],
+        true,
+      );
+    });
+
+    await helper.wait.newBlocks(maxWaitBlocks);
+
+    targetAccountBalance = await helper.balance.getSubstrate(targetAccount.address);
+    expect(targetAccountBalance).to.be.equal(validTransferAmount);
+  });
 });
modifiedtests/src/xcm/xcmUnique.test.tsdiffbeforeafterboth
645 expect(unqFees == 0n).to.be.true;645 expect(unqFees == 0n).to.be.true;
646 });646 });
647
648 itSub('Acala can send only up to its balance', async ({helper}) => {
649 // set Acala's sovereign account's balance
650 const acalaBalance = 10000n * (10n ** UNQ_DECIMALS);
651 const acalaSovereignAccount = helper.address.paraSiblingSovereignAccount(ACALA_CHAIN);
652 await helper.getSudo().balance.setBalanceSubstrate(alice, acalaSovereignAccount, acalaBalance);
653
654 const moreThanAcalaHas = acalaBalance * 2n;
655
656 let targetAccountBalance = 0n;
657 const [targetAccount] = await helper.arrange.createAccounts([targetAccountBalance], alice);
658
659 const uniqueMultilocation = {
660 V1: {
661 parents: 1,
662 interior: {
663 X1: {Parachain: UNIQUE_CHAIN},
664 },
665 },
666 };
667
668 const maliciousXcmProgram = helper.arrange.makeXcmProgramWithdrawDeposit(targetAccount.addressRaw, moreThanAcalaHas);
669
670 // Try to trick Unique
671 await usingAcalaPlaygrounds(acalaUrl, async (helper) => {
672 await helper.getSudo().executeExtrinsic(
673 alice,
674 'api.tx.polkadotXcm.send',
675 [
676 uniqueMultilocation,
677 maliciousXcmProgram,
678 ],
679 true,
680 );
681 });
682
683 const maxWaitBlocks = 3;
684
685 const xcmpQueueFailEvent = await helper.wait.eventOutcome<XcmV2TraitsError>(
686 maxWaitBlocks,
687 'xcmpQueue',
688 'Fail',
689 );
690
691 expect(
692 xcmpQueueFailEvent != null,
693 `'xcmpQueue.FailEvent' event is expected`,
694 ).to.be.true;
695
696 expect(
697 xcmpQueueFailEvent!.isFailedToTransactAsset,
698 `The XCM error should be 'FailedToTransactAsset'`,
699 ).to.be.true;
700
701 targetAccountBalance = await helper.balance.getSubstrate(targetAccount.address);
702 expect(targetAccountBalance).to.be.equal(0n);
703
704 // But Acala still can send the correct amount
705 const validTransferAmount = acalaBalance / 2n;
706 const validXcmProgram = helper.arrange.makeXcmProgramWithdrawDeposit(targetAccount.addressRaw, validTransferAmount);
707
708 await usingAcalaPlaygrounds(acalaUrl, async (helper) => {
709 await helper.getSudo().executeExtrinsic(
710 alice,
711 'api.tx.polkadotXcm.send',
712 [
713 uniqueMultilocation,
714 validXcmProgram,
715 ],
716 true,
717 );
718 });
719
720 await helper.wait.newBlocks(maxWaitBlocks);
721
722 targetAccountBalance = await helper.balance.getSubstrate(targetAccount.address);
723 expect(targetAccountBalance).to.be.equal(validTransferAmount);
724 });
647});725});
648726
649// These tests are relevant only when727// These tests are relevant only when
1064 expect(unqFees == 0n).to.be.true;1142 expect(unqFees == 0n).to.be.true;
1065 });1143 });
1144
1145 itSub.skip('Moonbeam can send only up to its balance', async ({helper}) => {
1146 throw Error("Not yet implemented");
1147 });
1066});1148});
10671149
1068describeXCM('[XCM] Integration test: Exchanging tokens with Astar', () => {1150describeXCM('[XCM] Integration test: Exchanging tokens with Astar', () => {
1331 });1413 });
1332 });1414 });
1415
1416 itSub('Astar can send only up to its balance', async ({helper}) => {
1417 // set Astar's sovereign account's balance
1418 const astarBalance = 10000n * (10n ** UNQ_DECIMALS);
1419 const astarSovereignAccount = helper.address.paraSiblingSovereignAccount(ASTAR_CHAIN);
1420 await helper.getSudo().balance.setBalanceSubstrate(alice, astarSovereignAccount, astarBalance);
1421
1422 const moreThanShidenHas = astarBalance * 2n;
1423
1424 let targetAccountBalance = 0n;
1425 const [targetAccount] = await helper.arrange.createAccounts([targetAccountBalance], alice);
1426
1427 const uniqueMultilocation = {
1428 V1: {
1429 parents: 1,
1430 interior: {
1431 X1: {Parachain: UNIQUE_CHAIN},
1432 },
1433 },
1434 };
1435
1436 const maliciousXcmProgram = helper.arrange.makeXcmProgramWithdrawDeposit(targetAccount.addressRaw, moreThanShidenHas);
1437
1438 // Try to trick Unique
1439 await usingAstarPlaygrounds(astarUrl, async (helper) => {
1440 await helper.getSudo().executeExtrinsic(
1441 alice,
1442 'api.tx.polkadotXcm.send',
1443 [
1444 uniqueMultilocation,
1445 maliciousXcmProgram,
1446 ],
1447 true,
1448 );
1449 });
1450
1451 const maxWaitBlocks = 3;
1452
1453 const xcmpQueueFailEvent = await helper.wait.eventOutcome<XcmV2TraitsError>(
1454 maxWaitBlocks,
1455 'xcmpQueue',
1456 'Fail',
1457 );
1458
1459 expect(
1460 xcmpQueueFailEvent != null,
1461 `'xcmpQueue.FailEvent' event is expected`,
1462 ).to.be.true;
1463
1464 expect(
1465 xcmpQueueFailEvent!.isFailedToTransactAsset,
1466 `The XCM error should be 'FailedToTransactAsset'`,
1467 ).to.be.true;
1468
1469 targetAccountBalance = await helper.balance.getSubstrate(targetAccount.address);
1470 expect(targetAccountBalance).to.be.equal(0n);
1471
1472 // But Astar still can send the correct amount
1473 const validTransferAmount = astarBalance / 2n;
1474 const validXcmProgram = helper.arrange.makeXcmProgramWithdrawDeposit(targetAccount.addressRaw, validTransferAmount);
1475
1476 await usingAstarPlaygrounds(astarUrl, async (helper) => {
1477 await helper.getSudo().executeExtrinsic(
1478 alice,
1479 'api.tx.polkadotXcm.send',
1480 [
1481 uniqueMultilocation,
1482 validXcmProgram,
1483 ],
1484 true,
1485 );
1486 });
1487
1488 await helper.wait.newBlocks(maxWaitBlocks);
1489
1490 targetAccountBalance = await helper.balance.getSubstrate(targetAccount.address);
1491 expect(targetAccountBalance).to.be.equal(validTransferAmount);
1492 });
1333});1493});
13341494