github.com/mavryk-network/mvgo@v1.19.9/rpc/contracts.go (about) 1 // Copyright (c) 2020-2022 Blockwatch Data Inc. 2 // Author: alex@blockwatch.cc 3 4 package rpc 5 6 import ( 7 "bytes" 8 "context" 9 "encoding/json" 10 "fmt" 11 "strconv" 12 13 "github.com/mavryk-network/mvgo/mavryk" 14 "github.com/mavryk-network/mvgo/micheline" 15 ) 16 17 // UnparsingMode defines the way types and values are represented in Micheline script 18 // and storage. This affects timestamps, keys, addresses, signatures and nested pairs. 19 // Optimized encodings use integers for timestamps and bytes instead of base58 encoded 20 // values. Legacy mode is supposed to output 2-ary pairs only, but is messed up on 21 // certain endpoints (e.g. /script/normalized), so there's no guarantee. 22 type UnparsingMode string 23 24 const ( 25 UnparsingModeInvalid = "" 26 UnparsingModeLegacy = "Optimized_legacy" 27 UnparsingModeOptimized = "Optimized" 28 UnparsingModeReadable = "Readable" 29 ) 30 31 func (m UnparsingMode) String() string { 32 return string(m) 33 } 34 35 // Contracts holds a list of addresses 36 type Contracts []mavryk.Address 37 38 // Contracts holds info about a Tezos account 39 type ContractInfo struct { 40 Balance int64 `json:"balance,string"` 41 Delegate mavryk.Address `json:"delegate"` 42 Counter int64 `json:"counter,string"` 43 Manager string `json:"manager"` 44 FrozenDeposits struct { 45 InitialAmount int64 `json:"initial_amount,string"` 46 ActualAmount int64 `json:"actual_amount,string"` 47 } `json:"frozen_deposits"` 48 FrozenDepositsPseudotokens int64 `json:"frozen_deposits_pseudotokens,string"` 49 MissedAttestations struct { 50 RemainingSlots int64 `json:"remaining_slots"` 51 MissedLevels int64 `json:"missed_levels"` 52 } `json:"missed_attestations"` 53 StakingParameters struct { 54 // TODO 55 } `json:"staking_parameters"` 56 UnstakeRequests struct { 57 Delegate mavryk.Address `json:"delegate"` 58 Requests []struct { 59 Cycle int64 `json:"cycle"` 60 RequestedAmount int64 `json:"requested_amount,string"` 61 } `json:"requests"` 62 } `json:"unstake_requests"` 63 UnstakedFrozenDeposits []UnstakedDeposit `json:"unstaked_frozen_deposits"` 64 } 65 66 type UnstakedDeposit struct { 67 Cycle int64 `json:"cycle"` 68 InitialAmount int64 `json:"initial_amount,string"` 69 ActualAmount int64 `json:"actual_amount,string"` 70 } 71 72 // [[44,{"initial_amount":"1007000000","actual_amount":"1007000000"}]] 73 func (u *UnstakedDeposit) UnmarshalJSON(buf []byte) error { 74 if len(buf) == 0 { 75 return nil 76 } 77 s, data, ok := bytes.Cut(buf[1:len(buf)-1], []byte{','}) 78 if !ok || buf[0] != '[' || buf[len(buf)-1] != ']' { 79 return fmt.Errorf("UnstakedDeposit: invalid format") 80 } 81 num, err := strconv.ParseInt(string(s), 10, 64) 82 if err != nil { 83 return err 84 } 85 u.Cycle = num 86 type alias *UnstakedDeposit 87 return json.Unmarshal(data, alias(u)) 88 } 89 90 func (i ContractInfo) IsRevealed() bool { 91 return mavryk.IsPublicKey(i.Manager) 92 } 93 94 func (i ContractInfo) ManagerKey() mavryk.Key { 95 key, _ := mavryk.ParseKey(i.Manager) 96 return key 97 } 98 99 // GetContract returns info about an account at block id. 100 func (c *Client) GetContract(ctx context.Context, addr mavryk.Address, id BlockID) (*ContractInfo, error) { 101 u := fmt.Sprintf("chains/main/blocks/%s/context/contracts/%s", id, addr) 102 var info ContractInfo 103 err := c.Get(ctx, u, &info) 104 if err != nil { 105 return nil, err 106 } 107 return &info, nil 108 } 109 110 // GetContractBalance returns the spendable balance for this account at block id. 111 func (c *Client) GetContractBalance(ctx context.Context, addr mavryk.Address, id BlockID) (mavryk.Z, error) { 112 u := fmt.Sprintf("chains/main/blocks/%s/context/contracts/%s/balance", id, addr) 113 var bal mavryk.Z 114 err := c.Get(ctx, u, &bal) 115 return bal, err 116 } 117 118 // GetManagerKey returns the revealed public key of an account at block id. 119 func (c *Client) GetManagerKey(ctx context.Context, addr mavryk.Address, id BlockID) (mavryk.Key, error) { 120 u := fmt.Sprintf("chains/main/blocks/%s/context/contracts/%s/manager_key", id, addr) 121 var key mavryk.Key 122 err := c.Get(ctx, u, &key) 123 return key, err 124 } 125 126 // GetContractExt returns info about an account at block id including its public key when revealed. 127 func (c *Client) GetContractExt(ctx context.Context, addr mavryk.Address, id BlockID) (*ContractInfo, error) { 128 u := fmt.Sprintf("chains/main/blocks/%s/context/raw/json/contracts/index/%s", id, addr) 129 var info ContractInfo 130 err := c.Get(ctx, u, &info) 131 if err != nil { 132 return nil, err 133 } 134 return &info, nil 135 } 136 137 // ListContracts returns a list of all known contracts at head. This call may be very SLOW for 138 // large chains and there is no means to limit the result. Use with caution and consider 139 // calling an indexer API instead. 140 func (c *Client) ListContracts(ctx context.Context, id BlockID) (Contracts, error) { 141 contracts := make(Contracts, 0) 142 u := fmt.Sprintf("chains/main/blocks/%s/context/contracts", id) 143 if err := c.Get(ctx, u, &contracts); err != nil { 144 return nil, err 145 } 146 return contracts, nil 147 } 148 149 type rawContract struct { 150 Script micheline.Script 151 } 152 153 // GetContractScript returns the originated contract script in default data mode. 154 func (c *Client) GetContractScript(ctx context.Context, addr mavryk.Address) (*micheline.Script, error) { 155 u := fmt.Sprintf("chains/main/blocks/head/context/contracts/%s", addr) 156 var rc rawContract 157 err := c.Get(ctx, u, &rc) 158 if err != nil { 159 return nil, err 160 } 161 return &rc.Script, nil 162 } 163 164 // GetNormalizedScript returns the originated contract script with global constants 165 // expanded using given unparsing mode. 166 func (c *Client) GetNormalizedScript(ctx context.Context, addr mavryk.Address, mode UnparsingMode) (*micheline.Script, error) { 167 u := fmt.Sprintf("chains/main/blocks/head/context/contracts/%s/script/normalized", addr) 168 s := micheline.NewScript() 169 if mode == "" { 170 mode = UnparsingModeOptimized 171 } 172 postData := struct { 173 Mode UnparsingMode `json:"unparsing_mode"` 174 }{ 175 Mode: mode, 176 } 177 err := c.Post(ctx, u, &postData, s) 178 if err != nil { 179 return nil, err 180 } 181 return s, nil 182 } 183 184 // GetContractStorage returns the contract's storage at block id. 185 func (c *Client) GetContractStorage(ctx context.Context, addr mavryk.Address, id BlockID) (micheline.Prim, error) { 186 u := fmt.Sprintf("chains/main/blocks/%s/context/contracts/%s/storage", id, addr) 187 prim := micheline.Prim{} 188 err := c.Get(ctx, u, &prim) 189 if err != nil { 190 return micheline.InvalidPrim, err 191 } 192 return prim, nil 193 } 194 195 // GetContractStorageNormalized returns contract's storage at block id using unparsing mode. 196 func (c *Client) GetContractStorageNormalized(ctx context.Context, addr mavryk.Address, id BlockID, mode UnparsingMode) (micheline.Prim, error) { 197 u := fmt.Sprintf("chains/main/blocks/%s/context/contracts/%s/storage/normalized", id, addr) 198 if mode == "" { 199 mode = UnparsingModeOptimized 200 } 201 postData := struct { 202 Mode UnparsingMode `json:"unparsing_mode"` 203 }{ 204 Mode: mode, 205 } 206 prim := micheline.Prim{} 207 err := c.Post(ctx, u, &postData, &prim) 208 if err != nil { 209 return micheline.InvalidPrim, err 210 } 211 return prim, nil 212 } 213 214 // GetContractEntrypoints returns the contract's entrypoints. 215 func (c *Client) GetContractEntrypoints(ctx context.Context, addr mavryk.Address) (map[string]micheline.Type, error) { 216 u := fmt.Sprintf("chains/main/blocks/head/context/contracts/%s/entrypoints", addr) 217 type eptype struct { 218 Entrypoints map[string]micheline.Type `json:"entrypoints"` 219 } 220 eps := &eptype{} 221 err := c.Get(ctx, u, eps) 222 if err != nil { 223 return nil, err 224 } 225 return eps.Entrypoints, nil 226 } 227 228 // ListBigmapKeys returns all keys in the bigmap at block id. This call may be very SLOW for 229 // large bigmaps and there is no means to limit the result. Use of this method is discouraged. 230 // Instead, call the ListBigmapValuesExt method below. In case you require the pre-image of 231 // bigmap keys consider calling an indexer API instead. 232 func (c *Client) ListBigmapKeys(ctx context.Context, bigmap int64, id BlockID) ([]mavryk.ExprHash, error) { 233 u := fmt.Sprintf("chains/main/blocks/%s/context/raw/json/big_maps/index/%d/contents", id, bigmap) 234 hashes := make([]mavryk.ExprHash, 0) 235 err := c.Get(ctx, u, &hashes) 236 if err != nil { 237 return nil, err 238 } 239 return hashes, nil 240 } 241 242 // ListActiveBigmapKeys returns all keys in the bigmap at block id. This call may be very SLOW for 243 // large bigmaps and there is no means to limit the result. Use of this method is discouraged. 244 // Instead, call the ListActiveBigmapValuesExt method below. In case you require the pre-image of 245 // bigmap keys consider calling an indexer API instead. 246 func (c *Client) ListActiveBigmapKeys(ctx context.Context, bigmap int64) ([]mavryk.ExprHash, error) { 247 return c.ListBigmapKeys(ctx, bigmap, Head) 248 } 249 250 // GetBigmapValue returns value at key hash from bigmap at block id 251 func (c *Client) GetBigmapValue(ctx context.Context, bigmap int64, hash mavryk.ExprHash, id BlockID) (micheline.Prim, error) { 252 u := fmt.Sprintf("chains/main/blocks/%s/context/big_maps/%d/%s", id, bigmap, hash) 253 prim := micheline.Prim{} 254 err := c.Get(ctx, u, &prim) 255 if err != nil { 256 return micheline.InvalidPrim, err 257 } 258 return prim, nil 259 } 260 261 // GetActiveBigmapValue returns current active value at key hash from bigmap. 262 func (c *Client) GetActiveBigmapValue(ctx context.Context, bigmap int64, hash mavryk.ExprHash) (micheline.Prim, error) { 263 return c.GetBigmapValue(ctx, bigmap, hash, Head) 264 } 265 266 // ListBigmapValues returns all values from bigmap at block id. This call may be very SLOW for 267 // large bigmaps and there is no means to limit the result. Use of this method is discouraged. 268 // Instead, call the ListBigmapValuesExt method below. In case you require the pre-image of 269 // bigmap keys consider calling an indexer API instead. 270 func (c *Client) ListBigmapValues(ctx context.Context, bigmap int64, id BlockID) ([]micheline.Prim, error) { 271 u := fmt.Sprintf("chains/main/blocks/%s/context/big_maps/%d", id, bigmap) 272 vals := make([]micheline.Prim, 0) 273 err := c.Get(ctx, u, &vals) 274 if err != nil { 275 return nil, err 276 } 277 return vals, nil 278 } 279 280 // ListBigmapValues returns at most limit values starting at offset from bigmap at block id. 281 func (c *Client) ListBigmapValuesExt(ctx context.Context, bigmap int64, id BlockID, offset, limit int) ([]micheline.Prim, error) { 282 u := fmt.Sprintf("chains/main/blocks/%s/context/big_maps/%d?offset=%d&length=%d", id, bigmap, offset, limit) 283 vals := make([]micheline.Prim, 0) 284 err := c.Get(ctx, u, &vals) 285 if err != nil { 286 return nil, err 287 } 288 return vals, nil 289 } 290 291 // ListActiveBigmapValues returns all values from bigmap at block id. This call may be very SLOW for 292 // large bigmaps and there is no means to limit the result. Use of this method is discouraged. 293 // Instead, call the ListActiveBigmapValuesExt method below. In case you require the pre-image of 294 // bigmap keys consider calling an indexer API instead. 295 func (c *Client) ListActiveBigmapValues(ctx context.Context, bigmap int64, id BlockID) ([]micheline.Prim, error) { 296 return c.ListBigmapValues(ctx, bigmap, Head) 297 } 298 299 // ListActiveBigmapValuesExt returns at most limit values starting at offset from bigmap 300 // at block id. In case you require the pre-image of bigmap keys consider calling an 301 // indexer API instead. 302 func (c *Client) ListActiveBigmapValuesExt(ctx context.Context, bigmap int64, id BlockID, offset, limit int) ([]micheline.Prim, error) { 303 return c.ListBigmapValuesExt(ctx, bigmap, Head, offset, limit) 304 } 305 306 type BigmapInfo struct { 307 KeyType micheline.Prim `json:"key_type"` 308 ValueType micheline.Prim `json:"value_type"` 309 TotalBytes int64 `json:"total_bytes,string"` 310 } 311 312 // GetActiveBigmapInfo returns type and content info from bigmap at current head. 313 func (c *Client) GetActiveBigmapInfo(ctx context.Context, bigmap int64) (*BigmapInfo, error) { 314 return c.GetBigmapInfo(ctx, bigmap, Head) 315 } 316 317 // GetBigmapInfo returns type and content info from bigmap at block id. 318 func (c *Client) GetBigmapInfo(ctx context.Context, bigmap int64, id BlockID) (*BigmapInfo, error) { 319 u := fmt.Sprintf("chains/main/blocks/%s/context/raw/json/big_maps/index/%d", id, bigmap) 320 info := &BigmapInfo{} 321 err := c.Get(ctx, u, info) 322 if err != nil { 323 return nil, err 324 } 325 return info, nil 326 }