โ˜‘
Whitelist smart contract

๐ŸŒŠ Intro

This repository provides an implementation of Whitelist interface proposed in the TZIP-15 written in SmartPy: Python library for constructing Tezos SC and compiled to Michelson code. The contract is migrated from the Lorentz whitelisting contract.

๐Ÿ’ก Why a whitelist contract?

The purpose of the Whitelist contract is to validate transfers so the token's contract holder can control which users can perform such operations. The Whitelist contract contains a list of users and entities that have satisfied the euroTz KYC/AML compliance procedures and thus are eligible to hold euroTz Tokens.

๐Ÿ”” Specifications

UserID

As userID, we use the user's public key hash, e.g. a tz1 address.

Storage

โ€ข whitelists:
1
big_map (
2
key = whitelistID: Nat,
3
value = {
4
unrestricted: Bool,
5
allowedWhitelists: set(whitelistID)
6
})
Copied!
โ€ข users:
1
big_map (
2
key = userID: address,
3
value = whitelistID : Nat
4
)
Copied!
โ€ข admin: address
โ€ข issuer: address

๐Ÿš€ We use the interface as an on-chain wrapper:

  1. 1.
    The whitelist contract is deployed separately from our euroTz contract.
  2. 2.
    The assertion entrypoints are called from euroTz contract, without requiring callbacks since they call FAILWITH when they fail.

How does our wrapper whitelist SC work?

๐ŸŽฅ Main scenarios:
  1. 1.
    Issuer may transfer to bob ONLY if bob's is an asserted receiver, in other words, bob must be added to the users big_map and his whitelistID must be set and unrestricted in the whitelists big_map.
  2. 2.
    Alice may transfer to Bob ONLY if bob and Alice are asserted users AND Bob's whitelistID is in Alice's allowedWhitelists.

โฌ‡๏ธ Get the Project:

  1. 1.
    Clone the project & cd to the directory;
  2. 2.
    Install the packages with yarn install.

๐Ÿ” EntryPoints (SC methods):

EntryPoint
Params (type / desc.)
Permission
Type
addUser
address (address) / whitelistID (option(nat))
Admin
Management
setWhitelistOutbound
whitelistID (nat) / option(allowed_whitelists (set) / unrestricted (bool))
Admin
Management
setAdmin
address (address)
Admin
Management
setIssuer
address (address)
Admin
Management
getAdmin
address (address / KT1 view contractAddress)
Any
Informative
getIssuer
address (address / KT1 view contractAddress)
Any
Informative
getWhitelist
address (address / KT1 view contractAddress) / whitelistID (nat)
Any
Informative
getUser
address (address / KT1 view contractAddress) / address (address / userAddress)
Any
Informative
assertReceiver
address (address)
Any
Assertion
assertReceivers
set (set(address))
Any
Assertion
assertTransfer
from_ (address) / to_ (address)
Any
Assertion
assertTransfers
set (set({from_: address, to_: address}))
Any
Assertion
Visit TZIP-15 to get a more developed description of the whitelist contract entrypoints.

๐Ÿ‘€ Tests Cases

The smartContract tests are written in smartPy and in JS (with Taquito, Mocha and Chai)

To launch tests, you have to:
  1. 1.
    Originate the whitelist contract with:
    1
    yarn originate-whitelist
    Copied!
  2. 2.
    Paste the address of the originated whitelist SC in the conf file under /conf as following:
1
whitelistContractAddress: KT1-whitelist-address
Copied!
  1. 1.
    Originate the euroTz contract with:
    1
    yarn originate-euroTz
    Copied!
  2. 2.
    Paste the address of the originated euroTz SC in the same conf file as follows:
1
euroTzContractAddress: KT1-euroTz-address
Copied!
๐ŸŽ‰ You're ready to launch tests now...
The following tests use as
โ€ข whitelist contract address: KT1PFj9vshZKrHYLCswxUXKtY89SDYkXThDCโ€‹
โ€ข euroTz contract address: KT1WcxYBrh9WwRo1vkbSJxAqr6ZVAUqDEiFgโ€‹

Management entrypoints

1
yarn test-setAdmin # Test setAdmin entryPoint
Copied!

Test Output:

