@coti-io/coti-contracts 0.1.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 (180) hide show
  1. package/.github/workflows/npm-publish.yml +52 -0
  2. package/CODE_OF_CONDUCT.md +44 -0
  3. package/CONTRIBUTING.md +101 -0
  4. package/LICENSE +201 -0
  5. package/README.md +48 -0
  6. package/contracts/access/DataPrivacyFramework/DataPrivacyFramework.sol +480 -0
  7. package/contracts/access/DataPrivacyFramework/README.md +68 -0
  8. package/contracts/access/DataPrivacyFramework/extensions/DataPrivacyFrameworkMpc.sol +1139 -0
  9. package/contracts/mocks/README.md +5 -0
  10. package/contracts/mocks/access/DataPrivacyFramework/DataPrivacyFrameworkMock.sol +9 -0
  11. package/contracts/mocks/token/PrivateERC20/PrivateERC20Mock.sol +17 -0
  12. package/contracts/mocks/token/PrivateERC721/PrivateERC721URIStorageMock.sol +34 -0
  13. package/contracts/mocks/utils/mpc/ArithmeticTestsContract.sol +431 -0
  14. package/contracts/mocks/utils/mpc/BitwiseTestsContract.sol +361 -0
  15. package/contracts/mocks/utils/mpc/Comparison1Tests.Contract.sol +307 -0
  16. package/contracts/mocks/utils/mpc/Comparison2TestsContract.sol +307 -0
  17. package/contracts/mocks/utils/mpc/MinMaxTestsContract.sol +297 -0
  18. package/contracts/mocks/utils/mpc/Miscellaneous1TestsContract.sol +185 -0
  19. package/contracts/mocks/utils/mpc/Miscellaneous2TestsContract.sol +448 -0
  20. package/contracts/mocks/utils/mpc/OffboardToUserKeyTestsContract.sol +81 -0
  21. package/contracts/mocks/utils/mpc/README.md +486 -0
  22. package/contracts/mocks/utils/mpc/ShiftTestsContract.sol +311 -0
  23. package/contracts/mocks/utils/mpc/StringTestsContract.sol +59 -0
  24. package/contracts/mocks/utils/mpc/TransferScalarTestsContract.sol +271 -0
  25. package/contracts/mocks/utils/mpc/TransferTestsContract.sol +715 -0
  26. package/contracts/mocks/wallet/PrivateERC20Wallet/PrivateERC20WalletMock.sol +25 -0
  27. package/contracts/onboard/AccountOnboard.sol +21 -0
  28. package/contracts/onboard/README.md +65 -0
  29. package/contracts/package.json +11 -0
  30. package/contracts/token/PrivateERC20/IPrivateERC20.sol +142 -0
  31. package/contracts/token/PrivateERC20/PrivateERC20.sol +478 -0
  32. package/contracts/token/PrivateERC20/README.md +104 -0
  33. package/contracts/token/PrivateERC721/PrivateERC721.sol +458 -0
  34. package/contracts/token/PrivateERC721/README.md +282 -0
  35. package/contracts/token/PrivateERC721/extensions/PrivateERC721URIStorage.sol +87 -0
  36. package/contracts/utils/mpc/MpcCore.sol +3215 -0
  37. package/contracts/utils/mpc/MpcInterface.sol +41 -0
  38. package/contracts/utils/mpc/README.md +82 -0
  39. package/hardhat.config.ts +18 -0
  40. package/package.json +14 -0
  41. package/test/access/DataPrivacyFramework/DataPrivacyFramework.test.ts +780 -0
  42. package/test/onboard/AccountOnboard.test.ts +45 -0
  43. package/test/token/PrivateERC20/PrivateERC20.test.ts +546 -0
  44. package/test/token/PrivateERC721/PrivateERC721.test.ts +223 -0
  45. package/test/utils/accounts.ts +55 -0
  46. package/test/utils/mpc/Precompile.test.ts +113 -0
  47. package/test/utils/mpc/String.test.ts +227 -0
  48. package/tsconfig.json +11 -0
  49. package/typechain-types/@openzeppelin/contracts/index.ts +9 -0
  50. package/typechain-types/@openzeppelin/contracts/interfaces/IERC4906.ts +462 -0
  51. package/typechain-types/@openzeppelin/contracts/interfaces/draft-IERC6093.sol/IERC1155Errors.ts +69 -0
  52. package/typechain-types/@openzeppelin/contracts/interfaces/draft-IERC6093.sol/IERC20Errors.ts +69 -0
  53. package/typechain-types/@openzeppelin/contracts/interfaces/draft-IERC6093.sol/IERC721Errors.ts +69 -0
  54. package/typechain-types/@openzeppelin/contracts/interfaces/draft-IERC6093.sol/index.ts +6 -0
  55. package/typechain-types/@openzeppelin/contracts/interfaces/index.ts +6 -0
  56. package/typechain-types/@openzeppelin/contracts/token/ERC721/IERC721.ts +393 -0
  57. package/typechain-types/@openzeppelin/contracts/token/ERC721/IERC721Receiver.ts +110 -0
  58. package/typechain-types/@openzeppelin/contracts/token/ERC721/index.ts +5 -0
  59. package/typechain-types/@openzeppelin/contracts/token/index.ts +5 -0
  60. package/typechain-types/@openzeppelin/contracts/utils/index.ts +5 -0
  61. package/typechain-types/@openzeppelin/contracts/utils/introspection/ERC165.ts +94 -0
  62. package/typechain-types/@openzeppelin/contracts/utils/introspection/IERC165.ts +94 -0
  63. package/typechain-types/@openzeppelin/contracts/utils/introspection/index.ts +5 -0
  64. package/typechain-types/@openzeppelin/index.ts +5 -0
  65. package/typechain-types/common.ts +131 -0
  66. package/typechain-types/contracts/access/DataPrivacyFramework/DataPrivacyFramework.ts +598 -0
  67. package/typechain-types/contracts/access/DataPrivacyFramework/extensions/DataPrivacyFrameworkMpc.ts +598 -0
  68. package/typechain-types/contracts/access/DataPrivacyFramework/extensions/index.ts +4 -0
  69. package/typechain-types/contracts/access/DataPrivacyFramework/index.ts +6 -0
  70. package/typechain-types/contracts/access/index.ts +5 -0
  71. package/typechain-types/contracts/index.ts +13 -0
  72. package/typechain-types/contracts/mocks/access/DataPrivacyFramework/DataPrivacyFrameworkMock.ts +598 -0
  73. package/typechain-types/contracts/mocks/access/DataPrivacyFramework/index.ts +4 -0
  74. package/typechain-types/contracts/mocks/access/index.ts +5 -0
  75. package/typechain-types/contracts/mocks/index.ts +11 -0
  76. package/typechain-types/contracts/mocks/token/PrivateERC20/PrivateERC20Mock.ts +543 -0
  77. package/typechain-types/contracts/mocks/token/PrivateERC20/index.ts +4 -0
  78. package/typechain-types/contracts/mocks/token/PrivateERC721/PrivateERC721URIStorageMock.ts +576 -0
  79. package/typechain-types/contracts/mocks/token/PrivateERC721/index.ts +4 -0
  80. package/typechain-types/contracts/mocks/token/index.ts +7 -0
  81. package/typechain-types/contracts/mocks/utils/index.ts +5 -0
  82. package/typechain-types/contracts/mocks/utils/mpc/ArithmeticTestsContract.ts +354 -0
  83. package/typechain-types/contracts/mocks/utils/mpc/BitwiseTestsContract.ts +340 -0
  84. package/typechain-types/contracts/mocks/utils/mpc/Comparison1Tests.Contract.sol/Comparison1TestsContract.ts +340 -0
  85. package/typechain-types/contracts/mocks/utils/mpc/Comparison1Tests.Contract.sol/index.ts +4 -0
  86. package/typechain-types/contracts/mocks/utils/mpc/Comparison2TestsContract.ts +340 -0
  87. package/typechain-types/contracts/mocks/utils/mpc/MinMaxTestsContract.ts +321 -0
  88. package/typechain-types/contracts/mocks/utils/mpc/Miscellaneous1TestsContract.ts +199 -0
  89. package/typechain-types/contracts/mocks/utils/mpc/Miscellaneous2TestsContract.ts +384 -0
  90. package/typechain-types/contracts/mocks/utils/mpc/OffboardToUserKeyTestsContract.sol/OffboardToUserKeyTestContract.ts +218 -0
  91. package/typechain-types/contracts/mocks/utils/mpc/OffboardToUserKeyTestsContract.sol/index.ts +4 -0
  92. package/typechain-types/contracts/mocks/utils/mpc/ShiftTestsContract.ts +339 -0
  93. package/typechain-types/contracts/mocks/utils/mpc/StringTestsContract.ts +211 -0
  94. package/typechain-types/contracts/mocks/utils/mpc/TransferScalarTestsContract.ts +266 -0
  95. package/typechain-types/contracts/mocks/utils/mpc/TransferTestsContract.ts +288 -0
  96. package/typechain-types/contracts/mocks/utils/mpc/index.ts +17 -0
  97. package/typechain-types/contracts/mocks/wallet/PrivateERC20Wallet/PrivateERC20WalletMock.ts +173 -0
  98. package/typechain-types/contracts/mocks/wallet/PrivateERC20Wallet/index.ts +4 -0
  99. package/typechain-types/contracts/mocks/wallet/index.ts +5 -0
  100. package/typechain-types/contracts/onboard/AccountOnboard.ts +135 -0
  101. package/typechain-types/contracts/onboard/index.ts +4 -0
  102. package/typechain-types/contracts/token/PrivateERC20/IPrivateERC20.ts +437 -0
  103. package/typechain-types/contracts/token/PrivateERC20/PrivateERC20.ts +505 -0
  104. package/typechain-types/contracts/token/PrivateERC20/index.ts +5 -0
  105. package/typechain-types/contracts/token/PrivateERC721/PrivateERC721.ts +409 -0
  106. package/typechain-types/contracts/token/PrivateERC721/extensions/PrivateERC721URIStorage.ts +501 -0
  107. package/typechain-types/contracts/token/PrivateERC721/extensions/index.ts +4 -0
  108. package/typechain-types/contracts/token/PrivateERC721/index.ts +6 -0
  109. package/typechain-types/contracts/token/index.ts +7 -0
  110. package/typechain-types/contracts/utils/index.ts +5 -0
  111. package/typechain-types/contracts/utils/mpc/MpcInterface.sol/ExtendedOperations.ts +698 -0
  112. package/typechain-types/contracts/utils/mpc/MpcInterface.sol/index.ts +4 -0
  113. package/typechain-types/contracts/utils/mpc/index.ts +5 -0
  114. package/typechain-types/factories/@openzeppelin/contracts/index.ts +6 -0
  115. package/typechain-types/factories/@openzeppelin/contracts/interfaces/IERC4906__factory.ts +339 -0
  116. package/typechain-types/factories/@openzeppelin/contracts/interfaces/draft-IERC6093.sol/IERC1155Errors__factory.ts +127 -0
  117. package/typechain-types/factories/@openzeppelin/contracts/interfaces/draft-IERC6093.sol/IERC20Errors__factory.ts +111 -0
  118. package/typechain-types/factories/@openzeppelin/contracts/interfaces/draft-IERC6093.sol/IERC721Errors__factory.ts +128 -0
  119. package/typechain-types/factories/@openzeppelin/contracts/interfaces/draft-IERC6093.sol/index.ts +6 -0
  120. package/typechain-types/factories/@openzeppelin/contracts/interfaces/index.ts +5 -0
  121. package/typechain-types/factories/@openzeppelin/contracts/token/ERC721/IERC721Receiver__factory.ts +59 -0
  122. package/typechain-types/factories/@openzeppelin/contracts/token/ERC721/IERC721__factory.ts +307 -0
  123. package/typechain-types/factories/@openzeppelin/contracts/token/ERC721/index.ts +5 -0
  124. package/typechain-types/factories/@openzeppelin/contracts/token/index.ts +4 -0
  125. package/typechain-types/factories/@openzeppelin/contracts/utils/index.ts +4 -0
  126. package/typechain-types/factories/@openzeppelin/contracts/utils/introspection/ERC165__factory.ts +41 -0
  127. package/typechain-types/factories/@openzeppelin/contracts/utils/introspection/IERC165__factory.ts +41 -0
  128. package/typechain-types/factories/@openzeppelin/contracts/utils/introspection/index.ts +5 -0
  129. package/typechain-types/factories/@openzeppelin/index.ts +4 -0
  130. package/typechain-types/factories/contracts/access/DataPrivacyFramework/DataPrivacyFramework__factory.ts +621 -0
  131. package/typechain-types/factories/contracts/access/DataPrivacyFramework/extensions/DataPrivacyFrameworkMpc__factory.ts +621 -0
  132. package/typechain-types/factories/contracts/access/DataPrivacyFramework/extensions/index.ts +4 -0
  133. package/typechain-types/factories/contracts/access/DataPrivacyFramework/index.ts +5 -0
  134. package/typechain-types/factories/contracts/access/index.ts +4 -0
  135. package/typechain-types/factories/contracts/index.ts +8 -0
  136. package/typechain-types/factories/contracts/mocks/access/DataPrivacyFramework/DataPrivacyFrameworkMock__factory.ts +670 -0
  137. package/typechain-types/factories/contracts/mocks/access/DataPrivacyFramework/index.ts +4 -0
  138. package/typechain-types/factories/contracts/mocks/access/index.ts +4 -0
  139. package/typechain-types/factories/contracts/mocks/index.ts +7 -0
  140. package/typechain-types/factories/contracts/mocks/token/PrivateERC20/PrivateERC20Mock__factory.ts +615 -0
  141. package/typechain-types/factories/contracts/mocks/token/PrivateERC20/index.ts +4 -0
  142. package/typechain-types/factories/contracts/mocks/token/PrivateERC721/PrivateERC721URIStorageMock__factory.ts +630 -0
  143. package/typechain-types/factories/contracts/mocks/token/PrivateERC721/index.ts +4 -0
  144. package/typechain-types/factories/contracts/mocks/token/index.ts +5 -0
  145. package/typechain-types/factories/contracts/mocks/utils/index.ts +4 -0
  146. package/typechain-types/factories/contracts/mocks/utils/mpc/ArithmeticTestsContract__factory.ts +374 -0
  147. package/typechain-types/factories/contracts/mocks/utils/mpc/BitwiseTestsContract__factory.ts +361 -0
  148. package/typechain-types/factories/contracts/mocks/utils/mpc/Comparison1Tests.Contract.sol/Comparison1TestsContract__factory.ts +361 -0
  149. package/typechain-types/factories/contracts/mocks/utils/mpc/Comparison1Tests.Contract.sol/index.ts +4 -0
  150. package/typechain-types/factories/contracts/mocks/utils/mpc/Comparison2TestsContract__factory.ts +361 -0
  151. package/typechain-types/factories/contracts/mocks/utils/mpc/MinMaxTestsContract__factory.ts +337 -0
  152. package/typechain-types/factories/contracts/mocks/utils/mpc/Miscellaneous1TestsContract__factory.ts +236 -0
  153. package/typechain-types/factories/contracts/mocks/utils/mpc/Miscellaneous2TestsContract__factory.ts +432 -0
  154. package/typechain-types/factories/contracts/mocks/utils/mpc/OffboardToUserKeyTestsContract.sol/OffboardToUserKeyTestContract__factory.ts +245 -0
  155. package/typechain-types/factories/contracts/mocks/utils/mpc/OffboardToUserKeyTestsContract.sol/index.ts +4 -0
  156. package/typechain-types/factories/contracts/mocks/utils/mpc/ShiftTestsContract__factory.ts +374 -0
  157. package/typechain-types/factories/contracts/mocks/utils/mpc/StringTestsContract__factory.ts +264 -0
  158. package/typechain-types/factories/contracts/mocks/utils/mpc/TransferScalarTestsContract__factory.ts +360 -0
  159. package/typechain-types/factories/contracts/mocks/utils/mpc/TransferTestsContract__factory.ts +441 -0
  160. package/typechain-types/factories/contracts/mocks/utils/mpc/index.ts +15 -0
  161. package/typechain-types/factories/contracts/mocks/wallet/PrivateERC20Wallet/PrivateERC20WalletMock__factory.ts +194 -0
  162. package/typechain-types/factories/contracts/mocks/wallet/PrivateERC20Wallet/index.ts +4 -0
  163. package/typechain-types/factories/contracts/mocks/wallet/index.ts +4 -0
  164. package/typechain-types/factories/contracts/onboard/AccountOnboard__factory.ts +104 -0
  165. package/typechain-types/factories/contracts/onboard/index.ts +4 -0
  166. package/typechain-types/factories/contracts/token/PrivateERC20/IPrivateERC20__factory.ts +406 -0
  167. package/typechain-types/factories/contracts/token/PrivateERC20/PrivateERC20__factory.ts +532 -0
  168. package/typechain-types/factories/contracts/token/PrivateERC20/index.ts +5 -0
  169. package/typechain-types/factories/contracts/token/PrivateERC721/PrivateERC721__factory.ts +439 -0
  170. package/typechain-types/factories/contracts/token/PrivateERC721/extensions/PrivateERC721URIStorage__factory.ts +512 -0
  171. package/typechain-types/factories/contracts/token/PrivateERC721/extensions/index.ts +4 -0
  172. package/typechain-types/factories/contracts/token/PrivateERC721/index.ts +5 -0
  173. package/typechain-types/factories/contracts/token/index.ts +5 -0
  174. package/typechain-types/factories/contracts/utils/index.ts +4 -0
  175. package/typechain-types/factories/contracts/utils/mpc/MpcInterface.sol/ExtendedOperations__factory.ts +919 -0
  176. package/typechain-types/factories/contracts/utils/mpc/MpcInterface.sol/index.ts +4 -0
  177. package/typechain-types/factories/contracts/utils/mpc/index.ts +4 -0
  178. package/typechain-types/factories/index.ts +5 -0
  179. package/typechain-types/hardhat.d.ts +621 -0
  180. package/typechain-types/index.ts +72 -0
