Clones.t.sol 3.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. // SPDX-License-Identifier: MIT
  2. pragma solidity ^0.8.20;
  3. import {Test} from "forge-std/Test.sol";
  4. import {Clones} from "@openzeppelin/contracts/proxy/Clones.sol";
  5. contract ClonesTest is Test {
  6. function getNumber() external pure returns (uint256) {
  7. return 42;
  8. }
  9. function testSymbolicPredictDeterministicAddressSpillage(address implementation, bytes32 salt) public {
  10. address predicted = Clones.predictDeterministicAddress(implementation, salt);
  11. bytes32 spillage;
  12. assembly ("memory-safe") {
  13. spillage := and(predicted, 0xffffffffffffffffffffffff0000000000000000000000000000000000000000)
  14. }
  15. assertEq(spillage, bytes32(0));
  16. }
  17. function testSymbolicPredictDeterministicAddressWithImmutableArgsSpillage(
  18. address implementation,
  19. bytes32 salt,
  20. bytes memory args
  21. ) public {
  22. vm.assume(args.length < 0xbfd3);
  23. address predicted = Clones.predictDeterministicAddressWithImmutableArgs(implementation, args, salt);
  24. bytes32 spillage;
  25. /// @solidity memory-safe-assembly
  26. assembly {
  27. spillage := and(predicted, 0xffffffffffffffffffffffff0000000000000000000000000000000000000000)
  28. }
  29. assertEq(spillage, bytes32(0));
  30. }
  31. function testCloneDirty() external {
  32. address cloneClean = Clones.clone(address(this));
  33. address cloneDirty = Clones.clone(_dirty(address(this)));
  34. // both clones have the same code
  35. assertEq(cloneClean.code, cloneDirty.code);
  36. // both clones behave as expected
  37. assertEq(ClonesTest(cloneClean).getNumber(), this.getNumber());
  38. assertEq(ClonesTest(cloneDirty).getNumber(), this.getNumber());
  39. }
  40. function testCloneDeterministicDirty(bytes32 salt) external {
  41. address cloneClean = Clones.cloneDeterministic(address(this), salt);
  42. address cloneDirty = Clones.cloneDeterministic(_dirty(address(this)), ~salt);
  43. // both clones have the same code
  44. assertEq(cloneClean.code, cloneDirty.code);
  45. // both clones behave as expected
  46. assertEq(ClonesTest(cloneClean).getNumber(), this.getNumber());
  47. assertEq(ClonesTest(cloneDirty).getNumber(), this.getNumber());
  48. }
  49. function testPredictDeterministicAddressDirty(bytes32 salt) external {
  50. address predictClean = Clones.predictDeterministicAddress(address(this), salt);
  51. address predictDirty = Clones.predictDeterministicAddress(_dirty(address(this)), salt);
  52. //prediction should be similar
  53. assertEq(predictClean, predictDirty);
  54. }
  55. function testFetchCloneArgs(bytes memory args, bytes32 salt) external {
  56. vm.assume(args.length < 0xbfd3);
  57. address instance1 = Clones.cloneWithImmutableArgs(address(this), args);
  58. address instance2 = Clones.cloneDeterministicWithImmutableArgs(address(this), args, salt);
  59. // both clones have the same code
  60. assertEq(instance1.code, instance2.code);
  61. // both clones behave as expected and args can be fetched
  62. assertEq(ClonesTest(instance1).getNumber(), this.getNumber());
  63. assertEq(ClonesTest(instance2).getNumber(), this.getNumber());
  64. assertEq(Clones.fetchCloneArgs(instance1), args);
  65. assertEq(Clones.fetchCloneArgs(instance2), args);
  66. }
  67. function _dirty(address input) private pure returns (address output) {
  68. assembly ("memory-safe") {
  69. output := or(input, shl(160, not(0)))
  70. }
  71. }
  72. }