Skip to content
Merged
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
33 changes: 33 additions & 0 deletions packages/komodo_defi_framework/app_build/BUILD_CONFIG_README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,39 @@ Paths in the config are relative to that package directory.
- Use `--concurrent` for faster downloads in development
- Override behavior per build via env `OVERRIDE_DEFI_API_DOWNLOAD=true|false`

### Using Nebula mirror and short commit hashes

- You can add Nebula as an additional source in `api.source_urls`:

```
"source_urls": [
"https://api.github.com/repos/KomodoPlatform/komodo-defi-framework",
"https://sdk.devbuilds.komodo.earth/",
"https://nebula.decker.im/kdf/"
]
```

- The downloader expects branch-scoped directory listings (e.g., `.../dev/`) on both devbuilds and Nebula mirrors and will fallback to the base listing when available. It searches for artifacts that match the platform patterns and contain either the full commit hash or a 7-char short hash.
- To pin a specific commit (e.g., `4025b8c`) without changing branches, update `api.api_commit_hash` or use the CLI with `--commit`:

```bash
dart run packages/komodo_wallet_cli/bin/update_api_config.dart \
--source mirror \
--mirror-url https://nebula.decker.im/ \
--commit 4025b8c \
--config packages/komodo_defi_framework/app_build/build_config.json \
--output-dir packages/komodo_defi_framework/app_build/temp_downloads \
--verbose
```

- To switch to a different Nebula commit in the future, either:
- Edit `api.api_commit_hash` in `build_config.json` to the new short/full hash, or
- Re-run the CLI with a different `--commit <hash>` value.

Notes:
- Nebula index includes additional files like `komodo-wallet-*`; these are automatically ignored by the downloader.
- macOS on Nebula uses `kdf-macos-universal2-<hash>.zip` (special case handled in `matching_pattern`). Other platforms use `kdf_<hash>-<platform>.zip`.

## Troubleshooting