@@ -0,0 +1,45 @@
1
+ import hre from "hardhat"
2
+ import { expect } from "chai"
3
+
4
+ import { generateRSAKeyPair } from "@coti-io/coti-sdk-typescript"
5
+ import { setupAccounts } from "../utils/accounts"
6
+
7
+ const gasLimit = 12000000
8
+
9
+ async function deploy() {
10
+ const [owner, otherAccount] = await setupAccounts()
11
+
12
+ const factory = await hre.ethers.getContractFactory("AccountOnboard")
13
+ const contract = await factory.connect(owner).deploy({ gasLimit })
14
+ await contract.waitForDeployment()
15
+
16
+ return { contract, contractAddress: await contract.getAddress(), owner, otherAccount }
17
+ }
18
+
19
+ describe("Account Onboard", function () {
20
+ let deployment: Awaited<ReturnType<typeof deploy>>
21
+
22
+ before(async function () {
23
+ deployment = await deploy()
24
+ })
25
+
26
+ it('Should successfully onboard the account', async function () {
27
+ const { owner } = deployment
28
+
29
+ await owner.generateOrRecoverAes()
30
+
31
+ expect(owner.getUserOnboardInfo()?.aesKey).to.not.equal('')
32
+ })
33
+
34
+ it('Should revert when the signature is empty', async function () {
35
+ const { owner, contract } = deployment
36
+
37
+ const { publicKey } = generateRSAKeyPair()
38
+
39
+ const tx = await contract
40
+ .connect(owner)
41
+ .onboardAccount(publicKey, '0x')
42
+
43
+ expect(tx).to.be.reverted
44
+ })
45
+ })
@@ -0,0 +1,546 @@
1
+ import hre from "hardhat"
2
+ import { expect } from "chai"
3
+
4
+ import { setupAccounts } from "../../utils/accounts"
5
+ import { PrivateERC20Mock, PrivateERC20WalletMock } from "../../../typechain-types"
6
+ import { itUint, Wallet, ZeroAddress } from "@coti-io/coti-ethers"
7
+
8
+ const GAS_LIMIT = 12000000
9
+
10
+ async function deploy() {
11
+ const [owner, otherAccount] = await setupAccounts()
12
+
13
+ const tokenContract = await hre.ethers.getContractFactory("PrivateERC20Mock")
14
+
15
+ const token = await tokenContract
16
+ .connect(owner)
17
+ .deploy({ gasLimit: GAS_LIMIT })
18
+
19
+ const contract = await token.waitForDeployment()
20
+
21
+ return {
22
+ contract,
23
+ contractAddress: await contract.getAddress(),
24
+ owner,
25
+ otherAccount
26
+ }
27
+ }
28
+
29
+ describe("Private ERC20", function () {
30
+ let contract: PrivateERC20Mock
31
+ let contractAddress: string
32
+ let owner: Wallet
33
+ let otherAccount: Wallet
34
+
35
+ before(async function () {
36
+ const deployment = await deploy()
37
+
38
+ contract = deployment.contract
39
+ contractAddress = deployment.contractAddress
40
+ owner = deployment.owner
41
+ otherAccount = deployment.otherAccount
42
+ })
43
+
44
+ describe("deploy", function () {
45
+ it('has a name', async function () {
46
+ await expect(await contract.name()).to.equal("PrivateERC20Mock");
47
+ })
48
+
49
+ it('has a symbol', async function () {
50
+ await expect(await contract.symbol()).to.equal("PE20M");
51
+ })
52
+
53
+ it('has 2 decimals', async function () {
54
+ await expect(await contract.decimals()).to.equal(2n);
55
+ })
56
+ })
57
+
58
+ describe("mint", function () {
59
+ const value = 5000n
60
+
61
+ describe("successful mint", async function () {
62
+ before("minting", async function () {
63
+ this.tx = await contract
64
+ .connect(owner)
65
+ .mint(owner.address, value, { gasLimit: GAS_LIMIT })
66
+
67
+ await this.tx.wait()
68
+ })
69
+
70
+ it('does not increment totalSupply', async function () {
71
+ await expect(await contract.totalSupply()).to.equal(0n)
72
+ })
73
+
74
+ it('increments recipient balance', async function () {
75
+ const ctBalance = await contract["balanceOf(address)"](owner.address)
76
+
77
+ const balance = await owner.decryptValue(ctBalance)
78
+
79
+ await expect(balance).to.equal(value)
80
+ })
81
+
82
+ it('emits Transfer event', async function () {
83
+ await expect(this.tx).to.emit(contract, "Transfer")
84
+ })
85
+ })
86
+
87
+ describe('failed mint', async function () {
88
+ it('rejects minting to the zero address', async function () {
89
+ await expect(
90
+ contract
91
+ .connect(owner)
92
+ .mint(ZeroAddress, value)
93
+ )
94
+ .to.be.revertedWithCustomError(contract, "ERC20InvalidReceiver")
95
+ .withArgs(ZeroAddress)
96
+ })
97
+
98
+ // it('rejects overflow', async function () {
99
+ // const tx = await contract
100
+ // .connect(owner.wallet)
101
+ // .mint(owner.wallet.address, (BigInt(2) ** BigInt(64)) - BigInt(1), { gasLimit: GAS_LIMIT })
102
+
103
+ // await tx.wait()
104
+
105
+ // await expect(tx).to.be.reverted
106
+ // })
107
+ })
108
+ })
109
+
110
+ describe("burn", function () {
111
+ const value = 5000n
112
+
113
+ describe('failed burn', async function () {
114
+ it('rejects burning from the zero address', async function () {
115
+ await expect(
116
+ contract
117
+ .connect(owner)
118
+ .burn(ZeroAddress, value)
119
+ )
120
+ .to.be.revertedWithCustomError(contract, "ERC20InvalidSender")
121
+ .withArgs(ZeroAddress)
122
+ })
123
+
124
+ it('does not update balance when burning more than balance', async function () {
125
+ const tx = await contract
126
+ .connect(owner)
127
+ .burn(owner.address, value + 1n, { gasLimit: GAS_LIMIT })
128
+
129
+ await tx.wait()
130
+
131
+ const ctBalance = await contract["balanceOf(address)"](owner.address)
132
+
133
+ const balance = await owner.decryptValue(ctBalance)
134
+
135
+ await expect(balance).to.equal(value)
136
+ })
137
+ })
138
+
139
+ describe('successful burn', async function () {
140
+ before("burning", async function () {
141
+ this.tx = await contract
142
+ .connect(owner)
143
+ .burn(owner.address, value, { gasLimit: GAS_LIMIT })
144
+
145
+ await this.tx.wait()
146
+ })
147
+
148
+ it('decrements the senders balance', async function () {
149
+ const ctBalance = await contract["balanceOf(address)"](owner.address)
150
+
151
+ const balance = await owner.decryptValue(ctBalance)
152
+
153
+ await expect(balance).to.equal(0n)
154
+ })
155
+
156
+ it('emits Transfer event', async function () {
157
+ await expect(this.tx).to.emit(contract, "Transfer")
158
+ })
159
+ })
160
+ })
161
+
162
+ describe("transfer", function () {
163
+ const value = 10000n
164
+
165
+ before("minting", async function () {
166
+ this.tx = await contract
167
+ .connect(owner)
168
+ .mint(owner.address, value, { gasLimit: GAS_LIMIT })
169
+
170
+ await this.tx.wait()
171
+ })
172
+
173
+ describe("failed transfer", async function () {
174
+ it('rejects transferring to the zero address', async function () {
175
+ const itValue = await owner.encryptValue(value, contractAddress, contract["transfer(address,(uint256,bytes))"].fragment.selector) as itUint
176
+
177
+ await expect(
178
+ contract
179
+ .connect(owner)
180
+ ["transfer(address,(uint256,bytes))"]
181
+ (ZeroAddress, itValue)
182
+ )
183
+ .to.be.revertedWithCustomError(contract, "ERC20InvalidReceiver")
184
+ .withArgs(ZeroAddress)
185
+ })
186
+
187
+ it('does not transfer tokens when amount exceeds balance', async function () {
188
+ const itValue = await owner.encryptValue(value + 1n, contractAddress, contract["transfer(address,(uint256,bytes))"].fragment.selector) as itUint
189
+
190
+ const tx = await contract
191
+ .connect(owner)
192
+ ["transfer(address,(uint256,bytes))"]
193
+ (otherAccount.address, itValue, { gasLimit: GAS_LIMIT })
194
+
195
+ await tx.wait()
196
+
197
+ let ctBalance = await contract["balanceOf(address)"](owner.address)
198
+
199
+ let balance = await owner.decryptValue(ctBalance)
200
+
201
+ await expect(balance).to.equal(value)
202
+
203
+ ctBalance = await contract["balanceOf(address)"](otherAccount.address)
204
+
205
+ balance = await otherAccount.decryptValue(ctBalance)
206
+
207
+ await expect(balance).to.equal(0n)
208
+ })
209
+ })
210
+
211
+ describe("successful transfer", async function () {
212
+ before("transferring", async function () {
213
+ const itValue = await owner.encryptValue(value / 2n, contractAddress, contract["transfer(address,(uint256,bytes))"].fragment.selector) as itUint
214
+
215
+ const tx = await contract
216
+ .connect(owner)
217
+ ["transfer(address,(uint256,bytes))"]
218
+ (otherAccount.address, itValue, { gasLimit: GAS_LIMIT })
219
+
220
+ await tx.wait()
221
+ })
222
+
223
+ it('decrements the senders balance', async function () {
224
+ const ctBalance = await contract["balanceOf(address)"](owner.address)
225
+
226
+ const balance = await owner.decryptValue(ctBalance)
227
+
228
+ await expect(balance).to.equal(value / 2n)
229
+ })
230
+
231
+ it('increments the receivers balance', async function () {
232
+ const ctBalance = await contract["balanceOf(address)"](otherAccount.address)
233
+
234
+ const balance = await otherAccount.decryptValue(ctBalance)
235
+
236
+ await expect(balance).to.equal(value / 2n)
237
+ })
238
+ })
239
+ })
240
+
241
+ describe("approve", function () {
242
+ const value = 5000n
243
+
244
+ describe("failed approval", async function () {
245
+ it('rejects when approving the zero address', async function () {
246
+ const itValue = await owner.encryptValue(value, contractAddress, contract["transfer(address,(uint256,bytes))"].fragment.selector) as itUint
247
+
248
+ await expect(
249
+ contract
250
+ .connect(owner)
251
+ ["approve(address,(uint256,bytes))"]
252
+ (ZeroAddress, itValue)
253
+ )
254
+ .to.be.revertedWithCustomError(contract, "ERC20InvalidSpender")
255
+ .withArgs(ZeroAddress)
256
+ })
257
+ })
258
+
259
+ describe("successful approval", async function () {
260
+ before('approving', async function () {
261
+ const itValue = await owner.encryptValue(value, contractAddress, contract["approve(address,(uint256,bytes))"].fragment.selector) as itUint
262
+
263
+ const tx = await contract
264
+ .connect(owner)
265
+ ["approve(address,(uint256,bytes))"]
266
+ (otherAccount.address, itValue, { gasLimit: GAS_LIMIT })
267
+
268
+ await tx.wait()
269
+ })
270
+
271
+ it('increment the allowance encrypted with the owners key', async function () {
272
+ const ctAllowance = await contract
273
+ ["allowance(address,address)"]
274
+ (owner.address, otherAccount.address)
275
+
276
+ const allowance = await owner.decryptValue(ctAllowance[1])
277
+
278
+ await expect(allowance).to.equal(value)
279
+ })
280
+
281
+ it('increment the allowance encrypted with the spenders key', async function () {
282
+ const ctAllowance = await contract
283
+ ["allowance(address,address)"]
284
+ (owner.address, otherAccount.address)
285
+
286
+ const allowance = await otherAccount.decryptValue(ctAllowance[2])
287
+
288
+ await expect(allowance).to.equal(value)
289
+ })
290
+ })
291
+ })
292
+
293
+ describe('transferFrom', function () {
294
+ const value = 3000n
295
+
296
+ describe('failed transferFrom', async function () {
297
+ it('rejects transferring to the zero address', async function () {
298
+ const itValue = await otherAccount.encryptValue(value, contractAddress, contract["transferFrom(address,address,(uint256,bytes))"].fragment.selector)as itUint
299
+
300
+ await expect(
301
+ contract
302
+ .connect(otherAccount)
303
+ ["transferFrom(address,address,(uint256,bytes))"]
304
+ (owner.address, ZeroAddress, itValue)
305
+ )
306
+ .to.be.revertedWithCustomError(contract, "ERC20InvalidReceiver")
307
+ .withArgs(ZeroAddress)
308
+ })
309
+
310
+ describe("transferring more than the owners balance", async function () {
311
+ before("transferring", async function () {
312
+ const itValue = await otherAccount.encryptValue(2n * value, contractAddress, contract["transferFrom(address,address,(uint256,bytes))"].fragment.selector)as itUint
313
+
314
+ const tx = await contract
315
+ .connect(otherAccount)
316
+ ["transferFrom(address,address,(uint256,bytes))"]
317
+ (owner.address, "0x0000000000000000000000000000000000000001", itValue)
318
+
319
+ await tx.wait()
320
+ })
321
+
322
+ it("does not decrement the owners balance", async function () {
323
+ const ctBalance = await contract["balanceOf(address)"](owner.address)
324
+
325
+ const balance = await owner.decryptValue(ctBalance)
326
+
327
+ await expect(balance).to.equal(5000n)
328
+ })
329
+
330
+ it("does not decrement the spenders allowance", async function () {
331
+ const ctAllowance = await contract["allowance(address,address)"](owner.address, otherAccount.address)
332
+
333
+ const allowance = await owner.decryptValue(ctAllowance[1])
334
+
335
+ await expect(allowance).to.equal(5000n)
336
+ })
337
+ })
338
+ })
339
+
340
+ describe('successful transferFrom', async function () {
341
+ before('transferring', async function () {
342
+ const itValue = await otherAccount.encryptValue(value, contractAddress, contract["transferFrom(address,address,(uint256,bytes))"].fragment.selector)as itUint
343
+
344
+ const tx = await contract
345
+ .connect(otherAccount)
346
+ ["transferFrom(address,address,(uint256,bytes))"]
347
+ (owner.address, otherAccount.address, itValue)
348
+
349
+ await tx.wait()
350
+ })
351
+
352
+ it('decrement the owners balance', async function () {
353
+ const ctBalance = await contract["balanceOf(address)"](owner.address)
354
+
355
+ const balance = await owner.decryptValue(ctBalance)
356
+
357
+ await expect(balance).to.equal(2000n)
358
+ })
359
+
360
+ it('increment the recipients balance', async function () {
361
+ const ctBalance = await contract["balanceOf(address)"](otherAccount.address)
362
+
363
+ const balance = await otherAccount.decryptValue(ctBalance)
364
+
365
+ await expect(balance).to.equal(8000n)
366
+ })
367
+
368
+ it('decrement the spenders allowance', async function () {
369
+ const ctAllowance = await contract["allowance(address,address)"](owner.address, otherAccount.address)
370
+
371
+ const allowance = await otherAccount.decryptValue(ctAllowance[2])
372
+
373
+ await expect(allowance).to.equal(2000n)
374
+ })
375
+ })
376
+ })
377
+
378
+ describe("contract-to-contract interactions", function () {
379
+ const value = 10000n
380
+ let walletContract: PrivateERC20WalletMock
381
+ let walletContractAddress: string
382
+
383
+ before("deploying and funding wallet contract", async function () {
384
+ const walletContractFactory = await hre.ethers.getContractFactory("PrivateERC20WalletMock")
385
+
386
+ walletContract = await walletContractFactory
387
+ .connect(owner)
388
+ .deploy({ gasLimit: GAS_LIMIT })
389
+
390
+ walletContract = await walletContract.waitForDeployment()
391
+
392
+ walletContractAddress = await walletContract.getAddress()
393
+
394
+ this.tx = await contract
395
+ .connect(owner)
396
+ .mint(walletContractAddress, value, { gasLimit: GAS_LIMIT })
397
+
398
+ await this.tx.wait()
399
+ })
400
+
401
+ describe("setAccountEncryptionAddress", async function () {
402
+ before("setting account encryption address", async function () {
403
+ const tx = await walletContract
404
+ .connect(otherAccount)
405
+ .setAccountEncryptionAddress(contractAddress, otherAccount.address, { gasLimit: GAS_LIMIT })
406
+
407
+ await tx.wait()
408
+ })
409
+
410
+ it("update accountEncryptionAddress mapping", async function () {
411
+ const accountEncryptionAddress = await contract.accountEncryptionAddress(walletContractAddress)
412
+
413
+ await expect(accountEncryptionAddress).to.equal(otherAccount.address)
414
+ })
415
+
416
+ it("reencrypt balance using the new account encryption address", async function () {
417
+ const ctBalance = await contract["balanceOf(address)"](walletContractAddress)
418
+
419
+ const balance = await otherAccount.decryptValue(ctBalance)
420
+
421
+ await expect(balance).to.equal(value)
422
+ })
423
+ })
424
+
425
+ describe("transfer", async function () {
426
+ before("transferring", async function () {
427
+ const tx = await walletContract
428
+ .connect(otherAccount)
429
+ .transfer(contractAddress, otherAccount.address, value / 2n, { gasLimit: GAS_LIMIT })
430
+
431
+ await tx.wait()
432
+ })
433
+
434
+ it('decrement the senders balance', async function () {
435
+ const ctBalance = await contract["balanceOf(address)"](walletContractAddress)
436
+
437
+ const balance = await otherAccount.decryptValue(ctBalance)
438
+
439
+ await expect(balance).to.equal(value / 2n)
440
+ })
441
+
442
+ it('increment the receivers balance', async function () {
443
+ const ctBalance = await contract["balanceOf(address)"](otherAccount.address)
444
+
445
+ const balance = await otherAccount.decryptValue(ctBalance)
446
+
447
+ await expect(balance).to.equal(13000n)
448
+ })
449
+ })
450
+
451
+ describe("approve", async function () {
452
+ before("approving", async function () {
453
+ const tx = await walletContract
454
+ .connect(otherAccount)
455
+ .approve(contractAddress, owner.address, value / 2n, { gasLimit: GAS_LIMIT })
456
+
457
+ await tx.wait()
458
+ })
459
+
460
+ it("increment the spenders allowance", async function () {
461
+ const ctAllowance = await contract["allowance(address,address)"](walletContractAddress, owner.address)
462
+
463
+ const allowance = await otherAccount.decryptValue(ctAllowance[1])
464
+
465
+ await expect(allowance).to.equal(value / 2n)
466
+ })
467
+ })
468
+
469
+ describe("transferFrom", async function () {
470
+ const value = 5000n
471
+
472
+ before("transferring", async function () {
473
+ const itValue = await otherAccount.encryptValue(value, contractAddress, contract["approve(address,(uint256,bytes))"].fragment.selector) as itUint
474
+
475
+ let tx = await contract
476
+ .connect(otherAccount)
477
+ ["approve(address,(uint256,bytes))"]
478
+ (walletContractAddress, itValue)
479
+
480
+ await tx.wait()
481
+
482
+ tx = await walletContract
483
+ .connect(otherAccount)
484
+ .transferFrom(contractAddress, otherAccount.address, owner.address, value)
485
+
486
+ await tx.wait()
487
+ })
488
+
489
+ it('decrement the owners balance', async function () {
490
+ const itBalance = await contract["balanceOf(address)"](otherAccount.address)
491
+
492
+ const balance = await otherAccount.decryptValue(itBalance)
493
+
494
+ await expect(balance).to.equal(8000n)
495
+ })
496
+
497
+ it('increment the recipients balance', async function () {
498
+ const itBalance = await contract["balanceOf(address)"](owner.address)
499
+
500
+ const balance = await owner.decryptValue(itBalance)
501
+
502
+ await expect(balance).to.equal(7000n)
503
+ })
504
+ })
505
+ })
506
+
507
+ describe("maximum allowance", function () {
508
+ const value = (2n ** 64n) - 1n
509
+
510
+ before("transferring", async function () {
511
+ let itValue = await owner.encryptValue(value, contractAddress, contract["approve(address,(uint256,bytes))"].fragment.selector) as itUint
512
+
513
+ let tx = await contract
514
+ .connect(owner)
515
+ ["approve(address,(uint256,bytes))"]
516
+ (otherAccount.address, itValue)
517
+
518
+ await tx.wait()
519
+
520
+ itValue = await otherAccount.encryptValue(7000n, contractAddress, contract["transferFrom(address,address,(uint256,bytes))"].fragment.selector) as itUint
521
+
522
+ tx = await contract
523
+ .connect(otherAccount)
524
+ ["transferFrom(address,address,(uint256,bytes))"]
525
+ (owner.address, "0x0000000000000000000000000000000000000001", itValue)
526
+
527
+ await tx.wait()
528
+ })
529
+
530
+ it("decrement the owners balance", async function () {
531
+ const ctBalance = await contract["balanceOf(address)"](owner.address)
532
+
533
+ const balance = await owner.decryptValue(ctBalance)
534
+
535
+ await expect(balance).to.equal(0n)
536
+ })
537
+
538
+ it("does not decrement the spenders allowance", async function () {
539
+ const ctAllowance = await contract["allowance(address,address)"](owner.address, otherAccount.address)
540
+
541
+ const allowance = await owner.decryptValue(ctAllowance[1])
542
+
543
+ await expect(allowance).to.equal(value)
544
+ })
545
+ })
546
+ })