Smart Contract
FlowEVMBridgeTemplates
A.1e4aa0b87d10b141.FlowEVMBridgeTemplates
1import FungibleToken from 0xf233dcee88fe0abe
2import NonFungibleToken from 0x1d7e57aa55817448
3
4import EVM from 0xe467b9dd11fa00df
5
6import FlowEVMBridgeUtils from 0x1e4aa0b87d10b141
7
8/// This contract serves Cadence code from chunked templates, replacing the contract name with the name derived from
9/// given arguments - either Cadence Type or EVM contract address.
10///
11access(all)
12contract FlowEVMBridgeTemplates {
13
14 /// Canonical path for the Admin resource
15 access(all)
16 let AdminStoragePath: StoragePath
17 /// Chunked Hex-encoded Cadence contract code, to be joined on derived contract name
18 access(self)
19 let templateCodeChunks: {String: [[UInt8]]}
20
21 /// Emitted whenever there is a change to templated code
22 access(all)
23 event Updated(name: String, isNew: Bool?)
24
25 /**************
26 Getters
27 **************/
28
29 /// Serves bridged asset contract code for a given type, deriving the contract name from the EVM contract info
30 access(all)
31 fun getBridgedAssetContractCode(_ cadenceContractName: String, isERC721: Bool): [UInt8]? {
32 if isERC721 {
33 return self.getBridgedNFTContractCode(contractName: cadenceContractName)
34 } else {
35 return self.getBridgedTokenContractCode(contractName: cadenceContractName)
36 }
37 }
38
39 /**************
40 Internal
41 **************/
42
43 access(self)
44 fun getBridgedNFTContractCode(contractName: String): [UInt8]? {
45 if let chunks = self.templateCodeChunks["bridgedNFT"] {
46 return self.joinChunks(chunks, with: String.encodeHex(contractName.utf8))
47 }
48 return nil
49 }
50
51 access(self)
52 fun getBridgedTokenContractCode(contractName: String): [UInt8]? {
53 if let chunks = self.templateCodeChunks["bridgedToken"] {
54 return self.joinChunks(chunks, with: String.encodeHex(contractName.utf8))
55 }
56 return nil
57 }
58
59 access(self)
60 fun joinChunks(_ chunks: [[UInt8]], with name: String): [UInt8] {
61 let nameBytes: [UInt8] = name.decodeHex()
62 let code: [UInt8] = []
63 for i, chunk in chunks {
64 code.appendAll(chunk)
65 // No need to append the contract name after the last chunk
66 if i == chunks.length - 1 {
67 break
68 }
69 code.appendAll(nameBytes)
70 }
71 return code
72 }
73
74 /************
75 Admin
76 ************/
77
78 /// Resource enabling updates to the contract template code
79 ///
80 access(all)
81 resource Admin {
82
83 /// Adds a new template to the templateCodeChunks mapping, preventing overwrites of existing templates
84 ///
85 /// @param newTemplate: The name of the new template
86 /// @param chunks: The chunks of hex-encoded Cadence contract code
87 ///
88 /// @emits Updated with the name of the template and `isNew` set to true by way of the pre-condition
89 ///
90 access(all)
91 fun addNewContractCodeChunks(newTemplate: String, chunks: [String]) {
92 pre {
93 FlowEVMBridgeTemplates.templateCodeChunks[newTemplate] == nil: "Code already exists for template"
94 }
95 self.upsertContractCodeChunks(forTemplate: newTemplate, chunks: chunks)
96 }
97
98 /// Upserts the contract code chunks for a given template, overwriting the existing template if exists
99 ///
100 /// @param newTemplate: The name of the new template
101 /// @param chunks: The chunks of hex-encoded Cadence contract code
102 ///
103 /// @emits Updated with the name of the template and a boolean indicating if it was a newly named
104 /// template or an existing one was overwritten
105 ///
106 access(all)
107 fun upsertContractCodeChunks(forTemplate: String, chunks: [String]) {
108 let byteChunks: [[UInt8]] = []
109 for chunk in chunks {
110 byteChunks.append(chunk.decodeHex())
111 }
112
113 let isNew = FlowEVMBridgeTemplates.templateCodeChunks[forTemplate] == nil
114 emit Updated(name: forTemplate, isNew: isNew)
115
116 FlowEVMBridgeTemplates.templateCodeChunks[forTemplate] = byteChunks
117 }
118
119 /// Removes the template from the templateCodeChunks mapping
120 ///
121 /// @param name: The name of the template to remove
122 ///
123 /// @return true if the template was removed, false if it did not exist
124 ///
125 /// @emits Updated with the name of the template and `isNew` set `nil`
126 ///
127 access(all)
128 fun removeTemplate(name: String): Bool {
129 if let removed = FlowEVMBridgeTemplates.templateCodeChunks.remove(key: name) {
130 emit Updated(name: name, isNew: nil)
131 return true
132 }
133 return false
134 }
135 }
136
137 init() {
138 self.AdminStoragePath = /storage/flowEVMBridgeTemplatesAdmin
139 self.templateCodeChunks = {}
140
141 self.account.storage.save(<-create Admin(), to: self.AdminStoragePath)
142 }
143}
144