Skip to content

Commit a65462f

Browse files
Merge branch 'master' into janez/enable-concurrent-fee-collection
2 parents 7a9e376 + 18685e4 commit a65462f

File tree

6 files changed

+222
-1
lines changed

6 files changed

+222
-1
lines changed
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
import "FlowToken"
2+
import "FungibleToken"
3+
import "EVM"
4+
5+
/// Contract deployed to the service account to emit events when fraudulent tokens
6+
/// from the Dec 27th, 2025 attack are retrieved or destroyed
7+
/// This is to have transparency with the actions the service account committee takes
8+
/// to reconcile the fraudulent tokens
9+
10+
access(all) contract RetrieveFraudulentTokensEvents {
11+
12+
access(all) let adminStoragePath: StoragePath
13+
14+
/// Event emitted when fraudulent tokens are retrieved from any address and stored in the service account's vault
15+
/// for later destruction
16+
/// @param typeIdentifier - The type identifier of the fraudulent tokens
17+
/// @param amount - The amount of fraudulent tokens retrieved
18+
/// @param fromAddress - The address from which the fraudulent tokens were retrieved.
19+
/// This can be a Cadence Address, a COA Address, or an EOA Address.
20+
access(all) event FraudulentTokensRetrieved(typeIdentifier: String, amount: UFix64, fromAddress: String)
21+
22+
/// Event emitted when fraudulent tokens are destroyed from the service account's vault
23+
/// @param typeIdentifier - The type identifier of the fraudulent tokens to be destroyed
24+
/// @param amount - The amount of fraudulent tokens destroyed
25+
access(all) event FraudulentTokensDestroyed(typeIdentifier: String, amount: UFix64)
26+
27+
/// Resource that allows only the service account admin to emit the events
28+
access(all) resource Admin {
29+
30+
/// Emits the FraudulentTokensRetrieved event
31+
access(all) fun emitRetrieveTokensEvent(typeIdentifier: String, amount: UFix64, fromAddress: String) {
32+
emit FraudulentTokensRetrieved(typeIdentifier: typeIdentifier, amount: amount, fromAddress: fromAddress)
33+
}
34+
35+
/// Emits the FraudulentTokensDestroyed event
36+
access(all) fun emitDestroyTokensEvent(typeIdentifier: String, amount: UFix64) {
37+
emit FraudulentTokensDestroyed(typeIdentifier: typeIdentifier, amount: amount)
38+
}
39+
}
40+
41+
init() {
42+
43+
self.adminStoragePath = /storage/serviceAccountAdmin
44+
45+
// Create a new ServiceAccountAdmin resource
46+
self.account.storage.save(<-create Admin(), to: self.adminStoragePath)
47+
48+
// Store a new FlowToken Vault at a non-standard storage path to hold fraudulent tokens
49+
let emptyVault <- FlowToken.createEmptyVault(vaultType: Type<@FlowToken.Vault>())
50+
self.account.storage.save(<-emptyVault, to: /storage/fraudulentFlowTokenVault)
51+
52+
// Create a public capability to the Vault that only exposes
53+
// the deposit function through the Receiver interface
54+
let receiverCapability = self.account.capabilities.storage.issue<&FlowToken.Vault>(/storage/fraudulentFlowTokenVault)
55+
self.account.capabilities.publish(receiverCapability, at: /public/fraudulentFlowTokenReceiver)
56+
57+
// Create a public capability to the Vault that only exposes
58+
// the balance field through the Balance interface
59+
let balanceCapability = self.account.capabilities.storage.issue<&FlowToken.Vault>(/storage/fraudulentFlowTokenVault)
60+
self.account.capabilities.publish(balanceCapability, at: /public/fraudulentFlowTokenBalance)
61+
62+
// Create a new array to store the COAs to be destroyed
63+
let newCoaArray: @[EVM.CadenceOwnedAccount] <- []
64+
self.account.storage.save(<-newCoaArray, to: /storage/coaArrayToDestroy)
65+
66+
/* --- Configure COA --- */
67+
//
68+
// Ensure there is not yet a CadenceOwnedAccount in the standard path
69+
let coaPath = /storage/evm
70+
if self.account.storage.type(at: coaPath) == nil {
71+
// COA not found in standard path, create and publish a public **unentitled** capability
72+
self.account.storage.save(<-EVM.createCadenceOwnedAccount(), to: coaPath)
73+
let coaCapability = self.account.capabilities.storage.issue<&EVM.CadenceOwnedAccount>(coaPath)
74+
self.account.capabilities.publish(coaCapability, at: /public/evm)
75+
}
76+
77+
}
78+
}

flow.json

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@
6767
"aliases": {
6868
"emulator": "f8d6e0586b0a20c7",
6969
"mainnet": "e467b9dd11fa00df",
70-
"testing": "0000000000000007",
70+
"testing": "0000000000000001",
7171
"testnet": "8c5303eaa26202d6"
7272
}
7373
},
@@ -164,6 +164,13 @@
164164
"emulator": "f8d6e0586b0a20c7",
165165
"testing": "0000000000000007"
166166
}
167+
},
168+
"RetrieveFraudulentTokensEvents": {
169+
"source": "./contracts/testContracts/RetrieveFraudulentTokensEvents.cdc",
170+
"aliases": {
171+
"testing": "0000000000000001",
172+
"mainnet": "e467b9dd11fa00df"
173+
}
167174
}
168175
},
169176
"dependencies": {

lib/go/contracts/internal/assets/assets.go

Lines changed: 23 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)