From 5850bcec451ab6491b488a379a9ae14d7963de12 Mon Sep 17 00:00:00 2001 From: Max Date: Thu, 6 Aug 2026 00:12:08 +0400 Subject: [PATCH 1/2] fix: expose MTS bank hook suppression Keep seize as a direct BANK.transfer after validateSeize. Expose the transient suppression state so Injective Core can read in-flight contract storage before entering the matching permissions hooks. The getter does not alter transfer semantics or storage layout; ordinary EVM and Cosmos transfers continue through compliance. --- contracts/token/DSTokenMTS.sol | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/contracts/token/DSTokenMTS.sol b/contracts/token/DSTokenMTS.sol index d6482c8..dc19646 100644 --- a/contracts/token/DSTokenMTS.sol +++ b/contracts/token/DSTokenMTS.sol @@ -172,6 +172,10 @@ contract DSTokenMTS is DSToken { return code != 0; } + function isBankTransferHookSuppressed() external view returns (bool) { + return suppressPostTransferRecord; + } + function postTransfer( address _from, address _to, From 1efa06a5aa0022014ef40ef40090adb1b29c2224 Mon Sep 17 00:00:00 2001 From: Max Date: Thu, 6 Aug 2026 00:12:27 +0400 Subject: [PATCH 2/2] test: cover direct-transfer MTS seize flow Extend the real-node Hardhat acceptance test with a restricted issuer wallet. Confirm ordinary EVM and Cosmos transfers remain rejected, then verify partial and full seize operations preserve supply, balances, wallet tracking, and investor counters. --- test/dstoken-injective-mts.test.ts | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/test/dstoken-injective-mts.test.ts b/test/dstoken-injective-mts.test.ts index 70e5cf1..b88910d 100644 --- a/test/dstoken-injective-mts.test.ts +++ b/test/dstoken-injective-mts.test.ts @@ -191,7 +191,7 @@ describeInjective('DS Token Injective MTS integration', function() { it('uses the Bank precompile and permissions hooks for regulated transfers', async function() { assertInjectivedKeys(); - const [owner, holder, blocked] = await hre.ethers.getSigners(); + const [owner, holder, blocked, issuerWallet] = await hre.ethers.getSigners(); const contracts = await hre.run('deploy-all', { name: 'Token Example 1', @@ -204,6 +204,7 @@ describeInjective('DS Token Injective MTS integration', function() { const registryService = contracts.registryService; const complianceService = contracts.complianceService; const complianceConfigurationService = contracts.complianceConfigurationService; + const walletManager = contracts.walletManager; const tokenAddress = await dsToken.getAddress(); const denom = `erc20:${tokenAddress}`; @@ -256,5 +257,30 @@ describeInjective('DS Token Injective MTS integration', function() { expect(await dsToken.balanceOf(holder.address)).to.equal(375); expect(await dsToken.balanceOf(blocked.address)).to.equal(0); + + await (await walletManager.addIssuerWallet(issuerWallet.address)).wait(); + + await expect(dsToken.connect(holder).transfer(issuerWallet.address, 1)).to.be.reverted; + expect(() => bankSend('user1', injAddressFromEth(issuerWallet.address), denom, 1n)).to.throw(/transfer is restricted by EVM hook/i); + + await (await dsToken.seize(holder.address, issuerWallet.address, 100, 'test partial seize')).wait(); + + expect(await dsToken.totalSupply()).to.equal(500); + expect(await dsToken.balanceOf(holder.address)).to.equal(275); + expect(await dsToken.balanceOf(issuerWallet.address)).to.equal(100); + expect(await dsToken.balanceOfInvestor(INVESTORS.INVESTOR_ID.INVESTOR_ID_1)).to.equal(275); + expect(await dsToken.walletCount()).to.equal(3); + expect(await complianceService.getTotalInvestorsCount()).to.equal(2); + + await (await dsToken.seize(holder.address, issuerWallet.address, 275, 'test full seize')).wait(); + + expect(await dsToken.totalSupply()).to.equal(500); + expect(await dsToken.balanceOf(holder.address)).to.equal(0); + expect(await dsToken.balanceOf(owner.address)).to.equal(125); + expect(await dsToken.balanceOf(issuerWallet.address)).to.equal(375); + expect(await dsToken.balanceOfInvestor(INVESTORS.INVESTOR_ID.INVESTOR_ID_1)).to.equal(0); + expect(await dsToken.balanceOfInvestor(INVESTORS.INVESTOR_ID.INVESTOR_ID_2)).to.equal(125); + expect(await dsToken.walletCount()).to.equal(2); + expect(await complianceService.getTotalInvestorsCount()).to.equal(1); }); });