1
Whitelist Smart Contract: SetAdmin Entrypoint tests
2
initialAdmin: tz1SVqTz7entj982jDSKcTQNgT7f2cg7C8dk
3
------------------------------------------------------------
4
MESSAGE STATEMENT: only admin may update
5
โœ“ Update admin as non-admin / Should fail (4409ms)
6
โ€‹
7
OpHash : oo5ofnco8QxcMtjm4Xo3Px93knyssQBLhL2bCTeKHUSbpWW7fX3
8
Admin from storage: tz1XrCvviH8CqoHMSKpKuznLArEa1yR9U7ep
9
โœ“ Update admin as admin / Should succeed (27855ms)
10
โ€‹
11
OpHash : oom91CsjUhFs9ThaSP2S2NgtYK4UT5HnceEHwr27i6bn3kvxeMX
12
Admin from storage: tz1SVqTz7entj982jDSKcTQNgT7f2cg7C8dk
13
โœ“ Reset old admin as admin / Should succeed (46817ms)
14
3 passing (1m)
15
โœจ Done in 82.75s.
Copied!
1
yarn test-setIssuer # Test setIssuer entryPoint
Copied!

Test Output:

1
Whitelist Smart Contract: SetIssuer Entrypoint tests
2
initialIssuer: tz1SVqTz7entj982jDSKcTQNgT7f2cg7C8dk
3
------------------------------------------------------------
4
MESSAGE STATEMENT: only admin may update
5
โœ“ Update issuer as non-admin / Should fail (5824ms)
6
โ€‹
7
OpHash : ooERfBcJPaByiUdrhvidyHZEkZ2ki68LbVMz2mbPWrSJMfDwvzU
8
Issuer from storage: tz1XrCvviH8CqoHMSKpKuznLArEa1yR9U7ep
9
โœ“ Update issuer as admin / Should succeed (38408ms)
10
โ€‹
11
OpHash : oooiEXQCbmtAFYZpqvDKbJzeyXvYGYqWatTfGxCYdxxZona1gZz
12
Issuer from storage: tz1SVqTz7entj982jDSKcTQNgT7f2cg7C8dk
13
โœ“ Reset old issuer as admin / Should succeed (52151ms)
14
3 passing (2m)
15
โœจ Done in 101.61s.
Copied!
1
yarn test-addUser # Test addUser entryPoint
Copied!

Test Output:

1
Whitelist Smart Contract: AddUser Entrypoint tests
2
โ€‹
3
MESSAGE STATEMENT: only admin may update
4
โœ“ Add user as non-admin / Should fail (2832ms)
5
โ€‹
6
MESSAGE STATEMENT: issuer is not a user
7
โœ“ Add Issuer as a standard user as admin / Should fail (3734ms)
8
โ€‹
9
OpHash : opVy3boRogtgpU2fz4wjgMwNEYxogymqGRqsUFzPdc7WChEzviq
10
โœ“ Add User with None as admin / Should succeed (16585ms)
11
โ€‹
12
OpHash : ooZvAefYT4Q7bqi8K2AJQY1QWi3neMZVxEVqXGeAzsN52pHVKtz
13
userWhitelistID: 10
14
โœ“ Add user with Some as admin / Should succeed (116256ms)
15
โ€‹
16
4 passing (2m)
17
โœจ Done in 142.39s.
Copied!
1
yarn test-setWhitelistOutbound # Test setWhitelistOutbound entryPoint
Copied!

Test Output:

1
Whitelist Smart Contract: SetWhitelistOutbound Entrypoint tests
2
โ€‹
3
MESSAGE STATEMENT: only admin may update
4
โœ“ Set Whitelist Outbound as non-admin / Should fail (3120ms)
5
โ€‹
6
OpHash: ooczsae6WA6xDTGYVhUuk4SS1WC55CFeqcBtPkdhGkVQjfqnrR6
7
whitelistDetails: { allowed_whitelists: [], unrestricted: true }
8
โœ“ Set Whitelist Outbound as admin with Some / Should succeed (177318ms)
9
โ€‹
10
OpHash: onjtUV2b4KWD67hNawDmKkndh1Hwa4JWDYmg83iXCrhn4ZDrGMB
11
whitelistDetails: {allowed_whitelists: [ 555 ], unrestricted: true}
12
โœ“ Update existing outbound whitelists as admin / Should succeed (36756ms)
13
โ€‹
14
OpHash: oooTfhZYiiMQUjPpsTMXXdH6KUUQu6a5a4KDqV2k9BPaha798o6
15
โœ“ Remove outbound whitelist as admin / Should succeed (25887ms)
16
โ€‹
17
4 passing (4m)
18
โœจ Done in 247.35s.
Copied!

Informative entrypoints

1
yarn test-viewEntryPoints # Test getters entryPoints
Copied!

Test Output:

