diff --git a/abi/omen_thumbnailmapping.abi.json b/abi/omen_thumbnailmapping.abi.json new file mode 100644 index 0000000..9524caf --- /dev/null +++ b/abi/omen_thumbnailmapping.abi.json @@ -0,0 +1,64 @@ +[ + { + "type": "function", + "name": "get", + "inputs": [ + { "name": "marketAddress", "type": "address", "internalType": "address" } + ], + "outputs": [{ "name": "", "type": "bytes32", "internalType": "bytes32" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getLatestImageChanger", + "inputs": [ + { "name": "marketAddress", "type": "address", "internalType": "address" } + ], + "outputs": [{ "name": "", "type": "address", "internalType": "address" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "remove", + "inputs": [ + { "name": "marketAddress", "type": "address", "internalType": "address" } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "set", + "inputs": [ + { "name": "marketAddress", "type": "address", "internalType": "address" }, + { "name": "image_hash", "type": "bytes32", "internalType": "bytes32" } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "event", + "name": "ImageUpdated", + "inputs": [ + { + "name": "marketAddress", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "image_hash", + "type": "bytes32", + "indexed": false, + "internalType": "bytes32" + }, + { + "name": "changer", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + } +] diff --git a/lib/openzeppelin-contracts b/lib/openzeppelin-contracts index 442886e..483fc3f 160000 --- a/lib/openzeppelin-contracts +++ b/lib/openzeppelin-contracts @@ -1 +1 @@ -Subproject commit 442886ed5ff8a0b9ab477b191f5238541ee6d772 +Subproject commit 483fc3f1f89ef6eb0803d578a4a17346d94359f7 diff --git a/src/OmenThumbnailMapping.sol b/src/OmenThumbnailMapping.sol index e38a391..6c6cd34 100644 --- a/src/OmenThumbnailMapping.sol +++ b/src/OmenThumbnailMapping.sol @@ -5,24 +5,31 @@ import {IERC20} from "../lib/openzeppelin-contracts/contracts/interfaces/IERC20. /// @dev Mapping from market's address to image's IPFS hash contract OmenThumbnailMapping { + event ImageUpdated(address indexed marketAddress, bytes32 image_hash, address indexed changer); + mapping(address => bytes32) private marketAddressToIPFSHash; mapping(address => address) private marketAddressToLatestImageChanger; /// @dev Get IPFS hash of thumbnail for the given market. - function get(address marketAddress) external view returns (bytes32) { + function get(address marketAddress) public view returns (bytes32) { return marketAddressToIPFSHash[marketAddress]; } /// @dev Update IPFS hash of thumbnail for the given market. - function set(address marketAddress, bytes32 image_hash) external requireThatSenderCanChangeImage(marketAddress) { + function set(address marketAddress, bytes32 image_hash) public requireThatSenderCanChangeImage(marketAddress) { marketAddressToIPFSHash[marketAddress] = image_hash; marketAddressToLatestImageChanger[marketAddress] = msg.sender; + emit ImageUpdated(marketAddress, image_hash, msg.sender); } /// @dev Remove IPFS hash of thumbnail for the given market. - function remove(address marketAddress) external requireThatSenderCanChangeImage(marketAddress) { - delete marketAddressToIPFSHash[marketAddress]; - marketAddressToLatestImageChanger[marketAddress] = msg.sender; + function remove(address marketAddress) public requireThatSenderCanChangeImage(marketAddress) { + set(marketAddress, bytes32(0)); + } + + /// @dev Get the address of the latest person who updated the image for the given market. + function getLatestImageChanger(address marketAddress) public view returns (address) { + return marketAddressToLatestImageChanger[marketAddress]; } /// @dev Verify that sender is allowed to update IPFS hash for the given market. diff --git a/test/OmenThumbnailMapping.t.sol b/test/OmenThumbnailMapping.t.sol index d92a15b..a929f5b 100644 --- a/test/OmenThumbnailMapping.t.sol +++ b/test/OmenThumbnailMapping.t.sol @@ -21,6 +21,8 @@ contract OmenThumbnailMappingTest is Test { function testCanUpdateImageWithAnyFundsInMarketIfThisIsFirstUpdater() public { productMarketMaker.mint(address(this), 1); + vm.expectEmit(true, true, true, true); + emit OmenThumbnailMapping.ImageUpdated(address(productMarketMaker), "Qm123", address(this)); omenThumbnailMapping.set(address(productMarketMaker), "Qm123"); assertEq(omenThumbnailMapping.get(address(productMarketMaker)), "Qm123"); } @@ -56,4 +58,27 @@ contract OmenThumbnailMappingTest is Test { omenThumbnailMapping.set(address(productMarketMaker), "Qm456"); assertEq(omenThumbnailMapping.get(address(productMarketMaker)), "Qm456"); } + + function testNonSetImageIsEqualToNullBytes32() public { + assertEq(omenThumbnailMapping.get(address(productMarketMaker)), bytes32(0)); + } + + function testImageIsNullBytesAfterRemovalAndChangerIsUpdatedCorrectly() public { + productMarketMaker.mint(address(this), 1); + vm.expectEmit(true, true, true, true); + emit OmenThumbnailMapping.ImageUpdated(address(productMarketMaker), "Qm123", address(this)); + omenThumbnailMapping.set(address(productMarketMaker), "Qm123"); + assertEq(omenThumbnailMapping.get(address(productMarketMaker)), "Qm123"); + assertEq(omenThumbnailMapping.getLatestImageChanger(address(productMarketMaker)), address(this)); + + address anotherUser = address(0x123); + productMarketMaker.mint(anotherUser, 2); + vm.expectEmit(true, true, true, true); + emit OmenThumbnailMapping.ImageUpdated(address(productMarketMaker), bytes32(0), anotherUser); + vm.prank(anotherUser); + + omenThumbnailMapping.remove(address(productMarketMaker)); + assertEq(omenThumbnailMapping.get(address(productMarketMaker)), bytes32(0)); + assertEq(omenThumbnailMapping.getLatestImageChanger(address(productMarketMaker)), anotherUser); + } }