Smart Contract

Maduro

A.0e964e9e2b53ed06.Maduro

Valid From

138,915,161

Deployed

1w ago
Feb 15, 2026, 10:37:32 PM UTC

Dependents

3 imports
1// MADURO COŃO E TU MADRE
2// CartasParaMaduro - Anonymous Letters to Maduro
3// A decentralized platform for writing anonymous letters to Nicolas Maduro
4
5access(all) contract Maduro {
6
7    // Event emitted when a new letter is submitted
8    access(all) event LetterSubmitted(id: UInt64, timestamp: UFix64)
9    access(all) event LetterReplaced(id: UInt64, timestamp: UFix64)
10
11    // Letter info struct for public reading (view function safe)
12    access(all) struct LetterInfo {
13        access(all) let id: UInt64
14        access(all) let content: String
15        access(all) let timestamp: UFix64
16        access(all) let author: Address?
17
18        init(id: UInt64, content: String, timestamp: UFix64, author: Address?) {
19            self.id = id
20            self.content = content
21            self.timestamp = timestamp
22            self.author = author
23        }
24    }
25
26    // Letter resource - stores the content and metadata
27    access(all) resource Letter {
28        access(all) let id: UInt64
29        access(all) let content: String
30        access(all) let timestamp: UFix64
31        access(all) let author: Address?
32
33        init(id: UInt64, content: String, author: Address?) {
34            self.id = id
35            self.content = content
36            self.timestamp = getCurrentBlock().timestamp
37            self.author = author // Optional anonymity - can be nil for true anonymity
38        }
39    }
40
41    // Storage path for letters collection
42    access(contract) let LettersStoragePath: StoragePath
43
44    // Public path for letter collection capability (if needed for external access)
45    access(contract) let LettersPublicPath: PublicPath
46
47    // Collection of all submitted letters stored in contract account
48    access(contract) var letters: @{UInt64: Letter}
49    access(contract) var nextLetterId: UInt64
50
51    // Public interface for reading letters
52    access(all) fun getLetter(id: UInt64): LetterInfo? {
53        let letterRef = &self.letters[id] as &Letter?
54        if letterRef == nil {
55            return nil
56        }
57        return LetterInfo(
58            id: letterRef!.id,
59            content: letterRef!.content,
60            timestamp: letterRef!.timestamp,
61            author: letterRef!.author
62        )
63    }
64
65    access(all) fun getAllLetterIds(): [UInt64] {
66        return self.letters.keys
67    }
68
69    access(all) fun getLetterCount(): UInt64 {
70        return self.nextLetterId - 1
71    }
72
73    // Validate that letter starts with proper greeting
74    access(all) view fun isValidLetter(_ content: String): Bool {
75        let trimmed = content.toLower()
76        return trimmed.slice(from: 0, upTo: 12) == "para: maduro" ||
77               trimmed.slice(from: 0, upTo: 10) == "to: maduro"
78    }
79
80    // Check if letter contains forbidden text (calling him "Presidente")
81    // HE IS NOT THE PRESIDENT OF VENEZUELA
82    access(all) view fun containsForbiddenText(_ content: String): Bool {
83        let lowerContent = content.toLower()
84        return lowerContent.contains("presidente maduro") ||
85               lowerContent.contains("presidente nicolas maduro") ||
86               lowerContent.contains("presidente nicolás maduro")
87    }
88
89    access(all) fun replaceLetter(id: UInt64, content: String, author: Address?) {
90        pre {
91            content.length > 0: "Letter cannot be empty"
92            content.length <= 10000: "Letter too long (max 10000 characters)"
93            Maduro.isValidLetter(content): "Letter must start with 'Para: Maduro' or 'To: Maduro'"
94            !Maduro.containsForbiddenText(content): "Cannot call him 'Presidente Maduro' - HE IS NOT THE PRESIDENT OF VENEZUELA"
95        }
96        // Remove old letter if it exists
97        if let oldLetter <- self.letters.remove(key: id) {
98            destroy oldLetter
99        }
100        // Create the Letter resource with the correct id
101        let letter <- create Letter(
102            id: id,
103            content: content,
104            author: author
105        )
106        // Store the letter resource in the contract's storage
107        // Use force-assignment since we've removed the old value (slot is guaranteed to be empty)
108        self.letters[id] <-! letter
109        emit LetterReplaced(id: id, timestamp: getCurrentBlock().timestamp)
110    }
111
112    // Submit a new letter (transaction function)
113    access(all) fun submitLetter(content: String, author: Address?) {
114        pre {
115            content.length > 0: "Letter cannot be empty"
116            content.length <= 10000: "Letter too long (max 10000 characters)"
117            Maduro.isValidLetter(content): "Letter must start with 'Para: Maduro' or 'To: Maduro'"
118            !Maduro.containsForbiddenText(content): "Cannot call him 'Presidente Maduro' - HE IS NOT THE PRESIDENT OF VENEZUELA"
119        }
120
121        // Create the Letter resource
122        let letter <- create Letter(
123            id: self.nextLetterId,
124            content: content,
125            author: author
126        )
127
128        // Store the letter resource in the contract's storage
129        self.letters[self.nextLetterId] <-! letter
130        self.nextLetterId = self.nextLetterId + 1
131
132        emit LetterSubmitted(
133            id: self.nextLetterId - 1,
134            timestamp: getCurrentBlock().timestamp
135        )
136    }
137
138    init() {
139        // Initialize storage paths for the contract
140        self.LettersStoragePath = /storage/maduroLetters
141        self.LettersPublicPath = /public/maduroLetters
142
143        // Initialize the letters collection
144        self.letters <- {}
145        self.nextLetterId = 1
146    }
147}