1
Whitelist Smart Contract: Informative Entrypoints tests
2
โ€‹
3
viewOpHash : ooZZfDBazuXBiUsE2Vc3NAfg6f9eWPFdA6RooXqDtguajvpFGiY
4
Admin from view contract storage: tz1SVqTz7entj982jDSKcTQNgT7f2cg7C8dk
5
โœ“ Get Admin Address / Should succeed (84910ms)
6
โ€‹
7
viewOpHash : oofULds4jJv6DyWw6v2nnh3FCogfgZhNvPwPTyica45zZzQAvzD
8
Issuer from view contract storage: tz1SVqTz7entj982jDSKcTQNgT7f2cg7C8dk
9
โœ“ Get Issuer Address / Should succeed (16055ms)
10
โ€‹
11
viewOpHash : op2rGJ3L2oczuUnkfshRetWgAkGSj2Zr6nahuGyzbAHfSJ3wNpw
12
Whitelist details from view contract storage: { allowed_whitelists: [], unrestricted: true }
13
โœ“ Get WhitelistDetails / Should succeed (111324ms)
14
โ€‹
15
viewOpHash : onq4VEiZ6q3SVKp8p1k7fya7auSL2m8WNaaUiphGi6XdJ2hv1NP
16
whiteListID from view contract storage: 444
17
โœ“ Get User whitelist ID / Should succeed (75185ms)
18
โ€‹
19
MESSAGE STATEMENT: whitelist not found
20
โœ“ Get inexistent WhitelistDetails / Should fail (2839ms)
21
โ€‹
22
MESSAGE STATEMENT: user not found
23
โœ“ Get inexistent User / Should fail (4059ms)
24
โ€‹
25
6 passing (5m)
26
โœจ Done in 302.18s.
Copied!

Assertion entrypoints

โ€‹
โš 
In order to mint some euroTz tokens to the Issuer, you must launch the assertReceiver test before the assertTrasnfer one.
1
yarn test-assertReceiver # Test assertReceiver entryPoint
Copied!

Test Output:

1
Whitelist Smart Contract: AssertReceiver Entrypoint tests
2
โ€‹
3
opHash : onsWLrfWngr7PGLjYTJWUE5Fn1N2pGcd8uWPXQb1b2G9TCRqLKn
4
โœ“ Assert receiver Issuer - Admin mints 50 euroTz to the Issuer / Should succeed (66577ms)
5
โ€‹
6
MESSAGE STATEMENT: user not on a whitelist
7
โœ“ Assert receiver inexistent User - Admin tries to mint 40 euroTz to an inexistent user / Should fail (4432ms)
8
โ€‹
9
OpHash : op5bsabpVa8FNszZJWmXi5TpDyYjz3AViovU1J3dMafo3Vha6m7
10
โœ“ Admin adds Ouss in users big_map (26387ms)
11
โ€‹
12
MESSAGE STATEMENT: whitelist does not exist
13
โœ“ Assert receiver existing User, his associated whitelistID don t refer to an existing whitelist - Admin tries to mint 40 euroTz / Should fail (5517ms)
14
โ€‹
15
OpHash : oodR5jieVi7enfGoVkUZcJdVnep5fyya7DFGQ576rJZzbtSEoAs
16
โœ“ Admin sets Ouss s whitelist outbound initally restricted (26856ms)
17
โ€‹
18
MESSAGE STATEMENT: outbound restricted
19
โœ“ Assert receiver existing User, his associated whitelist is restricted - Admin tries to mint 40 euroTz to whitelisted restricted user (Ouss) / Should fail (2814ms)
20
โ€‹
21
OpHash : oneyu5hcCPQopgvuQ2KsV4AjJLrNjkh2iKCWi96tuB9VceChcJX
22
โœ“ Admin sets Ouss s whitelist outbound unrestricted (106327ms)
23
โ€‹
24
opHash : ooRxZ5HtiEfwtSrMpYgzJ6qWyt6qap87ThpRFP2mNpfjyughTH9
25
โœ“ Assert receiver existing User, the associated whitelistID refers to an existing whitelist and unrestricted - Admin mints 50 euroTz to Ouss: whitelisted unrestricted user / Should succeed (26285ms)
26
โ€‹
27
8 passing (4m)
28
โœจ Done in 270.13s.
Copied!
1
yarn test-assertReceivers # Test assertReceivers entryPoint
Copied!

Test Output:

