@chainlink/ace 0.5.0 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (126) hide show
  1. package/.github/workflows/npm-publish.yml +28 -0
  2. package/README.md +9 -1
  3. package/UPGRADE_GUIDE.md +754 -0
  4. package/getting_started/GETTING_STARTED.md +6 -0
  5. package/getting_started/MyVault.sol +2 -2
  6. package/getting_started/advanced/SanctionsPolicy.sol +6 -2
  7. package/package.json +3 -3
  8. package/packages/cross-chain-identity/docs/API_REFERENCE.md +2 -0
  9. package/packages/cross-chain-identity/src/CredentialRegistry.sol +9 -7
  10. package/packages/cross-chain-identity/src/CredentialRegistryFactory.sol +96 -0
  11. package/packages/cross-chain-identity/src/CredentialRegistryIdentityValidator.sol +15 -4
  12. package/packages/cross-chain-identity/src/CredentialRegistryIdentityValidatorPolicy.sol +10 -7
  13. package/packages/cross-chain-identity/src/IdentityRegistry.sol +33 -17
  14. package/packages/cross-chain-identity/src/IdentityRegistryFactory.sol +96 -0
  15. package/packages/cross-chain-identity/src/TrustedIssuerRegistry.sol +8 -6
  16. package/packages/cross-chain-identity/src/TrustedIssuerRegistryFactory.sol +96 -0
  17. package/packages/cross-chain-identity/src/interfaces/ICredentialRegistry.sol +6 -0
  18. package/packages/cross-chain-identity/src/interfaces/ICredentialRequirements.sol +2 -1
  19. package/packages/cross-chain-identity/src/interfaces/IIdentityRegistry.sol +7 -1
  20. package/packages/cross-chain-identity/src/interfaces/ITrustedIssuerRegistry.sol +6 -0
  21. package/packages/cross-chain-identity/test/CredentialRegistry.t.sol +1 -1
  22. package/packages/cross-chain-identity/test/CredentialRegistryFactory.t.sol +105 -0
  23. package/packages/cross-chain-identity/test/CredentialRegistryIdentityValidator.t.sol +16 -1
  24. package/packages/cross-chain-identity/test/CredentialRegistryIdentityValidatorPolicy.t.sol +58 -1
  25. package/packages/cross-chain-identity/test/IdentityRegistry.t.sol +140 -1
  26. package/packages/cross-chain-identity/test/IdentityRegistryFactory.t.sol +103 -0
  27. package/packages/cross-chain-identity/test/IdentityValidator.t.sol +1 -1
  28. package/packages/cross-chain-identity/test/TrustedIssuerRegistry.t.sol +1 -1
  29. package/packages/cross-chain-identity/test/TrustedIssuerRegistryFactory.t.sol +107 -0
  30. package/packages/cross-chain-identity/test/helpers/BaseProxyTest.sol +1 -1
  31. package/packages/cross-chain-identity/test/helpers/MockCredentialDataValidator.sol +1 -1
  32. package/packages/cross-chain-identity/test/helpers/MockCredentialRegistryReverting.sol +3 -1
  33. package/packages/policy-management/README.md +1 -0
  34. package/packages/policy-management/docs/API_GUIDE.md +2 -0
  35. package/packages/policy-management/docs/API_REFERENCE.md +3 -1
  36. package/packages/policy-management/docs/CUSTOM_POLICIES_TUTORIAL.md +10 -4
  37. package/packages/policy-management/src/core/Policy.sol +5 -4
  38. package/packages/policy-management/src/core/PolicyEngine.sol +113 -57
  39. package/packages/policy-management/src/core/PolicyEngineFactory.sol +102 -0
  40. package/packages/policy-management/src/core/PolicyFactory.sol +1 -1
  41. package/packages/policy-management/src/core/PolicyProtected.sol +28 -55
  42. package/packages/policy-management/src/core/PolicyProtectedUpgradeable.sol +134 -0
  43. package/packages/policy-management/src/extractors/ComplianceTokenForceTransferExtractor.sol +4 -1
  44. package/packages/policy-management/src/extractors/ComplianceTokenFreezeUnfreezeExtractor.sol +4 -1
  45. package/packages/policy-management/src/extractors/ComplianceTokenMintBurnExtractor.sol +4 -1
  46. package/packages/policy-management/src/extractors/ERC20ApproveExtractor.sol +4 -1
  47. package/packages/policy-management/src/extractors/ERC20TransferExtractor.sol +4 -1
  48. package/packages/policy-management/src/extractors/ERC3643ForcedTransferExtractor.sol +4 -1
  49. package/packages/policy-management/src/extractors/ERC3643FreezeUnfreezeExtractor.sol +4 -1
  50. package/packages/policy-management/src/extractors/ERC3643MintBurnExtractor.sol +4 -1
  51. package/packages/policy-management/src/extractors/ERC3643SetAddressFrozenExtractor.sol +4 -1
  52. package/packages/policy-management/src/interfaces/ICertifiedActionValidator.sol +110 -0
  53. package/packages/policy-management/src/interfaces/IExtractor.sol +6 -0
  54. package/packages/policy-management/src/interfaces/IMapper.sol +6 -0
  55. package/packages/policy-management/src/interfaces/IPolicy.sol +6 -0
  56. package/packages/policy-management/src/interfaces/IPolicyEngine.sol +90 -10
  57. package/packages/policy-management/src/interfaces/IPolicyProtected.sol +6 -0
  58. package/packages/policy-management/src/libraries/CertifiedActionLib.sol +47 -0
  59. package/packages/policy-management/src/policies/AllowPolicy.sol +12 -7
  60. package/packages/policy-management/src/policies/BypassPolicy.sol +23 -5
  61. package/packages/policy-management/src/policies/CertifiedActionDONValidatorPolicy.sol +156 -0
  62. package/packages/policy-management/src/policies/CertifiedActionERC20TransferValidatorPolicy.sol +202 -0
  63. package/packages/policy-management/src/policies/CertifiedActionValidatorPolicy.sol +365 -0
  64. package/packages/policy-management/src/policies/IntervalPolicy.sol +64 -48
  65. package/packages/policy-management/src/policies/MaxPolicy.sol +7 -5
  66. package/packages/policy-management/src/policies/OnlyAuthorizedSenderPolicy.sol +20 -4
  67. package/packages/policy-management/src/policies/OnlyOwnerPolicy.sol +4 -2
  68. package/packages/policy-management/src/policies/PausePolicy.sol +16 -15
  69. package/packages/policy-management/src/policies/RejectPolicy.sol +23 -5
  70. package/packages/policy-management/src/policies/RoleBasedAccessControlPolicy.sol +7 -5
  71. package/packages/policy-management/src/policies/SecureMintPolicy.sol +136 -48
  72. package/packages/policy-management/src/policies/VolumePolicy.sol +9 -5
  73. package/packages/policy-management/src/policies/VolumeRatePolicy.sol +11 -7
  74. package/packages/policy-management/test/PolicyEngine.t.sol +131 -23
  75. package/packages/policy-management/test/PolicyEngineFactory.t.sol +95 -0
  76. package/packages/policy-management/test/PolicyFactory.t.sol +1 -1
  77. package/packages/policy-management/test/{PolicyProtectedToken.t.sol → PolicyProtected.t.sol} +54 -8
  78. package/packages/policy-management/test/PolicyProtectedUpgradeable.t.sol +126 -0
  79. package/packages/policy-management/test/extractors/ComplianceTokenForceTransferExtractor.t.sol +1 -1
  80. package/packages/policy-management/test/extractors/ComplianceTokenFreezeUnfreezeExtractor.t.sol +1 -1
  81. package/packages/policy-management/test/extractors/ComplianceTokenMintBurnExtractor.t.sol +1 -1
  82. package/packages/policy-management/test/extractors/ERC20ApproveExtractor.t.sol +1 -1
  83. package/packages/policy-management/test/extractors/ERC3643ForcedTransferExtractor.t.sol +1 -1
  84. package/packages/policy-management/test/extractors/ERC3643FreezeUnfreezeExtractor.t.sol +1 -1
  85. package/packages/policy-management/test/extractors/ERC3643MintBurnExtractor.t.sol +1 -1
  86. package/packages/policy-management/test/extractors/ERC3643SetAddressFrozenExtractor.t.sol +1 -1
  87. package/packages/policy-management/test/helpers/BaseCertifiedActionTest.sol +44 -0
  88. package/packages/policy-management/test/helpers/BaseProxyTest.sol +88 -7
  89. package/packages/policy-management/test/helpers/CustomMapper.sol +3 -1
  90. package/packages/policy-management/test/helpers/DummyExtractor.sol +3 -1
  91. package/packages/policy-management/test/helpers/ExpectedParameterPolicy.sol +3 -1
  92. package/packages/policy-management/test/helpers/FaultyPolicyEngine.sol +54 -0
  93. package/packages/policy-management/test/helpers/MockCertifiedActionValidatorPolicyExtension.sol +46 -0
  94. package/packages/policy-management/test/helpers/MockToken.sol +2 -5
  95. package/packages/policy-management/test/helpers/MockTokenExtractor.sol +9 -4
  96. package/packages/policy-management/test/helpers/MockTokenUpgradeable.sol +66 -0
  97. package/packages/policy-management/test/helpers/PolicyAlwaysAllowed.sol +3 -1
  98. package/packages/policy-management/test/helpers/PolicyAlwaysContinue.sol +3 -1
  99. package/packages/policy-management/test/helpers/PolicyAlwaysRejected.sol +10 -1
  100. package/packages/policy-management/test/helpers/PolicyFailingRun.sol +3 -1
  101. package/packages/policy-management/test/policies/AllowPolicy.t.sol +39 -23
  102. package/packages/policy-management/test/policies/BypassPolicy.t.sol +48 -20
  103. package/packages/policy-management/test/policies/CertifiedActionDONValidatorPolicy.t.sol +172 -0
  104. package/packages/policy-management/test/policies/CertifiedActionERC20TransferValidatorPolicy.t.sol +217 -0
  105. package/packages/policy-management/test/policies/CertifiedActionValidatorPolicy.t.sol +1083 -0
  106. package/packages/policy-management/test/policies/IntervalPolicy.t.sol +105 -55
  107. package/packages/policy-management/test/policies/MaxPolicy.t.sol +15 -7
  108. package/packages/policy-management/test/policies/OnlyAuthorizedSenderPolicy.t.sol +91 -16
  109. package/packages/policy-management/test/policies/OnlyOwnerPolicy.t.sol +11 -7
  110. package/packages/policy-management/test/policies/PausePolicy.t.sol +46 -16
  111. package/packages/policy-management/test/policies/RejectPolicy.t.sol +52 -24
  112. package/packages/policy-management/test/policies/RoleBasedAccessControlPolicy.t.sol +50 -30
  113. package/packages/policy-management/test/policies/SecureMintPolicy.t.sol +211 -32
  114. package/packages/policy-management/test/policies/VolumePolicy.t.sol +20 -10
  115. package/packages/policy-management/test/policies/VolumeRatePolicy.t.sol +24 -18
  116. package/packages/tokens/erc-20/src/ComplianceTokenERC20.sol +4 -7
  117. package/packages/tokens/erc-20/src/ComplianceTokenStoreERC20.sol +4 -4
  118. package/packages/tokens/erc-20/test/ComplianceTokenERC20.t.sol +92 -82
  119. package/packages/tokens/erc-20/test/helpers/BaseProxyTest.sol +74 -1
  120. package/packages/tokens/erc-3643/src/ComplianceTokenERC3643.sol +12 -7
  121. package/packages/tokens/erc-3643/src/ComplianceTokenStoreERC3643.sol +4 -4
  122. package/packages/tokens/erc-3643/test/ComplianceTokenERC3643.t.sol +108 -119
  123. package/packages/tokens/erc-3643/test/helpers/BaseProxyTest.sol +74 -1
  124. package/packages/tokens/erc-3643/test/helpers/ExpectedContextPolicy.sol +3 -1
  125. package/remappings.txt +1 -0
  126. package/script/DeployCertifiedActionsComplianceTokenERC3643.s.sol +125 -0
