Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions Dockerfile.mainnet-fork
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
FROM debian:stable-slim

ENV APP_HOME=/app

RUN apt-get update && apt-get install -y --no-install-recommends \
curl ca-certificates bash git \
&& rm -rf /var/lib/apt/lists/*

# Install flow CLI pinned to v2.16.0 (matches e2e workflow)
RUN curl -fsSL "https://raw.githubusercontent.com/onflow/flow-cli/v2.16.0/install.sh" | bash \
&& mv /root/.local/bin/flow /usr/local/bin/flow \
&& flow version

WORKDIR ${APP_HOME}
COPY . ${APP_HOME}
RUN chmod +x ${APP_HOME}/local/*.sh

# Pre-install Cadence dependencies at build time (source resolution only;
# mainnet fork state is fetched at container startup, not here)
RUN flow deps install --skip-alias --skip-deployments

EXPOSE 3569 8888

# Runtime: start emulator forked from mainnet.
# The fork state is fetched from access.mainnet.nodes.onflow.org at startup.
#ENTRYPOINT ["flow", "emulator", "--fork", "mainnet", "--fork-height", "147329485", "--persist=false"]
ENTRYPOINT ["flow", "emulator", "--fork", "mainnet", "--persist=false"]
35 changes: 35 additions & 0 deletions cadence/tests/transactions/setup_ft_vault.cdc
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import "FungibleToken"
import "FungibleTokenMetadataViews"
import "ViewResolver"

/// Sets up a FungibleToken vault in the signer's storage if not already present,
/// publishing the standard receiver and metadata capabilities.
/// Works with any FT that implements FungibleTokenMetadataViews (including EVMVMBridgedTokens).
///
/// @param contractAddress Address of the token contract (e.g. 0x1e4aa0b87d10b141)
/// @param contractName Name of the token contract

transaction(contractAddress: Address, contractName: String) {
prepare(signer: auth(Storage, Capabilities) &Account) {
let viewResolver = getAccount(contractAddress).contracts.borrow<&{ViewResolver}>(name: contractName)
?? panic("Cannot borrow ViewResolver for ".concat(contractName))

let vaultData = viewResolver.resolveContractView(
resourceType: nil,
viewType: Type<FungibleTokenMetadataViews.FTVaultData>()
) as! FungibleTokenMetadataViews.FTVaultData?
?? panic("Cannot resolve FTVaultData for ".concat(contractName))

if signer.storage.borrow<&{FungibleToken.Vault}>(from: vaultData.storagePath) != nil {
return // already set up
}

signer.storage.save(<-vaultData.createEmptyVault(), to: vaultData.storagePath)
signer.capabilities.unpublish(vaultData.receiverPath)
signer.capabilities.unpublish(vaultData.metadataPath)
let receiverCap = signer.capabilities.storage.issue<&{FungibleToken.Vault}>(vaultData.storagePath)
let metadataCap = signer.capabilities.storage.issue<&{FungibleToken.Vault}>(vaultData.storagePath)
signer.capabilities.publish(receiverCap, at: vaultData.receiverPath)
signer.capabilities.publish(metadataCap, at: vaultData.metadataPath)
}
}
41 changes: 41 additions & 0 deletions cadence/tests/transactions/transfer_ft_via_vault_data.cdc
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import "FungibleToken"
import "FungibleTokenMetadataViews"
import "ViewResolver"

/// Generic FungibleToken transfer that resolves storage/receiver paths via FTVaultData.
/// Works with any FT implementing FungibleTokenMetadataViews (including EVMVMBridgedTokens).
///
/// @param contractAddress Address of the token contract (e.g. 0x1e4aa0b87d10b141)
/// @param contractName Name of the token contract (e.g. EVMVMBridgedToken_99af3eea856556646c98c8b9b2548fe815240750)
/// @param amount Amount to transfer
/// @param to Recipient Cadence address (must already have receiver capability published)

transaction(contractAddress: Address, contractName: String, amount: UFix64, to: Address) {

let sentVault: @{FungibleToken.Vault}
let receiverPath: PublicPath

prepare(signer: auth(BorrowValue) &Account) {
let viewResolver = getAccount(contractAddress).contracts.borrow<&{ViewResolver}>(name: contractName)
?? panic("Cannot borrow ViewResolver for ".concat(contractName))

let vaultData = viewResolver.resolveContractView(
resourceType: nil,
viewType: Type<FungibleTokenMetadataViews.FTVaultData>()
) as! FungibleTokenMetadataViews.FTVaultData?
?? panic("Cannot resolve FTVaultData for ".concat(contractName))

let vaultRef = signer.storage.borrow<auth(FungibleToken.Withdraw) &{FungibleToken.Vault}>(
from: vaultData.storagePath
) ?? panic("Cannot borrow vault from ".concat(vaultData.storagePath.toString()))

self.sentVault <- vaultRef.withdraw(amount: amount)
self.receiverPath = vaultData.receiverPath
}

execute {
let receiverRef = getAccount(to).capabilities.borrow<&{FungibleToken.Receiver}>(self.receiverPath)
?? panic("Cannot borrow receiver at ".concat(self.receiverPath.toString()))
receiverRef.deposit(from: <-self.sentVault)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import "FlowYieldVaultsClosedBeta"

/// Single-signer variant: admin grants beta access to their own account.
/// Use when the admin is also the test user (avoids multi-sig complexity in shell scripts).
transaction() {
prepare(admin: auth(BorrowValue, Storage) &Account) {
let handle = admin.storage.borrow<auth(FlowYieldVaultsClosedBeta.Admin) &FlowYieldVaultsClosedBeta.AdminHandle>(
from: FlowYieldVaultsClosedBeta.AdminHandleStoragePath
) ?? panic("Missing AdminHandle at AdminHandleStoragePath")

let cap: Capability<auth(FlowYieldVaultsClosedBeta.Beta) &FlowYieldVaultsClosedBeta.BetaBadge> =
handle.grantBeta(addr: admin.address)

let p = FlowYieldVaultsClosedBeta.UserBetaCapStoragePath

if let t = admin.storage.type(at: p) {
if t == Type<Capability<auth(FlowYieldVaultsClosedBeta.Beta) &FlowYieldVaultsClosedBeta.BetaBadge>>() {
let _ = admin.storage.load<Capability<auth(FlowYieldVaultsClosedBeta.Beta) &FlowYieldVaultsClosedBeta.BetaBadge>>(from: p)
} else {
panic("Unexpected type at UserBetaCapStoragePath: ".concat(t.identifier))
}
}
admin.storage.save(cap, to: p)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import "FlowALPv0"
import "BandOracleConnectors"
import "DeFiActions"
import "FungibleTokenConnectors"
import "FungibleToken"

/// Updates the FlowALP pool's price oracle with a larger staleThreshold.
///
/// Use in fork testing environments where Band oracle data may be up to
/// several hours old. The emulator fork uses mainnet state at a fixed
/// height; as real time advances the oracle data becomes stale.
///
/// @param staleThreshold: seconds beyond which oracle data is considered stale
/// Use 86400 (24h) for long-running fork test sessions.
///
/// Must be signed by the FlowALP pool owner (6b00ff876c299c61).
/// In fork mode, signature validation is disabled, so any key can be used.
transaction(staleThreshold: UInt64) {
let pool: auth(FlowALPv0.EGovernance) &FlowALPv0.Pool
let oracle: {DeFiActions.PriceOracle}

prepare(signer: auth(BorrowValue, IssueStorageCapabilityController) &Account) {
self.pool = signer.storage.borrow<auth(FlowALPv0.EGovernance) &FlowALPv0.Pool>(from: FlowALPv0.PoolStoragePath)
?? panic("Could not borrow reference to Pool from \(FlowALPv0.PoolStoragePath)")
let defaultToken = self.pool.getDefaultToken()

let vaultCap = signer.capabilities.storage.issue<auth(FungibleToken.Withdraw) &{FungibleToken.Vault}>(/storage/flowTokenVault)
let feeSource = FungibleTokenConnectors.VaultSource(min: nil, withdrawVault: vaultCap, uniqueID: nil)
self.oracle = BandOracleConnectors.PriceOracle(
unitOfAccount: defaultToken,
staleThreshold: staleThreshold,
feeSource: feeSource,
uniqueID: nil,
)
}

execute {
self.pool.setPriceOracle(self.oracle)
log("FlowALP oracle staleThreshold updated to \(staleThreshold)s")
}
}
25 changes: 14 additions & 11 deletions flow.json
Original file line number Diff line number Diff line change
Expand Up @@ -1077,7 +1077,6 @@
"type": "file",
"location": "local/emulator-account.pkey"
}

},
"testnet-flow-alp-deployer": {
"address": "426f0458ced60037",
Expand All @@ -1086,6 +1085,20 @@
"hashAlgorithm": "SHA2_256",
"resourceID": "projects/dl-flow-devex-staging/locations/us-central1/keyRings/tidal-keyring/cryptoKeys/tidal_admin_pk/cryptoKeyVersions/1"
}
},
"mainnet-fork-flowalp": {
"address": "6b00ff876c299c61",
"key": {
"type": "file",
"location": "local/emulator-account.pkey"
}
},
"mainnet-fork-pyusd0-donor": {
"address": "443472749ebdaac8",
"key": {
"type": "file",
"location": "local/emulator-account.pkey"
}
}
},
"deployments": {
Expand Down Expand Up @@ -1248,16 +1261,6 @@
},
"mainnet-fork": {
"mainnet-fork-admin": [
{
"name": "MockOracle",
"args": [
{
"value": "A.6b00ff876c299c61.MOET.Vault",
"type": "String"
}
]
},
"MockSwapper",
"UInt64LinkedList",
"AutoBalancers",
"FlowYieldVaultsSchedulerRegistry",
Expand Down
Loading
Loading