Smart Contract

Pb

A.08dd120226ec2213.Pb

Deployed

16h ago
Feb 28, 2026, 02:31:18 AM UTC

Dependents

0 imports
1access(all) contract Pb {
2  /// only support Varint and LengthDelim for now
3  access(all) enum WireType: UInt8 {
4    access(all) case Varint
5    access(all) case Fixed64
6    access(all) case LengthDelim
7    access(all) case StartGroup
8    access(all) case EndGroup
9    access(all) case Fixed32
10  }
11
12  access(all) struct TagType {
13    access(all) let tag: UInt64
14    access(all) let wt: WireType
15    init(tag: UInt64, wt: UInt8){
16      self.tag = tag
17      self.wt = WireType(rawValue: wt)!
18    }
19  }
20
21  access(all) struct Buffer {
22    access(all) var idx: Int
23    access(all) let b: [UInt8] // readonly of original pb msg
24
25    init(raw: [UInt8]) {
26      self.idx = 0
27      self.b = raw
28    }
29    // if idx >= b.length, means we're done
30    access(all) view fun hasMore(): Bool {
31      return self.idx < self.b.length
32    }
33
34    // has to use struct as cadence can has only single return
35    access(all) fun decKey(): TagType {
36      let v = self.decVarint()
37      return TagType(tag: v/8, wt: UInt8(v % 8) )
38    }
39  
40    // modify self.idx
41    access(all) fun decVarint(): UInt64 {
42      var ret: UInt64 = 0
43      // zero-copy for lower gas cost even though it may not matter
44      var i = 0
45      while i < 10 { // varint max 10 bytes
46        let b = self.b[self.idx+i]
47        ret = ret | UInt64(b & 0x7F) << UInt64(i * 7)
48          if (b < 0x80) {
49              self.idx = self.idx + i + 1;
50              return ret;
51          }
52        i = i + 1
53      }
54      assert(i<10, message: "invalid varint")
55      return ret
56    }
57    // modify self.idx
58    access(all) fun decBytes(): [UInt8] {
59      let len = self.decVarint()
60      let end = self.idx + Int(len)
61      assert(end <= self.b.length, message: "invalid bytes length: ".concat(end.toString()))
62      // array slice is https://github.com/onflow/cadence/pull/1315/files
63      // return self.b.slice(from: self.Idx, upTo: end)
64      var ret: [UInt8] = []
65      while self.idx < end {
66        ret.append(self.b[self.idx])
67        self.idx = self.idx + 1
68      }
69      return ret
70    }
71  }
72
73  // raw is UInt64 big endian, raw.length <= 8
74  access(all) fun toUInt64(_ raw: [UInt8]): UInt64 {
75    let rawLen = raw.length
76    assert(rawLen<=8, message: "invalid raw length for UInt64")
77    var ret: UInt64 = 0
78    var i = 0
79    while i < rawLen {
80      let val = UInt64(raw[rawLen - 1 - i]) << UInt64(i*8)
81      ret = ret + val
82      i = i + 1
83    }
84    return ret
85  }
86
87  // raw is UInt256 big endian, raw.length <= 32
88  access(all) fun toUInt256(_ raw: [UInt8]): UInt256 {
89    let rawLen = raw.length
90    assert(rawLen<=32, message: "invalid raw length for UInt256")
91    var ret: UInt256 = 0
92    var i = 0
93    while i < rawLen {
94      let val = UInt256(raw[rawLen - 1 - i]) << UInt256(i*8)
95      ret = ret + val
96      i = i + 1
97    }
98    return ret
99  }
100
101  access(all) fun toAddress(_ raw: [UInt8]): Address {
102    return Address(self.toUInt64(raw))
103  }
104
105  access(all) fun toUFix64(_ raw: [UInt8]): UFix64 {
106    let val = self.toUInt64(raw)
107    return UFix64(val/100_000_000) + UFix64(val % 100_000_000)/100_000_000.0
108  }
109
110  /// return hex string!
111  access(all) view fun toString(_ raw: [UInt8]): String {
112    return String.encodeHex(raw)
113  }
114}