github.com/mavryk-network/mvgo@v1.19.9/micheline/manager.go (about)

     1  // Copyright (c) 2020-2021 Blockwatch Data Inc.
     2  // Author: alex@blockwatch.cc
     3  
     4  // see
     5  // https://gitlab.com/nomadic-labs/mi-cho-coq/merge_requests/29/diffs
     6  // https://gitlab.com/tezos/tezos/blob/510ae152082334b79d3364079cd466e07172dc3a/specs/migration_004_to_005.md#origination-script-transformation
     7  
     8  package micheline
     9  
    10  import (
    11  	"bytes"
    12  	"encoding/hex"
    13  	"fmt"
    14  )
    15  
    16  // manager.tz
    17  // https://blog.nomadic-labs.com/babylon-update-instructions-for-delegation-wallet-developers.html
    18  const m_tz_script = "000000c602000000c105000764085e036c055f036d0000000325646f046c000000082564656661756c740501035d050202000000950200000012020000000d03210316051f02000000020317072e020000006a0743036a00000313020000001e020000000403190325072c020000000002000000090200000004034f0327020000000b051f02000000020321034c031e03540348020000001e020000000403190325072c020000000002000000090200000004034f0327034f0326034202000000080320053d036d0342"
    19  
    20  // empty store (used as placeholder and to satisfy script decoding which expects storage)
    21  const m_tz_store = "0000001a0a00000015000000000000000000000000000000000000000000"
    22  
    23  var (
    24  	manager_tz_code_len int
    25  	manager_tz          []byte
    26  )
    27  
    28  func init() {
    29  	// unpack manager.tz from binary blob
    30  	buf, err := hex.DecodeString(m_tz_script + m_tz_store)
    31  	if err != nil {
    32  		panic(fmt.Errorf("micheline: decoding manager script: %w", err))
    33  	}
    34  	manager_tz = buf
    35  	manager_tz_code_len = len(m_tz_script) / 2
    36  }
    37  
    38  func MakeManagerScript(managerHash []byte) (*Script, error) {
    39  	script := NewScript()
    40  	if err := script.UnmarshalBinary(manager_tz); err != nil {
    41  		return nil, fmt.Errorf("micheline: unmarshal manager script: %w", err)
    42  	}
    43  
    44  	// patch storage
    45  	copy(script.Storage.Bytes, managerHash)
    46  
    47  	return script, nil
    48  }
    49  
    50  func IsManagerTz(buf []byte) bool {
    51  	return len(buf) >= manager_tz_code_len && bytes.Equal(buf[:manager_tz_code_len], manager_tz[:manager_tz_code_len])
    52  }
    53  
    54  func (p Prim) MigrateToBabylonStorage(managerHash []byte) Prim {
    55  	return NewCode(D_PAIR, NewBytes(managerHash), p)
    56  }
    57  
    58  // Patch params, storage and code
    59  func (s *Script) MigrateToBabylonAddDo(managerHash []byte) {
    60  	// add default entrypoint annotation
    61  	s.Code.Param.Args[0].Anno = append([]string{"%default"}, s.Code.Param.Args[0].Anno...)
    62  
    63  	// adjust prim type to annotation type
    64  	switch s.Code.Param.Args[0].Type {
    65  	case PrimNullary, PrimUnary, PrimBinary:
    66  		s.Code.Param.Args[0].Type++
    67  	}
    68  
    69  	// wrap params
    70  	s.Code.Param.Args[0] = NewCode(
    71  		T_OR,
    72  		NewCodeAnno(T_LAMBDA, "%do", NewCode(T_UNIT), NewCode(T_LIST, NewCode(T_OPERATION))),
    73  		s.Code.Param.Args[0],
    74  	)
    75  
    76  	// wrap storage
    77  	s.Code.Storage.Args[0] = NewCode(T_PAIR, NewCode(T_KEY_HASH), s.Code.Storage.Args[0])
    78  
    79  	// wrap code
    80  	s.Code.Code.Args[0] = NewSeq(
    81  		NewCode(I_DUP),
    82  		NewCode(I_CAR),
    83  		NewCode(I_IF_LEFT,
    84  			DO_ENTRY(),
    85  			NewSeq(
    86  				// # Transform the inputs to the original script types
    87  				NewCode(I_DIP, NewSeq(NewCode(I_CDR), NewCode(I_DUP), NewCode(I_CDR))),
    88  				NewCode(I_PAIR),
    89  				// # 'default' entrypoint - original code
    90  				s.Code.Code.Args[0],
    91  				// # Transform the outputs to the new script types
    92  				NewCode(I_SWAP),
    93  				NewCode(I_CAR),
    94  				NewCode(I_SWAP),
    95  				UNPAIR(),
    96  				NewCode(I_DIP, NewSeq(NewCode(I_SWAP), NewCode(I_PAIR))),
    97  				NewCode(I_PAIR),
    98  			),
    99  		),
   100  	)
   101  
   102  	// migrate storage
   103  	s.Storage = s.Storage.MigrateToBabylonStorage(managerHash)
   104  }
   105  
   106  func (s *Script) MigrateToBabylonSetDelegate(managerHash []byte) {
   107  	// add default entrypoint annotation
   108  	s.Code.Param.Args[0].Anno = append([]string{"%default"}, s.Code.Param.Args[0].Anno...)
   109  
   110  	// adjust prim type to annotation type
   111  	switch s.Code.Param.Args[0].Type {
   112  	case PrimNullary, PrimUnary, PrimBinary:
   113  		s.Code.Param.Args[0].Type++
   114  	}
   115  
   116  	// wrap params
   117  	s.Code.Param.Args[0] = NewCode(
   118  		T_OR,
   119  		NewCode(T_OR,
   120  			NewCodeAnno(T_KEY_HASH, "%set_delegate"),
   121  			NewCodeAnno(T_UNIT, "%remove_delegate"),
   122  		),
   123  		s.Code.Param.Args[0],
   124  	)
   125  
   126  	// wrap storage
   127  	s.Code.Storage.Args[0] = NewCode(T_PAIR, NewCode(T_KEY_HASH), s.Code.Storage.Args[0])
   128  
   129  	// wrap code
   130  	s.Code.Code.Args[0] = NewSeq(
   131  		NewCode(I_DUP),
   132  		NewCode(I_CAR),
   133  		NewCode(I_IF_LEFT,
   134  			DELEGATE_ENTRY(),
   135  			NewSeq(
   136  				// # Transform the inputs to the original script types
   137  				NewCode(I_DIP, NewSeq(NewCode(I_CDR), NewCode(I_DUP), NewCode(I_CDR))),
   138  				NewCode(I_PAIR),
   139  				// # 'default' entrypoint - original code
   140  				s.Code.Code.Args[0],
   141  				// # Transform the outputs to the new script types
   142  				NewCode(I_SWAP),
   143  				NewCode(I_CAR),
   144  				NewCode(I_SWAP),
   145  				UNPAIR(),
   146  				NewCode(I_DIP, NewSeq(NewCode(I_SWAP), NewCode(I_PAIR))),
   147  				NewCode(I_PAIR),
   148  			),
   149  		),
   150  	)
   151  
   152  	// migrate storage
   153  	s.Storage = s.Storage.MigrateToBabylonStorage(managerHash)
   154  }
   155  
   156  // Macros
   157  func DO_ENTRY() Prim {
   158  	return NewSeq(
   159  		// # Assert no token was sent:
   160  		NewCode(I_PUSH, NewCode(T_MUMAV), NewInt64(0)), // PUSH mumav 0 ;
   161  		NewCode(I_AMOUNT), // AMOUNT ;
   162  		ASSERT_CMPEQ(),    // ASSERT_CMPEQ ;
   163  		// # Assert that the sender is the manager
   164  		DUUP(),                      // DUUP ;
   165  		NewCode(I_CDR),              // CDR ;
   166  		NewCode(I_CAR),              // CAR ;
   167  		NewCode(I_IMPLICIT_ACCOUNT), // IMPLICIT_ACCOUNT ;
   168  		NewCode(I_ADDRESS),          // ADDRESS ;
   169  		NewCode(I_SENDER),           // SENDER ;
   170  		IFCMPNEQ( // IFCMPNEQ
   171  			NewSeq(
   172  				NewCode(I_SENDER), //   { SENDER ;
   173  				NewCode(I_PUSH, NewCode(T_STRING), NewString("Only the owner can operate.")), // PUSH string "" ;
   174  				NewCode(I_PAIR),     //     PAIR ;
   175  				NewCode(I_FAILWITH), //     FAILWITH ;
   176  			),
   177  			NewSeq( // # Execute the lambda argument
   178  				NewCode(I_UNIT),                        //     UNIT ;
   179  				NewCode(I_EXEC),                        //     EXEC ;
   180  				NewCode(I_DIP, NewSeq(NewCode(I_CDR))), //     DIP { CDR } ;
   181  				NewCode(I_PAIR),                        //     PAIR ;
   182  			),
   183  		),
   184  	)
   185  }
   186  
   187  // 'set_delegate'/'remove_delegate' entrypoints
   188  func DELEGATE_ENTRY() Prim {
   189  	return NewSeq(
   190  		// # Assert no token was sent:
   191  		NewCode(I_PUSH, NewCode(T_MUMAV), NewInt64(0)), // PUSH mumav 0 ;
   192  		NewCode(I_AMOUNT), // AMOUNT ;
   193  		ASSERT_CMPEQ(),    // ASSERT_CMPEQ ;
   194  		// # Assert that the sender is the manager
   195  		DUUP(),                      // DUUP ;
   196  		NewCode(I_CDR),              // CDR ;
   197  		NewCode(I_CAR),              // CAR ;
   198  		NewCode(I_IMPLICIT_ACCOUNT), // IMPLICIT_ACCOUNT ;
   199  		NewCode(I_ADDRESS),          // ADDRESS ;
   200  		NewCode(I_SENDER),           // SENDER ;
   201  		IFCMPNEQ( // IFCMPNEQ
   202  			NewSeq(
   203  				NewCode(I_SENDER), // SENDER ;
   204  				NewCode(I_PUSH, NewCode(T_STRING), NewString("Only the owner can operate.")), // PUSH string "" ;
   205  				NewCode(I_PAIR),     // PAIR ;
   206  				NewCode(I_FAILWITH), // FAILWITH ;
   207  			),
   208  			NewSeq( // # entrypoints
   209  				NewCode(I_DIP, NewSeq(NewCode(I_CDR), NewCode(I_NIL, NewCode(T_OPERATION)))), // DIP { CDR ; NIL operation } ;
   210  				NewCode(I_IF_LEFT,
   211  					// # 'set_delegate' entrypoint
   212  					NewSeq(
   213  						NewCode(I_SOME),         // SOME ;
   214  						NewCode(I_SET_DELEGATE), // SET_DELEGATE ;
   215  						NewCode(I_CONS),         // CONS ;
   216  						NewCode(I_PAIR),         // PAIR ;
   217  					),
   218  					// # 'remove_delegate' entrypoint
   219  					NewSeq(
   220  						NewCode(I_DROP),                      // DROP ;
   221  						NewCode(I_NONE, NewCode(T_KEY_HASH)), // NONE key_hash ;
   222  						NewCode(I_SET_DELEGATE),              // SET_DELEGATE ;
   223  						NewCode(I_CONS),                      // CONS ;
   224  						NewCode(I_PAIR),                      // PAIR ;
   225  					),
   226  				),
   227  			),
   228  		),
   229  	)
   230  }