Usurpation of Identity
The previous section used the liquidity contract admins.liq and its techelson version admins.tz. It showcased how to handle expected transfer failures and turn them into test objectives. The failure used to demonstrate the example was that we tried to add a new administrator by calling the contract from the testcase, which failed because only administrators can add other administrators, and the (address of the) testcase was not registered as such.
PUSH @amount mutez 0 ;
# New admin's address.
DUUUUP ;
# New admin's name.
PUSH @new_name string "new_admin" ;
PAIR ;
# Root's name.
PUSH @name string "root" ;
PAIR @storage ;
TRANSFER_TOKENS ;
PUSH (option string) (Some "illegal access to admin account") ;
MUST_FAIL @this_must_fail string ;
PRINT_STACK ;
DIP {NIL operation } ;
CONS ;
APPLY_OPERATIONS ;
One solution would be to register the testcase directly, but it would be more natural and more
generic to be able to apply a transfer as someone else. Hence the SET_SOURCE
extension:
instruction | parameter | stack |
---|---|---|
SET_SOURCE | code | :: address : 'A |
-> 'B | ||
iff code :: [ A -> B ] |
Warning: the
SET_SOURCE
extension is only legal in testcases.
This extension allows to pretend the testcase is a live contract or account from the environment.
More precisely, all operations created in the code
under the SET_SOURCE
will have their source
and sender be the address from the stack. Testcase setSource.techel uses this instruction to
pretend that root
is the one adding a new administrator.
# New admin's address.
DUUUUP ;
# New admin's name.
PUSH @new_name string "new_admin" ;
PAIR ;
# Root's name.
PUSH @name string "root" ;
PAIR @storage ;
{ # Pretending to be `root`.
DUUUUUUP ;
PRINT_STACK ;
STEP ;
SET_SOURCE {
TRANSFER_TOKENS
}
} ;
PRINT_STACK ;
DIP { NIL operation } ;
CONS ;
APPLY_OPERATIONS
The testcase now succeeds, and its output is
$ techelson --contract rsc/admins/contracts/admins.tz -- rsc/admins/okay/setSource.techel
Running test `SetSource`
running test script...
timestamp: 1970-01-01 00:00:00 +00:00
applying operation CREATE[uid:2] (@address[3]@admins, "sha512:@contract_manager", None, false, true, 0utz) "Admins"
timestamp: 1970-01-01 00:00:00 +00:00
live contracts: none
=> live contracts: <anonymous> (0utz) address[2]@new_admin
Admins (0utz) address[3]@admins
<anonymous> (0utz) address[1]@root
running test script...
timestamp: 1970-01-01 00:00:00 +00:00
stack:
|==================================================================================================|
| @root |
| address[1]@root |
| address |
|--------------------------------------------------------------------------------------------------|
| @new_admin |
| address[2]@new_admin |
| address |
|--------------------------------------------------------------------------------------------------|
| address[3]@admins |
| (contract (pair string (pair string address))) |
|--------------------------------------------------------------------------------------------------|
| address[3]@admins |
| (contract (pair string (pair string address))) |
|--------------------------------------------------------------------------------------------------|
| @amount |
| 0utz |
| mutez |
|--------------------------------------------------------------------------------------------------|
| @storage |
| ("root", ("new_admin", address[2]@new_admin)) |
| (pair string (pair string address)) |
|--------------------------------------------------------------------------------------------------|
| address[1]@root |
| address |
|==================================================================================================|
running test script...
timestamp: 1970-01-01 00:00:00 +00:00
stopping [no information] press `return` to continue
running test script...
timestamp: 1970-01-01 00:00:00 +00:00
stack:
|==================================================================================================|
| @root |
| address[1]@root |
| address |
|--------------------------------------------------------------------------------------------------|
| @new_admin |
| address[2]@new_admin |
| address |
|--------------------------------------------------------------------------------------------------|
| address[3]@admins |
| (contract (pair string (pair string address))) |
|--------------------------------------------------------------------------------------------------|
| TRANSFER[uid:3] address[1]@root -> address[3]@admins 0utz ("root", ("new_admin", address[2]@new_admin)) |
| operation |
|==================================================================================================|
running test script...
timestamp: 1970-01-01 00:00:00 +00:00
applying operation TRANSFER[uid:3] address[1]@root -> address[3]@admins 0utz ("root", ("new_admin", address[2]@new_admin))
timestamp: 1970-01-01 00:00:00 +00:00
live contracts: <anonymous> (0utz) address[2]@new_admin
Admins (0utz) address[3]@admins
<anonymous> (0utz) address[1]@root
running TRANSFER[uid:3] address[1]@root -> address[3]@admins 0utz ("root", ("new_admin", address[2]@new_admin))
timestamp: 1970-01-01 00:00:00 +00:00
=> live contracts: <anonymous> (0utz) address[2]@new_admin
Admins (0utz) address[3]@admins
<anonymous> (0utz) address[1]@root
running test script...
timestamp: 1970-01-01 00:00:00 +00:00
Done running test `SetSource`
Notice how, in the last PRINT_STACK
, the sender of the transfer is now root
:
TRANSFER[uid:3] address[1]@root -> address[3]@admins ...