- Missing files: verify `config_output_path` points to this folder and the file exists
Expand Down
36 changes: 24 additions & 12 deletions packages/komodo_defi_framework/app_build/build_config.json
Original file line number Diff line number Diff line change
@@ -1,60 +1,72 @@
{
"api": {
"api_commit_hash": "476262f0d3390e24cfe672d5e15a78a46397dbfa",
"branch": "hotfix-remove-memorydb-size-metric",
"api_commit_hash": "8beb1196487550157f5616bf27808cb6d4ebf275",
"branch": "staging",
"fetch_at_build_enabled": true,
"concurrent_downloads_enabled": true,
"source_urls": [
"https://api.github.com/repos/KomodoPlatform/komodo-defi-framework",
"https://sdk.devbuilds.komodo.earth/"
"https://sdk.devbuilds.komodo.earth/",
"https://nebula.decker.im/"
],
"platforms": {
"web": {
"matching_pattern": "^(?:kdf_[a-f0-9]{7,40}-wasm|mm2_[a-f0-9]{7,40}-wasm|mm2-[a-f0-9]{7,40}-wasm)\\.zip$",
"valid_zip_sha256_checksums": [
"1ce88c3ef6ee4da3839b392e77d9f667a897c4b0b9f4459f878a1561193541a7"
"d7cfd4dfa47f455ee283aa02c4dd11542b4bcf349928ec5b07a1f20b7141bd65",
"d1ce6fa6e6dd2d11135fc054b802dc1aea4772af2ae5aef9acc4c3da6ffacd35"
],
"path": "web/kdf/bin"
},
"ios": {
"matching_pattern": "^(?:kdf_[a-f0-9]{7,40}-ios-aarch64|mm2_[a-f0-9]{7,40}-ios-aarch64|mm2-[a-f0-9]{7,40}-ios-aarch64-CI)\\.zip$",
"valid_zip_sha256_checksums": [
"68569c2bb3362dc94dd54b0e696559962fab8b29bd1203dd252078aeb1863ca3"
"49c26280232fadbe456fbdd1dacc2cfd7697272202e59e41612691e50376a347",
"57c77787ccab9cb0b7c54cfa0791a30210aa24a8548e66510d5871a6cae0b8a5"
],
"path": "ios"
},
"macos": {
"matching_pattern": "^(?:kdf_[a-f0-9]{7,40}-mac-arm64|mm2-[a-f0-9]{7,40}-Darwin-Release)\\.zip$",
"matching_pattern": "^(?:kdf_[a-f0-9]{7,40}-mac-arm64|kdf-macos-universal2-[a-f0-9]{7,40}|mm2-[a-f0-9]{7,40}-Darwin-Release)\\.zip$",
"matching_preference": [
"universal2",
"mac-arm64"
],
"valid_zip_sha256_checksums": [
"9613497ec79dab437251fb0c1ca6301c1b389325a01a8a979fde690d975c9902"
"30550ace9e66a1303ce3295ccd14f73759ff8fb56396419bd2d1d6e2da2cf54e",
"595de272b14ac52c6ee71ab442d355fc7f37b4a92f09198b575e5c44b796393f"
],
"path": "macos/bin"
},
"windows": {
"matching_pattern": "^(?:kdf_[a-f0-9]{7,40}-win-x86-64|mm2_[a-f0-9]{7,40}-win-x86-64|mm2-[a-f0-9]{7,40}-Win64)\\.zip$",
"valid_zip_sha256_checksums": [
"d25b417ef17685e439f6be9f1100dfa46b5e9b3ef646037066a5b5db0852f107"
"db77335c8637d03e467c2cbb275ea4e57962ca22ed29542941f7105e5ba69e9a",
"619816f62bfd984abf0c2fb83d9efc3fea60b7a305fd912df0ee6c46ab376135"
],
"path": "windows/bin"
},
"android-armv7": {
"matching_pattern": "^(?:kdf_[a-f0-9]{7,40}-android-armv7|mm2_[a-f0-9]{7,40}-android-armv7|mm2-[a-f0-9]{7,40}-android-armv7-CI)\\.zip$",
"valid_zip_sha256_checksums": [
"92e0d9515d3fb662bf90dc37802f901944d99b3c4b8e41566e6defacd59e213c"
"129f6f2467f14c9b7d9f7629d33d70197cb94b2237cbdb01a58e567a1b3260ee",
"5a393ce8dfb888d9edc3e4b24f42ac7f5f6f379cc14d9ac132f8cff37ab566d6"
],
"path": "android/app/src/main/cpp/libs/armeabi-v7a"
},
"android-aarch64": {
"matching_pattern": "^(?:kdf_[a-f0-9]{7,40}-android-aarch64|mm2_[a-f0-9]{7,40}-android-aarch64|mm2-[a-f0-9]{7,40}-android-aarch64-CI)\\.zip$",
"valid_zip_sha256_checksums": [
"4d6dc94ba31087180df09136c51bc61c75fd217e77889eb45ef40e0c6a34537f"
"00ea932edb7750c60c5d91705907b52ab018a7230f270a0f4286e41ee42cdf74",
"c0ee3ea7a6fe8f4410208b9b841fd90ebdf6a28b30696ead6c1d8c5dc4c0b13d"
],
"path": "android/app/src/main/cpp/libs/arm64-v8a"
},
"linux": {
"matching_pattern": "^(?:kdf_[a-f0-9]{7,40}-linux-x86-64|mm2_[a-f0-9]{7,40}-linux-x86-64|mm2-[a-f0-9]{7,40}-Linux-Release)\\.zip$",
"valid_zip_sha256_checksums": [
"7ab3d56bd0ad56e383903e3f0a444369f67b7945661f6fd0076a96b8d795cfbb"
"e25067ddb7b51455a109874722a595d7bc2ee4243ebd3af3e98426874d42f23d",
"93aa902af205fc2781c31e90e91688fff5aa63d9a26d77a21b1f95d934cccf75"
],
"path": "linux/bin"
}
Expand All @@ -63,7 +75,7 @@
"coins": {
"fetch_at_build_enabled": true,
"update_commit_on_build": true,
"bundled_coins_repo_commit": "f235190081e821996333c95e34b2629df331b333",
"bundled_coins_repo_commit": "fdc6c7312b2c7da1b4b904103ed30445311072eb",
"coins_repo_api_url": "https://api.github.com/repos/KomodoPlatform/coins",
"coins_repo_content_url": "https://raw.githubusercontent.com/KomodoPlatform/coins",
"coins_repo_branch": "master",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,55 @@ A new Flutter FFI plugin project.
echo "Warning: libkdflib.dylib not found in lib/libkdflib.dylib"
fi

# Prune binary slices to match $ARCHS (preserve universals) in Release builds only
if [ "$CONFIGURATION" = "Release" ]; then
TARGET_ARCHS="${ARCHS:-$(arch)}"

thin_binary_to_archs() {
file="$1"
keep_archs="$2"

[ -f "$file" ] || return 0

# Only act on fat files (multi-arch)
if ! lipo -info "$file" | grep -q 'Architectures in the fat file'; then
return 0
fi

bin_archs="$(lipo -archs "$file" 2>/dev/null || true)"
[ -n "$bin_archs" ] || return 0

dir="$(dirname "$file")"
base="$(basename "$file")"
work="$file"

for arch in $bin_archs; do
echo "$keep_archs" | tr ' ' '\n' | grep -qx "$arch" && continue
echo "Removing architecture $arch from $base"
next="$(mktemp "$dir/.${base}.XXXXXX")"
lipo "$work" -remove "$arch" -output "$next"
[ "$work" != "$file" ] && rm -f "$work"
work="$next"
done

if [ "$work" != "$file" ]; then
mv -f "$work" "$file"
fi
}

thin_binary_to_archs "$APP_SUPPORT_DIR/kdf" "$TARGET_ARCHS"
if [ -f "$APP_SUPPORT_DIR/kdf" ]; then chmod +x "$APP_SUPPORT_DIR/kdf"; fi

thin_binary_to_archs "$FRAMEWORKS_DIR/libkdflib.dylib" "$TARGET_ARCHS"
if [ -f "$FRAMEWORKS_DIR/libkdflib.dylib" ]; then install_name_tool -id "@rpath/libkdflib.dylib" "$FRAMEWORKS_DIR/libkdflib.dylib"; fi

# Re-sign after modifications (best-effort)
if [ -n "$EXPANDED_CODE_SIGN_IDENTITY" ]; then
codesign --force --sign "$EXPANDED_CODE_SIGN_IDENTITY" "$APP_SUPPORT_DIR/kdf" 2>/dev/null || true
codesign --force --sign "$EXPANDED_CODE_SIGN_IDENTITY" "$FRAMEWORKS_DIR/libkdflib.dylib" 2>/dev/null || true
fi
fi
Comment thread
cursor[bot] marked this conversation as resolved.

# Fail if neither file was found
if [ $FOUND_REQUIRED_FILE -eq 0 ]; then
echo "Error: Neither kdf executable nor libkdflib.dylib was found. At least one is required."
Expand All @@ -71,7 +120,7 @@ A new Flutter FFI plugin project.
# Configuration for macOS build
s.pod_target_xcconfig = {
'DEFINES_MODULE' => 'YES',
'EXCLUDED_ARCHS[sdk=macosx*]' => 'i386 x86_64',
# Allow building universal macOS apps (arm64 + x86_64). i386 remains excluded by default Xcode settings.
'OTHER_LDFLAGS' => '-framework SystemConfiguration',
# Add rpath to ensure dylib can be found at runtime
'LD_RUNPATH_SEARCH_PATHS' => [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ A new Flutter FFI plugin project.
# s.pod_target_xcconfig = { "OTHER_LDFLAGS" => "$(inherited) -force_load $(PODS_TARGET_SRCROOT)/Frameworks/libkdflib.a -lstdc++" }
s.pod_target_xcconfig = {
'DEFINES_MODULE' => 'YES',
'EXCLUDED_ARCHS[sdk=macosx*]' => 'i386 x86_64',
# Allow building universal macOS apps (arm64 + x86_64). i386 remains excluded by default Xcode settings.
'OTHER_LDFLAGS' => '-force_load $(PODS_TARGET_SRCROOT)/Frameworks/libkdflib.a -lstdc++ -framework SystemConfiguration'
}

Expand Down
2 changes: 1 addition & 1 deletion packages/komodo_defi_sdk/example/macos/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ EXTERNAL SOURCES:
SPEC CHECKSUMS:
flutter_secure_storage_darwin: ce237a8775b39723566dc72571190a3769d70468
FlutterMacOS: d0db08ddef1a9af05a5ec4b724367152bb0500b1
komodo_defi_framework: 725599127b357521f4567b16192bf07d7ad1d4b0
komodo_defi_framework: 2b0389a26ed9c574c3665b257bcb3ef147fe5345
local_auth_darwin: d2e8c53ef0c4f43c646462e3415432c4dab3ae19
mobile_scanner: 9157936403f5a0644ca3779a38ff8404c5434a93
path_provider_foundation: 080d55be775b7414fd5a5ef3ac137b97b097e564
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict/>
</plist>
Original file line number Diff line number Diff line change
Expand Up @@ -30,42 +30,84 @@ class DevBuildsArtefactDownloader implements ArtefactDownloader {
ApiFileMatchingConfig matchingConfig,
String platform,
) async {
final url = '$sourceUrl/$apiBranch/';
final response = await http.get(Uri.parse(url));
response.throwIfNotSuccessResponse();
// Try both branch-scoped and base-scoped listings to support different mirrors
final normalizedSource = sourceUrl.endsWith('/')
? sourceUrl
: '$sourceUrl/';
final baseUri = Uri.parse(normalizedSource);
final candidateListingUrls = <Uri>{
if (apiBranch.isNotEmpty) baseUri.resolve('$apiBranch/'),
baseUri,
};

final document = parser.parse(response.body);
final extensions = ['.zip'];

// Support both full and short hash variants
final fullHash = apiCommitHash;
final shortHash = apiCommitHash.substring(0, 7);
_log.info('Looking for files with hash $fullHash or $shortHash');

// Look for files with either hash length
final attemptedFiles = <String>[];
for (final element in document.querySelectorAll('a')) {
final href = element.attributes['href'];
if (href != null) attemptedFiles.add(href);
if (href != null &&
matchingConfig.matches(href) &&
extensions.any(href.endsWith)) {
if (href.contains(fullHash) || href.contains(shortHash)) {
_log.info('Found matching file: $href');
return '$sourceUrl/$apiBranch/$href';
for (final listingUrl in candidateListingUrls) {
try {
final response = await http.get(listingUrl);
response.throwIfNotSuccessResponse();
final document = parser.parse(response.body);

final attemptedFiles = <String>[];
final resolvedCandidates =
<String, String>{}; // fileName -> resolvedUrl
for (final element in document.querySelectorAll('a')) {
final href = element.attributes['href'];
if (href == null) continue;
attemptedFiles.add(href);

// Normalize href for directory indexes that include absolute paths
final hrefPath = Uri.tryParse(href)?.path ?? href;
final fileName = path.basename(hrefPath);

// Ignore wallet archives on Nebula index
if (fileName.contains('wallet')) {
Comment thread
CharlVS marked this conversation as resolved.
continue;
}

final matches =
matchingConfig.matches(fileName) &&
extensions.any(hrefPath.endsWith);
if (matches) {
final containsHash =
hrefPath.contains(fullHash) || hrefPath.contains(shortHash);
if (containsHash) {
// Build absolute URL respecting whether href is absolute or relative
final resolvedUrl = href.startsWith('http')
? href
: listingUrl.resolve(href).toString();
resolvedCandidates[fileName] = resolvedUrl;
}
}
}

if (resolvedCandidates.isNotEmpty) {
final preferred = matchingConfig.choosePreferred(
resolvedCandidates.keys,
);
final url =
resolvedCandidates[preferred] ?? resolvedCandidates.values.first;
_log.info('Selected file: $preferred at $listingUrl');
return url;
}

_log.fine(
'No matching files found in $listingUrl. '
'\nPattern: ${matchingConfig.matchingPattern}, '
'\nHashes tried: [$fullHash, $shortHash]'
'\nAvailable assets: ${attemptedFiles.join('\n')}',
);
} catch (e) {
_log.fine('Failed to query listing $listingUrl: $e');
}
}

final availableAssets = attemptedFiles.join('\n');
_log.fine(
'No matching files found in $sourceUrl. '
'\nPattern: ${matchingConfig.matchingPattern}, '
'\nHashes tried: [$fullHash, $shortHash]'
'\nAvailable assets: $availableAssets',
throw Exception(
'Zip file not found for platform $platform from $sourceUrl',
);

throw Exception('Zip file not found for platform $platform');
}

@override
Expand Down Expand Up @@ -106,10 +148,12 @@ class DevBuildsArtefactDownloader implements ArtefactDownloader {
// Determine the platform to use the appropriate extraction command
if (Platform.isMacOS || Platform.isLinux) {
// For macOS and Linux, use the `unzip` command with overwrite option
final result = await Process.run(
'unzip',
['-o', filePath, '-d', destinationFolder],
);
final result = await Process.run('unzip', [
'-o',
filePath,
'-d',
destinationFolder,
]);
if (result.exitCode != 0) {
throw Exception('Error extracting zip file: ${result.stderr}');
}
Expand Down
Loading
Loading