@@ -1,16 +1,16 @@
1
1
  // SPDX-License-Identifier: BUSL-1.1
2
- pragma solidity 0.8.26;
2
+ pragma solidity ^0.8.20;
3
3
 
4
4
  import {IPolicyEngine, PolicyEngine} from "@chainlink/policy-management/core/PolicyEngine.sol";
5
5
  import {ERC20TransferExtractor} from "@chainlink/policy-management/extractors/ERC20TransferExtractor.sol";
6
6
  import {BypassPolicy} from "@chainlink/policy-management/policies/BypassPolicy.sol";
7
- import {MockToken} from "../helpers/MockToken.sol";
7
+ import {MockTokenUpgradeable} from "../helpers/MockTokenUpgradeable.sol";
8
8
  import {ERC3643MintBurnExtractor} from "@chainlink/policy-management/extractors/ERC3643MintBurnExtractor.sol";
9
9
  import {BaseProxyTest} from "../helpers/BaseProxyTest.sol";
10
10
 
11
11
  contract BypassPolicyTest is BaseProxyTest {
12
12
  PolicyEngine public policyEngine;
13
- MockToken public token;
13
+ MockTokenUpgradeable public token;
14
14
  BypassPolicy public bypassPolicy;
15
15
  address public deployer;
16
16
  address public account;
@@ -30,26 +30,31 @@ contract BypassPolicyTest is BaseProxyTest {
30
30
  // add account by default
31
31
  bypassPolicy.allowAddress(account);
32
32
 
33
- token = MockToken(_deployMockToken(address(policyEngine)));
33
+ token = MockTokenUpgradeable(_deployMockToken(address(policyEngine)));
34
34
 
35
35
  // set up the bypassPolicy to check the recipient and origin address of token transfers
36
36
  ERC20TransferExtractor transferExtractor = new ERC20TransferExtractor();
37
37
  bytes32[] memory transferPolicyParams = new bytes32[](2);
38
38
  transferPolicyParams[0] = transferExtractor.PARAM_TO();
39
39
  transferPolicyParams[1] = transferExtractor.PARAM_FROM();
40
- policyEngine.setExtractor(MockToken.transfer.selector, address(transferExtractor));
41
- policyEngine.addPolicy(address(token), MockToken.transfer.selector, address(bypassPolicy), transferPolicyParams);
40
+ policyEngine.setExtractor(MockTokenUpgradeable.transfer.selector, address(transferExtractor));
41
+ policyEngine.addPolicy(
42
+ address(token), MockTokenUpgradeable.transfer.selector, address(bypassPolicy), transferPolicyParams
43
+ );
42
44
  // set up the bypassPolicy to check the mint account (single account)
43
45
  ERC3643MintBurnExtractor mintBurnExtractor = new ERC3643MintBurnExtractor();
44
46
  bytes32[] memory mintPolicyParams = new bytes32[](1);
45
47
  mintPolicyParams[0] = mintBurnExtractor.PARAM_ACCOUNT();
46
- policyEngine.setExtractor(MockToken.mint.selector, address(mintBurnExtractor));
47
- policyEngine.addPolicy(address(token), MockToken.mint.selector, address(bypassPolicy), mintPolicyParams);
48
+ policyEngine.setExtractor(MockTokenUpgradeable.mint.selector, address(mintBurnExtractor));
49
+ policyEngine.addPolicy(address(token), MockTokenUpgradeable.mint.selector, address(bypassPolicy), mintPolicyParams);
48
50
  }
49
51
 
50
52
  function test_allowAddress_succeeds() public {
51
53
  vm.startPrank(deployer, deployer);
52
54
 
55
+ vm.expectEmit(true, true, true, true);
56
+ emit BypassPolicy.AddressAllowed(recipient);
57
+
53
58
  // add the address to the allow list
54
59
  bypassPolicy.allowAddress(recipient);
55
60
  vm.assertEq(bypassPolicy.addressAllowed(recipient), true);
@@ -74,6 +79,9 @@ contract BypassPolicyTest is BaseProxyTest {
74
79
  bypassPolicy.allowAddress(recipient);
75
80
  vm.assertEq(bypassPolicy.addressAllowed(recipient), true);
76
81
 
82
+ vm.expectEmit(true, true, true, true);
83
+ emit BypassPolicy.AddressDisallowed(recipient);
84
+
77
85
  // remove the address from the bypass list
78
86
  bypassPolicy.disallowAddress(recipient);
79
87
  vm.assertEq(bypassPolicy.addressAllowed(recipient), false);
@@ -105,7 +113,13 @@ contract BypassPolicyTest is BaseProxyTest {
105
113
  vm.startPrank(account, account);
106
114
 
107
115
  // transfer from address to recipient (reverts)
108
- vm.expectRevert(_encodeRejectedRevert(0, address(0), "no policy allowed the action and default is reject"));
116
+ _expectRejectedRevert(
117
+ address(0),
118
+ "no policy allowed the action and default is reject",
119
+ MockTokenUpgradeable.transfer.selector,
120
+ account,
121
+ abi.encode(recipient, 100)
122
+ );
109
123
  token.transfer(recipient, 100);
110
124
  }
111
125
 
@@ -125,7 +139,13 @@ contract BypassPolicyTest is BaseProxyTest {
125
139
 
126
140
  // transfer from address to recipient (should revert after removal)
127
141
  vm.startPrank(account, account);
128
- vm.expectRevert(_encodeRejectedRevert(0, address(0), "no policy allowed the action and default is reject"));
142
+ _expectRejectedRevert(
143
+ address(0),
144
+ "no policy allowed the action and default is reject",
145
+ MockTokenUpgradeable.transfer.selector,
146
+ account,
147
+ abi.encode(recipient, 100)
148
+ );
129
149
  token.transfer(recipient, 100);
130
150
  }
131
151
 
@@ -137,7 +157,13 @@ contract BypassPolicyTest is BaseProxyTest {
137
157
 
138
158
  function test_mint_notInList_defaultReject_failure() public {
139
159
  vm.startPrank(deployer, deployer);
140
- vm.expectRevert(_encodeRejectedRevert(0, address(0), "no policy allowed the action and default is reject"));
160
+ _expectRejectedRevert(
161
+ address(0),
162
+ "no policy allowed the action and default is reject",
163
+ MockTokenUpgradeable.mint.selector,
164
+ deployer,
165
+ abi.encode(recipient, 100)
166
+ );
141
167
  token.mint(recipient, 100);
142
168
  }
143
169
 
@@ -145,15 +171,17 @@ contract BypassPolicyTest is BaseProxyTest {
145
171
  vm.startPrank(deployer);
146
172
  // misconfigure the bypassPolicy to check burn operations (no accounts)
147
173
  ERC3643MintBurnExtractor mintBurnExtractor = new ERC3643MintBurnExtractor();
148
- policyEngine.setExtractor(MockToken.burn.selector, address(mintBurnExtractor));
149
- policyEngine.addPolicy(address(token), MockToken.burn.selector, address(bypassPolicy), new bytes32[](0));
150
-
151
- bytes memory error = abi.encodeWithSignature("Error(string)", "expected at least 1 parameter");
152
- vm.expectRevert(
153
- abi.encodeWithSelector(
154
- IPolicyEngine.PolicyRunError.selector, MockToken.burn.selector, address(bypassPolicy), error
155
- )
156
- );
174
+ policyEngine.setExtractor(MockTokenUpgradeable.burn.selector, address(mintBurnExtractor));
175
+ policyEngine.addPolicy(address(token), MockTokenUpgradeable.burn.selector, address(bypassPolicy), new bytes32[](0));
176
+
177
+ IPolicyEngine.Payload memory payload = IPolicyEngine.Payload({
178
+ selector: MockTokenUpgradeable.burn.selector,
179
+ sender: deployer,
180
+ data: abi.encode(account, 100),
181
+ context: new bytes(0)
182
+ });
183
+ bytes memory error = abi.encodeWithSignature("InvalidParameters(string)", "expected at least 1 parameter");
184
+ _expectRunError(address(bypassPolicy), error, payload);
157
185
  token.burn(account, 100);
158
186
  }
159
187
  }
@@ -0,0 +1,172 @@
1
+ // SPDX-License-Identifier: BUSL-1.1
2
+ pragma solidity ^0.8.20;
3
+
4
+ import {IPolicyEngine, PolicyEngine} from "@chainlink/policy-management/core/PolicyEngine.sol";
5
+ import {ICertifiedActionValidator} from "@chainlink/policy-management/interfaces/ICertifiedActionValidator.sol";
6
+ import {CertifiedActionValidatorPolicy} from "@chainlink/policy-management/policies/CertifiedActionValidatorPolicy.sol";
7
+ import {CertifiedActionDONValidatorPolicy} from
8
+ "@chainlink/policy-management/policies/CertifiedActionDONValidatorPolicy.sol";
9
+ import {MockTokenUpgradeable} from "../helpers/MockTokenUpgradeable.sol";
10
+ import {MockTokenExtractor} from "../helpers/MockTokenExtractor.sol";
11
+ import {BaseCertifiedActionTest} from "../helpers/BaseCertifiedActionTest.sol";
12
+
13
+ contract CertifiedActionDONValidatorPolicyTest is BaseCertifiedActionTest {
14
+ PolicyEngine public policyEngine;
15
+ MockTokenUpgradeable public token;
16
+ CertifiedActionDONValidatorPolicy public policy;
17
+ address public deployer;
18
+ address public recipient;
19
+ address public signer;
20
+ uint256 public signerKey;
21
+ address public mockKeystoneForwarder;
22
+
23
+ function setUp() public {
24
+ deployer = makeAddr("deployer");
25
+ recipient = makeAddr("recipient");
26
+ (signer, signerKey) = makeAddrAndKey("signer");
27
+ mockKeystoneForwarder = makeAddr("mockKeystoneForwarder");
28
+
29
+ vm.startPrank(deployer);
30
+
31
+ policyEngine = _deployPolicyEngine(true, deployer);
32
+
33
+ CertifiedActionDONValidatorPolicy policyImpl = new CertifiedActionDONValidatorPolicy();
34
+ policy = CertifiedActionDONValidatorPolicy(
35
+ _deployPolicy(address(policyImpl), address(policyEngine), deployer, abi.encode(mockKeystoneForwarder))
36
+ );
37
+ policy.allowIssuer(abi.encode(signer));
38
+ MockTokenExtractor extractor = new MockTokenExtractor();
39
+ bytes32[] memory parameterOutputFormat = new bytes32[](3);
40
+ parameterOutputFormat[0] = extractor.PARAM_FROM();
41
+ parameterOutputFormat[1] = extractor.PARAM_TO();
42
+ parameterOutputFormat[2] = extractor.PARAM_AMOUNT();
43
+
44
+ token = MockTokenUpgradeable(_deployMockToken(address(policyEngine)));
45
+
46
+ policyEngine.setExtractor(MockTokenUpgradeable.transfer.selector, address(extractor));
47
+ policyEngine.setExtractor(MockTokenUpgradeable.transferFrom.selector, address(extractor));
48
+
49
+ policyEngine.addPolicy(
50
+ address(token), MockTokenUpgradeable.transfer.selector, address(policy), parameterOutputFormat
51
+ );
52
+ policyEngine.addPolicy(
53
+ address(token), MockTokenUpgradeable.transferFrom.selector, address(policy), parameterOutputFormat
54
+ );
55
+ }
56
+
57
+ function test_DONPreActionPermit_validPermit_succeeds() public {
58
+ vm.startPrank(mockKeystoneForwarder);
59
+
60
+ bytes[] memory params = new bytes[](3);
61
+ params[0] = abi.encode(deployer);
62
+ params[1] = abi.encode(recipient);
63
+ params[2] = abi.encode(uint256(100));
64
+
65
+ ICertifiedActionValidator.Permit memory permit =
66
+ _generatePermit(deployer, address(token), MockTokenUpgradeable.transfer.selector, params);
67
+
68
+ policy.onReport(_ocrMetadata(), abi.encode(permit));
69
+ uint256 usage = policy.getUsage(permit.permitId);
70
+
71
+ vm.stopPrank();
72
+ vm.startPrank(deployer);
73
+
74
+ vm.assertEq(token.balanceOf(recipient), 0);
75
+ token.transfer(recipient, 100);
76
+ vm.assertEq(token.balanceOf(recipient), 100);
77
+ vm.assertEq(policy.getUsage(permit.permitId), usage + 1);
78
+ }
79
+
80
+ function test_InvalidDONPreActionPermit_validPermit_succeeds() public {
81
+ address bogus = makeAddr("bogus");
82
+ vm.startPrank(bogus);
83
+
84
+ bytes[] memory params = new bytes[](3);
85
+ params[0] = abi.encode(deployer);
86
+ params[1] = abi.encode(recipient);
87
+ params[2] = abi.encode(uint256(100));
88
+
89
+ ICertifiedActionValidator.Permit memory permit =
90
+ _generatePermit(deployer, address(token), MockTokenUpgradeable.transfer.selector, params);
91
+
92
+ vm.expectRevert(
93
+ abi.encodeWithSelector(CertifiedActionDONValidatorPolicy.UnauthorizedKeystoneForwarder.selector, bogus)
94
+ );
95
+ policy.onReport(_ocrMetadata(), abi.encode(permit));
96
+ }
97
+
98
+ function test_check_fromKeystoneForwarder_returnsTrue() public {
99
+ vm.startPrank(mockKeystoneForwarder);
100
+
101
+ bytes[] memory params = new bytes[](3);
102
+ params[0] = abi.encode(deployer);
103
+ params[1] = abi.encode(recipient);
104
+ params[2] = abi.encode(uint256(100));
105
+
106
+ ICertifiedActionValidator.Permit memory permit =
107
+ _generatePermit(deployer, address(token), MockTokenUpgradeable.transfer.selector, params);
108
+
109
+ policy.onReport(_ocrMetadata(), abi.encode(permit));
110
+
111
+ vm.assertEq(policy.check(permit, abi.encode(signer)), true);
112
+ }
113
+
114
+ function test_check_invalidAddress_fromKeystoneForwarder_returnsFalse() public {
115
+ vm.startPrank(mockKeystoneForwarder);
116
+
117
+ bytes[] memory params = new bytes[](3);
118
+ params[0] = abi.encode(deployer);
119
+ params[1] = abi.encode(recipient);
120
+ params[2] = abi.encode(uint256(100));
121
+
122
+ ICertifiedActionValidator.Permit memory permit =
123
+ _generatePermit(deployer, address(token), MockTokenUpgradeable.transfer.selector, params);
124
+
125
+ policy.onReport(_ocrMetadata(), abi.encode(permit));
126
+
127
+ vm.assertEq(policy.check(permit, abi.encode(makeAddr("randomAddress"))), false);
128
+ }
129
+
130
+ function test_contextualPermit_reverts() public {
131
+ vm.startPrank(deployer);
132
+
133
+ MockTokenExtractor extractor = new MockTokenExtractor();
134
+ bytes32[] memory parameterOutputFormat = new bytes32[](3);
135
+ parameterOutputFormat[0] = extractor.PARAM_FROM();
136
+ parameterOutputFormat[1] = extractor.PARAM_TO();
137
+ parameterOutputFormat[2] = extractor.PARAM_AMOUNT();
138
+
139
+ policyEngine.setExtractor(MockTokenUpgradeable.transferWithContext.selector, address(extractor));
140
+ policyEngine.addPolicy(
141
+ address(token), MockTokenUpgradeable.transferWithContext.selector, address(policy), parameterOutputFormat
142
+ );
143
+
144
+ bytes[] memory params = new bytes[](3);
145
+ params[0] = abi.encode(deployer);
146
+ params[1] = abi.encode(recipient);
147
+ params[2] = abi.encode(uint256(100));
148
+
149
+ ICertifiedActionValidator.Permit memory permit =
150
+ _generatePermit(deployer, address(token), MockTokenUpgradeable.transferWithContext.selector, params);
151
+
152
+ bytes memory context = abi.encode(ICertifiedActionValidator.SignedPermit(permit, abi.encode(signer)));
153
+ _expectRejectedRevert(
154
+ address(policy),
155
+ "invalid signed permit in context",
156
+ MockTokenUpgradeable.transferWithContext.selector,
157
+ deployer,
158
+ abi.encode(recipient, 100, context),
159
+ context
160
+ );
161
+ token.transferWithContext(recipient, 100, context);
162
+ }
163
+
164
+ function _ocrMetadata() internal returns (bytes memory) {
165
+ return abi.encodePacked(
166
+ uint256(1234), // workflow_cid (32 bytes)
167
+ "AAAAAAAAAA", // workflow_name (10 bytes)
168
+ signer, // workflow_owner (20 bytes)
169
+ "BB" // report_name (2 bytes)
170
+ );
171
+ }
172
+ }
@@ -0,0 +1,217 @@
1
+ // SPDX-License-Identifier: BUSL-1.1
2
+ pragma solidity ^0.8.20;
3
+
4
+ import {IPolicyEngine, PolicyEngine} from "@chainlink/policy-management/core/PolicyEngine.sol";
5
+ import {ICertifiedActionValidator} from "@chainlink/policy-management/interfaces/ICertifiedActionValidator.sol";
6
+ import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
7
+ import {Policy} from "@chainlink/policy-management/core/Policy.sol";
8
+ import {CertifiedActionValidatorPolicy} from "@chainlink/policy-management/policies/CertifiedActionValidatorPolicy.sol";
9
+ import {CertifiedActionERC20TransferValidatorPolicy} from
10
+ "@chainlink/policy-management/policies/CertifiedActionERC20TransferValidatorPolicy.sol";
11
+ import {MockTokenUpgradeable} from "../helpers/MockTokenUpgradeable.sol";
12
+ import {MockTokenExtractor} from "../helpers/MockTokenExtractor.sol";
13
+ import {BaseCertifiedActionTest} from "../helpers/BaseCertifiedActionTest.sol";
14
+
15
+ contract CertifiedActionERC20TransferValidatorPolicyTest is BaseCertifiedActionTest {
16
+ PolicyEngine public policyEngine;
17
+ MockTokenUpgradeable public token;
18
+ CertifiedActionValidatorPolicy public policy;
19
+ address public deployer;
20
+ address public recipient;
21
+ address public signer;
22
+ uint256 public signerKey;
23
+
24
+ function setUp() public {
25
+ deployer = makeAddr("deployer");
26
+ recipient = makeAddr("recipient");
27
+ (signer, signerKey) = makeAddrAndKey("signer");
28
+
29
+ vm.startPrank(deployer);
30
+
31
+ policyEngine = _deployPolicyEngine(true, deployer);
32
+
33
+ CertifiedActionERC20TransferValidatorPolicy policyImpl = new CertifiedActionERC20TransferValidatorPolicy();
34
+ policy = CertifiedActionERC20TransferValidatorPolicy(
35
+ _deployPolicy(address(policyImpl), address(policyEngine), deployer, "")
36
+ );
37
+ policy.allowIssuer(abi.encode(signer));
38
+ MockTokenExtractor extractor = new MockTokenExtractor();
39
+ bytes32[] memory parameterOutputFormat = new bytes32[](3);
40
+ parameterOutputFormat[0] = extractor.PARAM_FROM();
41
+ parameterOutputFormat[1] = extractor.PARAM_TO();
42
+ parameterOutputFormat[2] = extractor.PARAM_AMOUNT();
43
+
44
+ token = MockTokenUpgradeable(_deployMockToken(address(policyEngine)));
45
+
46
+ policyEngine.setExtractor(MockTokenUpgradeable.transfer.selector, address(extractor));
47
+ policyEngine.setExtractor(MockTokenUpgradeable.transferWithContext.selector, address(extractor));
48
+ policyEngine.setExtractor(MockTokenUpgradeable.transferFrom.selector, address(extractor));
49
+
50
+ policyEngine.addPolicy(
51
+ address(token), MockTokenUpgradeable.transfer.selector, address(policy), parameterOutputFormat
52
+ );
53
+ policyEngine.addPolicy(
54
+ address(token), MockTokenUpgradeable.transferWithContext.selector, address(policy), parameterOutputFormat
55
+ );
56
+ policyEngine.addPolicy(
57
+ address(token), MockTokenUpgradeable.transferFrom.selector, address(policy), parameterOutputFormat
58
+ );
59
+ }
60
+
61
+ function test_preActionPermit_validPermitExact_succeeds() public {
62
+ vm.startPrank(deployer);
63
+
64
+ bytes[] memory params = new bytes[](3);
65
+ params[0] = abi.encode(deployer);
66
+ params[1] = abi.encode(recipient);
67
+ params[2] = abi.encode(uint256(100));
68
+
69
+ ICertifiedActionValidator.Permit memory permit =
70
+ _generatePermit(deployer, address(token), IERC20.transfer.selector, params);
71
+
72
+ bytes memory signature = _signPermit(policy, permit, signerKey);
73
+
74
+ policy.present(permit, signature);
75
+ uint256 usage = policy.getUsage(permit.permitId);
76
+
77
+ vm.assertEq(token.balanceOf(recipient), 0);
78
+ token.transfer(recipient, 100);
79
+ vm.assertEq(token.balanceOf(recipient), 100);
80
+ vm.assertEq(policy.getUsage(permit.permitId), usage + 1);
81
+ }
82
+
83
+ function test_preActionPermit_validPermitUnderMax_succeeds() public {
84
+ vm.startPrank(deployer);
85
+
86
+ bytes[] memory params = new bytes[](3);
87
+ params[0] = abi.encode(deployer);
88
+ params[1] = abi.encode(recipient);
89
+ params[2] = abi.encode(uint256(100));
90
+
91
+ ICertifiedActionValidator.Permit memory permit =
92
+ _generatePermit(deployer, address(token), IERC20.transfer.selector, params);
93
+
94
+ bytes memory signature = _signPermit(policy, permit, signerKey);
95
+
96
+ policy.present(permit, signature);
97
+ uint256 usage = policy.getUsage(permit.permitId);
98
+
99
+ vm.assertEq(token.balanceOf(recipient), 0);
100
+ token.transfer(recipient, 99);
101
+ vm.assertEq(token.balanceOf(recipient), 99);
102
+ vm.assertEq(policy.getUsage(permit.permitId), usage + 1);
103
+ }
104
+
105
+ function test_preActionPermit_validPermitOverMaxAmount_reverts() public {
106
+ vm.startPrank(deployer);
107
+
108
+ bytes[] memory params = new bytes[](3);
109
+ params[0] = abi.encode(deployer);
110
+ params[1] = abi.encode(recipient);
111
+ params[2] = abi.encode(uint256(100));
112
+
113
+ ICertifiedActionValidator.Permit memory permit =
114
+ _generatePermit(deployer, address(token), IERC20.transfer.selector, params);
115
+
116
+ bytes memory signature = _signPermit(policy, permit, signerKey);
117
+
118
+ policy.present(permit, signature);
119
+
120
+ _expectRejectedRevert(
121
+ address(policy),
122
+ "no valid pre-presented permit found",
123
+ MockTokenUpgradeable.transfer.selector,
124
+ deployer,
125
+ abi.encode(recipient, 101)
126
+ );
127
+ token.transfer(recipient, 101);
128
+ }
129
+
130
+ function test_preActionPermit_invalidSelector_reverts() public {
131
+ vm.startPrank(deployer);
132
+
133
+ bytes[] memory params = new bytes[](3);
134
+ params[0] = abi.encode(deployer);
135
+ params[1] = abi.encode(recipient);
136
+ params[2] = abi.encode(uint256(100));
137
+
138
+ ICertifiedActionValidator.Permit memory permit =
139
+ _generatePermit(deployer, address(token), IERC20.approve.selector, params);
140
+
141
+ bytes memory signature = _signPermit(policy, permit, signerKey);
142
+
143
+ vm.expectRevert(abi.encodeWithSelector(Policy.InvalidParameters.selector, "unsupported selector"));
144
+ policy.present(permit, signature);
145
+ }
146
+
147
+ function test_no_permit_reverts() public {
148
+ vm.startPrank(deployer);
149
+
150
+ _expectRejectedRevert(
151
+ address(policy),
152
+ "no valid permit found",
153
+ MockTokenUpgradeable.transfer.selector,
154
+ deployer,
155
+ abi.encode(recipient, 100)
156
+ );
157
+ token.transfer(recipient, 100);
158
+ }
159
+
160
+ function test_check_validPermit_returnsTrue() public {
161
+ vm.startPrank(deployer);
162
+
163
+ bytes[] memory params = new bytes[](3);
164
+ params[0] = abi.encode(deployer);
165
+ params[1] = abi.encode(recipient);
166
+ params[2] = abi.encode(uint256(100));
167
+
168
+ // permit for transfer
169
+ ICertifiedActionValidator.Permit memory permit1 =
170
+ _generatePermit(deployer, address(token), IERC20.transfer.selector, params);
171
+
172
+ bytes memory signature1 = _signPermit(policy, permit1, signerKey);
173
+
174
+ policy.present(permit1, signature1);
175
+ vm.assertEq(policy.check(permit1, signature1), true);
176
+
177
+ // permit for transferFrom
178
+ ICertifiedActionValidator.Permit memory permit2 =
179
+ _generatePermit(deployer, address(token), IERC20.transferFrom.selector, params);
180
+
181
+ bytes memory signature2 = _signPermit(policy, permit2, signerKey);
182
+
183
+ policy.present(permit2, signature2);
184
+ vm.assertEq(policy.check(permit2, signature2), true);
185
+ }
186
+
187
+ function test_check_invalidSelector_returnsFalse() public {
188
+ vm.startPrank(deployer);
189
+
190
+ bytes[] memory params = new bytes[](3);
191
+ params[0] = abi.encode(deployer);
192
+ params[1] = abi.encode(recipient);
193
+ params[2] = abi.encode(uint256(100));
194
+
195
+ ICertifiedActionValidator.Permit memory permit =
196
+ _generatePermit(deployer, address(token), IERC20.approve.selector, params);
197
+
198
+ bytes memory signature = _signPermit(policy, permit, signerKey);
199
+
200
+ vm.assertEq(policy.check(permit, signature), false);
201
+ }
202
+
203
+ function test_check_invalidParameters_returnsFalse() public {
204
+ vm.startPrank(deployer);
205
+
206
+ bytes[] memory params = new bytes[](2); // missing amount parameter
207
+ params[0] = abi.encode(deployer);
208
+ params[1] = abi.encode(recipient);
209
+
210
+ ICertifiedActionValidator.Permit memory permit =
211
+ _generatePermit(deployer, address(token), IERC20.transfer.selector, params);
212
+
213
+ bytes memory signature = _signPermit(policy, permit, signerKey);
214
+
215
+ vm.assertEq(policy.check(permit, signature), false);
216
+ }
217
+ }