1
Whitelist Smart Contract: AssertReceivers Entrypoint tests
2
โ€‹
3
MESSAGE STATEMENT: user not on a whitelist
4
โœ“ Assert receivers with one inexistent user / Should fail (3127ms)
5
โ€‹
6
OpHash : ooHWW4VusZTuiDREUuXefX7rLbAQw1PZe38Vz8qJXJDdMTTeCDc
7
โœ“ Admin adds Khaled in whitelst contract (75338ms)
8
โ€‹
9
MESSAGE STATEMENT: whitelist does not exist
10
โœ“ Assert receivers with one user s whitelistID don t refer to an existing whitelist / Should fail (3524ms)
11
โ€‹
12
OpHash: oo5W1bhrJmmSrv97mc5mS3Ee7Kqgbgu71vxJTYh1JW4jpM7QgZx
13
โœ“ Admin sets Khaled s whitelist outbound restricted (26590ms)
14
โ€‹
15
MESSAGE STATEMENT: outbound restricted
16
โœ“ Assert receivers with one user s whitelist restricted / Should fail (6387ms)
17
โ€‹
18
OpHash : opZcnwmQvBPiHReqad11vSB3iFZbto4i5aBsUAH1Ck8k23gxCoQ
19
โœ“ Admin sets Khaled s whitelist outbound unrestricted (55717ms)
20
โ€‹
21
OpHash: opCXZZmrC4esizqy5trQgTPv3gKv4yE7SHmXMpXRzfgvWcgufV9
22
โœ“ Assert receivers: all users are existing and unrestricted / Sould succeed (35641ms)
23
โ€‹
24
7 passing (5m)
25
โœจ Done in 324.29s.
Copied!
1
yarn test-assertTrasnfer # Test assertTrasnfer entryPoint
Copied!

Test Output:

1
Whitelist Smart Contract: AssertTransfer Entrypoint tests
2
โ€‹
3
MESSAGE STATEMENT: user not on a whitelist
4
โœ“ Assert Transfer from Issuer to an inexistent user - Issuer tries to transfer 9 euroTz to Fred / Should fail (3379ms)
5
โ€‹
6
OpHash : oozZLubPscjt5ed9YaQi61Mfq94xNLAYC6bruTy3u2zHvcZSDcR
7
โœ“ Admin adds Fred in whitelst contract (91502ms)
8
โ€‹
9
MESSAGE STATEMENT: whitelist does not exist
10
โœ“ Assert Transfer from Issuer to an existing user with whitelistID don t refer to an existing whitelist - Issuer tries to transfer 9 euroTz to Fred / Should fail (5575ms)
11
โ€‹
12
OpHash: ooykfX3jCuioSabk69PV9BpLdxT5BCT7sbJMZB2sRH4sAogk6sW
13
โœ“ Admin sets Fred s whitelist outbound initally restricted (18412ms)
14
โ€‹
15
MESSAGE STATEMENT: outbound restricted
16
โœ“ Assert Transfer from Issuer to existing, restricted user - Issuer tries to transfer 9 euroTz to Fred / Should fail (7536ms)
17
โ€‹
18
OpHash: opMY1NtPZC9tmJAP2PCZqXQ6jfzKL6S5XDVvJpu6sYNjPHf8qvD
19
โœ“ Admin sets Fred s whitelist outbound unrestricted (36973ms)
20
โ€‹
21
euroTzTrasnferOpHash: onxrnAwMs63ZvQKvG5T2GVhohfTuWdVcbKFLq9qQwzPgzTww5tS
22
โœ“ Assert Transfer from Issuer to an existing, unrestricted user - Issuer transfers 9 euroTz to Fred / Should succeed (27318ms)
23
โ€‹
24
MESSAGE STATEMENT: user not on a whitelist
25
โœ“ Assert Transfer from existing to an inexistent user - Fred tries to transfer 3 euroTz to Safwen / Should fail (4771ms)
26
โ€‹
27
OpHash : ooeXt7h7WrTsWNhFvwM4MJngD4pWb6eoCiLyDw3GmztBG1WkQU3
28
โœ“ Admin adds Safwen in whitelst contract (77621ms)
29
โ€‹
30
MESSAGE STATEMENT: whitelist does not exist
31
โœ“ Assert Transfer between: Two existing users with sender s whitelistID don t refer to an existing whitelist - Fred tries to transfer 3 euroTz to Safwen / Should fail (3318ms)
32
โ€‹
33
OpHash: op6oNdbhSAKixx795dQrogrDC9hzKYJissrJVBZbVeZ4Ldij8Kf
34
โœ“ Admin sets Safwen s whitelist outbound unrestricted (106412ms)
35
โ€‹
36
OpHash: oobQx7dVeYVtTBs9WSSiBBD4onMQPcHcXwCSwc1nJgDqL7a9hU6
37
โœ“ Admin sets Fred s whitelist outbound restricted (61054ms)
38
โ€‹
39
MESSAGE STATEMENT: outbound restricted
40
โœ“ Assert Transfer between: Two existing users while sender is restricted - Fred tries to transfer 3 euroTz to Safwen / Should fail (3590ms)
41
โ€‹
42
OpHash : ooYvVeAkfasz18E7F935WYeG1B5Ur9RgjHWhJr4ohqtAoxPtDHD
43
โœ“ Admin sets Fred s whitelist outbound unrestricted and contains Safwen (31729ms)
44
โ€‹
45
euroTzTrasnferOpHash : oorXEA6UpHcQhaFYp51sT11SYf6mpDMbvYDXKfwGawbUDEe5fKP
46
โœ“ Assert Transfer between: Two existing users, sender and receiver are unrestricted, receiver s whitelistID is in the sender s whitelist - Fred transfers 3 euroTz to Safwen / Should succeed (22084ms)
47
โ€‹
48
15 passing (8m)
49
โœจ Done in 507.14s.
Copied!
1
yarn test-assertTrasnfers # Test assertTrasnfers entryPoint
Copied!

