TransactionSEALED
█╲○◆░○▫&╳!╱▒░□#◆▒%◆╳^╱@◆■◆◇▓╳░╱@!◆◇#╲●?▫#&*▒!●╳□$▪^!▫#&█!●▫◆╱●^▒
Transaction ID
Execution Error
Error Code: 1009
error caused by: 1 error occurred:
Raw Error
[Error Code: 1009] error caused by: 1 error occurred: * transaction verification failed: [Error Code: 1006] invalid proposal key: public key 6 on account f380b22ef386ac7e does not have a valid signature: [Error Code: 1009] invalid envelope key: public key 6 on account f380b22ef386ac7e does not have a valid signature: signature is not valid
Transaction Summary
TransactionScript Arguments
0vaultIdentifierString
A.f1ab99c82dee3526.USDCFlow.Vault
1childAddress
2amountUFix64
0.00100000
Cadence Script
1import MetadataViews from 0x1d7e57aa55817448
2import ViewResolver from 0x1d7e57aa55817448
3import NonFungibleToken from 0x1d7e57aa55817448
4
5import FungibleToken from 0xf233dcee88fe0abe
6import FlowToken from 0x1654653399040a61
7import FungibleTokenMetadataViews from 0xf233dcee88fe0abe
8
9import ScopedFTProviders from 0x1e4aa0b87d10b141
10
11import EVM from 0xe467b9dd11fa00df
12
13import FlowEVMBridgeUtils from 0x1e4aa0b87d10b141
14import FlowEVMBridge from 0x1e4aa0b87d10b141
15import FlowEVMBridgeConfig from 0x1e4aa0b87d10b141
16
17import HybridCustody from 0xd8a7e05a7ac670c0
18import CapabilityFilter from 0xd8a7e05a7ac670c0
19
20
21transaction(vaultIdentifier: String, child: Address, amount: UFix64) {
22
23 // The Vault resource that holds the tokens that are being transferred
24 let paymentVault: @{FungibleToken.Vault}
25 let coa: auth(EVM.Bridge) &EVM.CadenceOwnedAccount
26 let scopedProvider: @ScopedFTProviders.ScopedFTProvider
27
28 prepare(signer: auth(Storage, CopyValue, BorrowValue, IssueStorageCapabilityController, PublishCapability, SaveValue) &Account) {
29 /* --- Reference the signer's CadenceOwnedAccount --- */
30 //
31 // Borrow a reference to the signer's COA
32 self.coa = signer.storage.borrow<auth(EVM.Bridge) &EVM.CadenceOwnedAccount>(from: /storage/evm)
33 ?? panic("Could not borrow COA from provided gateway address")
34
35 /* --- Retrieve the funds --- */
36 //
37 // Borrow a reference to the FungibleToken Vault
38 let vaultType = CompositeType(vaultIdentifier)
39 ?? panic("Could not construct Vault type from identifier: ".concat(vaultIdentifier))
40 // Parse the Vault identifier into its components
41 let tokenContractAddress = FlowEVMBridgeUtils.getContractAddress(fromType: vaultType)
42 ?? panic("Could not get contract address from identifier: ".concat(vaultIdentifier))
43 let tokenContractName = FlowEVMBridgeUtils.getContractName(fromType: vaultType)
44 ?? panic("Could not get contract name from identifier: ".concat(vaultIdentifier))
45
46 let viewResolver = getAccount(tokenContractAddress).contracts.borrow<&{ViewResolver}>(name: tokenContractName)
47 ?? panic("Could not borrow ViewResolver from FungibleToken contract")
48 let vaultData = viewResolver.resolveContractView(
49 resourceType: nil,
50 viewType: Type<FungibleTokenMetadataViews.FTVaultData>()
51 ) as! FungibleTokenMetadataViews.FTVaultData? ?? panic("Could not resolve FTVaultData view")
52 let vault = signer.storage.borrow<auth(FungibleToken.Withdraw) &{FungibleToken.Vault}>(
53 from: vaultData.storagePath
54 ) ?? panic("Could not access signer's FungibleToken Vault")
55
56 // signer is the parent account
57 // get the manager resource and borrow childAccount
58 let m = signer.storage.borrow<auth(HybridCustody.Manage) &HybridCustody.Manager>(from: HybridCustody.ManagerStoragePath)
59 ?? panic("manager does not exist")
60 let childAcct = m.borrowAccount(addr: child) ?? panic("child account not found")
61
62 //get Ft cap from child account
63 let capType = Type<auth(FungibleToken.Withdraw) &{FungibleToken.Provider}>()
64 let controllerID = childAcct.getControllerIDForType(type: capType, forPath: vaultData.storagePath)
65 ?? panic("no controller found for capType")
66
67 let cap = childAcct.getCapability(controllerID: controllerID, type: capType) ?? panic("no cap found")
68 let providerCap = cap as! Capability<auth(FungibleToken.Withdraw) &{FungibleToken.Provider}>
69 assert(providerCap.check(), message: "invalid provider capability")
70
71 // Get a reference to the child's stored vault
72 let vaultRef = providerCap.borrow()!
73
74 // Withdraw tokens from the signer's stored vault
75 vault.deposit(from: <- vaultRef.withdraw(amount: amount))
76 // Withdraw the requested balance & calculate the approximate bridge fee based on storage usage
77 let currentStorageUsage = signer.storage.used
78 self.paymentVault <- vault.withdraw(amount: amount)
79 let withdrawnStorageUsage = signer.storage.used
80 // Approximate the bridge fee based on the difference in storage usage with some buffer
81 let approxFee = FlowEVMBridgeUtils.calculateBridgeFee(
82 bytes: 400_000
83 )
84
85 /* --- Configure a ScopedFTProvider --- */
86 //
87 // Issue and store bridge-dedicated Provider Capability in storage if necessary
88 if signer.storage.type(at: FlowEVMBridgeConfig.providerCapabilityStoragePath) == nil {
89 let providerCap = signer.capabilities.storage.issue<auth(FungibleToken.Withdraw) &{FungibleToken.Provider}>(
90 /storage/flowTokenVault
91 )
92 signer.storage.save(providerCap, to: FlowEVMBridgeConfig.providerCapabilityStoragePath)
93 }
94 // Copy the stored Provider capability and create a ScopedFTProvider
95 let providerCapCopy = signer.storage.copy<Capability<auth(FungibleToken.Withdraw) &{FungibleToken.Provider}>>(from: FlowEVMBridgeConfig.providerCapabilityStoragePath)
96 ?? panic("Invalid Provider Capability found in storage.")
97 let providerFilter = ScopedFTProviders.AllowanceFilter(approxFee)
98 self.scopedProvider <- ScopedFTProviders.createScopedFTProvider(
99 provider: providerCapCopy,
100 filters: [ providerFilter ],
101 expiration: getCurrentBlock().timestamp + 1.0
102 )
103 }
104
105 execute {
106 self.coa.depositTokens(
107 vault: <-self.paymentVault,
108 feeProvider: &self.scopedProvider as auth(FungibleToken.Withdraw) &{FungibleToken.Provider}
109 )
110 // Destroy the ScopedFTProvider
111 destroy self.scopedProvider
112 }
113}