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 }