Test Output:

1
Whitelist Smart Contract: AssertTrasnfers Operation Testing
2
โ€‹
3
โ€‹
4
MESSAGE STATEMENT: user not on a whitelist
5
โœ“ Assert list of transfers with one inexistent sender / Should fail (4333ms)
6
โ€‹
7
MESSAGE STATEMENT: user not on a whitelist
8
โœ“ Assert list of transfers with one inexistent receiver / Should fail (2927ms)
9
โ€‹
10
OpHash : opTmp7RmzQS3BypxzahgsjtzemypbLVXiepgsNGgXHqzJGLwecg
11
โœ“ Admin adds Daly to users big_map in whitelist contract (16347ms)
12
โ€‹
13
MESSAGE STATEMENT: whitelist does not exist
14
โœ“ Assert list of transfers with one sender s whitelistID don t refer to an existing whitelist / Should fail (3160ms)
15
โ€‹
16
OpHash: oo9HkTbzfvffz8Zi6Avj4rAXqDysC4TtnpcDZt3zEde4vGKRQxU
17
โœ“ Admin sets Daly s whitelist outbound restricted (25520ms)
18
โ€‹
19
MESSAGE STATEMENT: outbound restricted
20
โœ“ Assert list of transfers with one restricted sender & restricted receiver / Should fail (2629ms)
21
โ€‹
22
OpHash: op5s6LJTAPrBZ5FvDvNz5KC1V3mpHquef2N5BYP5deFhi5c6FLG
23
โœ“ Admin sets Daly s whitelist outbound unrestricted (74910ms)
24
โ€‹
25
MESSAGE STATEMENT: outbound not whitelisted
26
โœ“ Assert list of transfers with one transfer where the receiver s whitelistID is not in the sender s whitelist / Should fail (2550ms)
27
โ€‹
28
OpHash: opEixE7d7tZF9XUcBP7ob6fSj91ifiYm4g4CBuFe43sszKK1TdP
29
โœ“ Admin adds Thib to Daly s whitelist (34924ms)
30
โ€‹
31
OpHash: oo7ss2kbjivZvchJKRUWdyDGa5LTCJ6Ditb5jFUX6h7wj6pCWVS
32
โœ“ Assert list of transfers: all senders & receivers are existing and unrestricted, all receivers are whitelisted in the senders' whitelists / Should succeed (2662ms)
33
โ€‹
34
10 passing (8m)
35
โœจ Done in 490.57s.
Copied!

๐Ÿ‘ฎ Roles:

  1. 1.
    Admin: the contract's owner and manager, he can:
    โ€ข Set a new contract's admin;
    โ€ข Set a new contract's issuer;
    โ€ข Add / Update / Delete any user in the users big_map;
    โ€ข Add / Update / Delete any whitelist in the whitelists big_map.
  2. 2.
    Issuer:
    โ€ข Can't be explicitly added to users;
    โ€ข Is always unrestricted;
    โ€ข Whose allowedWhitelists is the set of ALL whitelistId's

๐Ÿ”— Implementations

  • An implementation of wrapping and non-wrapping forms in Lorentz may be found hereโ€‹
  • A partial implementation of the compile-time wrapping form in LIGO may be found hereโ€‹