跨合约调用时T1合约Mapping数组大小未更新问题求助
问题核心原因
你遇到的问题是**msg.sender的上下文混淆**:当通过t2合约调用t1的addNewVal时,t1里的msg.sender是t2合约的地址,而不是触发t2.callandAdd的用户地址。所以你添加的_tokenId实际上存在了t2合约地址对应的数组条目里,用自己的地址调用findSize自然看不到长度变化。
解决方案
推荐两种直接的修正方式,优先选第一种:
方案一:传递用户地址参数(安全直观)
修改t1的addNewVal函数,让它接收一个用户地址参数,明确指定要往哪个地址的数组里添加元素;同时t2调用时把当前用户的地址传过去。
修改后的t1合约:
// SPDX-License-Identifier: MIT pragma solidity >=0.4.22 <0.9.0; contract t1{ mapping(address => uint256[]) AllSpecialNFT; // 新增address参数,指定要操作的用户地址 function addNewVal(address user, uint _tokenId) public { AllSpecialNFT[user].push(_tokenId); } function findSize() public view returns(uint){ return AllSpecialNFT[msg.sender].length; } }
修改后的t2合约:
// SPDX-License-Identifier: MIT pragma solidity >=0.4.22 <0.9.0; import './t1.sol'; contract t2 { t1 _t1; constructor(t1 t1_){ _t1 = t1_; } // 调用t1.addNewVal时,传入当前用户的msg.sender function callandAdd(uint _tokenId) public{ _t1.addNewVal(msg.sender, _tokenId); } }
操作后,调用t2.callandAdd时,_tokenId会被添加到你自己地址对应的数组里,再调用t1.findSize就能看到数组长度正确增加。
方案二:使用tx.origin(不推荐,有安全风险)
可以在t1的addNewVal里用tx.origin替代msg.sender,tx.origin指整个交易的发起者地址。但这种方式存在钓鱼攻击风险,仅作了解:
function addNewVal(uint _tokenId) public { AllSpecialNFT[tx.origin].push(_tokenId); }
验证补充
可以给t1加一个查询指定地址数组长度的函数,方便验证:
function findSizeOfAddress(address user) public view returns(uint){ return AllSpecialNFT[user].length; }
传入t2合约地址就能看到之前错误添加的元素数量,传入自己的地址则能看到修正后的正确长度。
内容的提问来源于stack exchange,提问作者VIASK
相关产品推荐
相关产品推荐

