[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"article-testing-kontrak-huff-foundry-fork-test-asersi-gas":3},{"article":4,"author":58},{"id":5,"category_id":6,"title":7,"slug":8,"excerpt":9,"content_md":10,"content_html":11,"locale":12,"author_id":13,"published":14,"published_at":15,"meta_title":7,"meta_description":16,"focus_keyword":17,"og_image":18,"canonical_url":18,"robots_meta":19,"created_at":15,"updated_at":15,"tags":20,"category_name":38,"related_articles":39},"d2000000-0000-0000-0000-000000000117","a0000000-0000-0000-0000-000000000022","Testing Kontrak Huff dengan Foundry Fork Test dan Asersi Gas","testing-kontrak-huff-foundry-fork-test-asersi-gas","Panduan lengkap testing kontrak Huff menggunakan Foundry: fork test terhadap mainnet, asersi gas untuk regresi, dan integrasi dengan foundry-huff untuk deployment test.","## Mengapa Testing Kontrak Huff Berbeda\n\nKontrak Huff beroperasi di tingkat opcode mentah — tanpa pemeriksaan overflow, tanpa revert message, tanpa guardrail Solidity. Ini berarti testing menjadi lebih kritis: satu kesalahan stack akan menyebabkan perilaku yang tidak terduga tanpa error message yang berguna.\n\nFoundry adalah framework testing terbaik untuk kontrak Huff karena:\n1. **foundry-huff** — Plugin yang mengkompilasi dan men-deploy file `.huff` dalam test Solidity\n2. **Fork testing** — Simulasikan terhadap state mainnet nyata\n3. **Gas reporting** — Lacak biaya gas per fungsi\n4. **Fuzzing** — Temukan edge case dengan input acak\n\n## Setup foundry-huff\n\n```bash\nforge install huff-language\u002Ffoundry-huff\n```\n\nTambahkan ke `foundry.toml`:\n```toml\n[profile.default]\nffi = true  # Diperlukan untuk kompilasi Huff\n```\n\nContoh deployment di test:\n```solidity\nimport {HuffDeployer} from \"foundry-huff\u002FHuffDeployer.sol\";\n\ncontract MyHuffTest is Test {\n    address public target;\n    \n    function setUp() public {\n        target = HuffDeployer.deploy(\"src\u002FMyContract\");\n    }\n    \n    function testBasicFunction() public {\n        (bool ok, bytes memory data) = target.call(\n            abi.encodeWithSignature(\"getValue()\")\n        );\n        assertTrue(ok);\n        uint256 value = abi.decode(data, (uint256));\n        assertEq(value, 42);\n    }\n}\n```\n\n## Fork Testing Terhadap Mainnet\n\nFork test memungkinkan Anda menguji kontrak Huff terhadap state blockchain nyata — termasuk token balance, pool reserves, dan harga oracle.\n\n```solidity\ncontract ForkTest is Test {\n    address constant WETH = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;\n    address constant USDC = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48;\n    address constant UNISWAP_PAIR = 0xB4e16d0168e52d35CaCD2c6185b44281Ec28C9Dc;\n    \n    address bot;\n    \n    function setUp() public {\n        \u002F\u002F Fork mainnet pada block tertentu\n        vm.createSelectFork(\"mainnet\", 18_000_000);\n        bot = HuffDeployer.deploy(\"src\u002FSwapBot\");\n        \n        \u002F\u002F Berikan WETH ke bot\n        deal(WETH, bot, 10 ether);\n    }\n    \n    function testSwapExactIn() public {\n        uint256 balanceBefore = IERC20(USDC).balanceOf(address(this));\n        \n        \u002F\u002F Panggil bot untuk swap WETH -> USDC\n        (bool ok,) = bot.call(\n            abi.encodePacked(\n                uint8(0x01),      \u002F\u002F opcode: swapExactIn\n                uint256(1 ether)  \u002F\u002F amount\n            )\n        );\n        assertTrue(ok, \"Swap gagal\");\n        \n        uint256 balanceAfter = IERC20(USDC).balanceOf(address(this));\n        assertGt(balanceAfter, balanceBefore, \"Tidak menerima USDC\");\n    }\n}\n```\n\n### Keuntungan Fork Testing\n- **State nyata** — Reserves pool, oracle price, token balance semuanya nyata\n- **Reprodusibilitas** — Pin ke block tertentu untuk hasil deterministik\n- **Edge case** — Temukan masalah dengan token non-standar (USDT, rebase token)\n\n## Asersi Gas\n\nUntuk kontrak Huff, gas adalah metrik kualitas utama. Foundry menyediakan snapshot gas:\n\n```solidity\nfunction testGasSwap() public {\n    uint256 gasBefore = gasleft();\n    \n    (bool ok,) = bot.call(\n        abi.encodePacked(uint8(0x01), uint256(1 ether))\n    );\n    assertTrue(ok);\n    \n    uint256 gasUsed = gasBefore - gasleft();\n    \n    \u002F\u002F Asersi batas gas\n    assertLt(gasUsed, 80_000, \"Swap melebihi batas gas\");\n    \n    \u002F\u002F Snapshot untuk tracking regresi\n    emit log_named_uint(\"Gas swap\", gasUsed);\n}\n```\n\n### Gas Snapshot untuk CI\u002FCD\n```bash\n# Buat snapshot awal\nforge snapshot\n\n# Bandingkan dengan snapshot sebelumnya\nforge snapshot --diff\n```\n\nOutput menunjukkan fungsi mana yang gas-nya berubah:\n```\ntestGasSwap() (gas: -150) ✓\ntestGasTransfer() (gas: +30) ⚠\n```\n\n## Fuzzing Kontrak Huff\n\nFuzzing sangat penting untuk kontrak Huff karena tidak ada pemeriksaan otomatis:\n\n```solidity\nfunction testFuzz_SwapAmount(uint256 amount) public {\n    \u002F\u002F Batasi input ke range yang masuk akal\n    amount = bound(amount, 0.001 ether, 100 ether);\n    deal(WETH, bot, amount);\n    \n    (bool ok,) = bot.call(\n        abi.encodePacked(uint8(0x01), amount)\n    );\n    \n    \u002F\u002F Swap harus selalu berhasil untuk jumlah yang valid\n    assertTrue(ok, \"Swap gagal untuk jumlah valid\");\n}\n\nfunction testFuzz_InvalidCalldata(bytes calldata data) public {\n    \u002F\u002F Kontrak harus menangani calldata invalid dengan baik\n    (bool ok,) = bot.call(data);\n    \u002F\u002F Boleh gagal, tetapi tidak boleh hang atau berperilaku aneh\n    \u002F\u002F Verifikasi state tidak berubah\n}\n```\n\nJalankan dengan iterasi tinggi:\n```bash\nforge test --match-test testFuzz -vvv --fuzz-runs 10000\n```\n\n## Testing Asersi Stack\n\nUntuk memverifikasi bahwa makro Huff menangani stack dengan benar:\n\n```solidity\nfunction testStackBalance() public {\n    \u002F\u002F Test bahwa kontrak mengembalikan nilai yang benar\n    \u002F\u002F untuk berbagai input — jika stack tidak seimbang,\n    \u002F\u002F hasilnya akan salah\n    for (uint256 i = 0; i \u003C 100; i++) {\n        (bool ok, bytes memory data) = target.call(\n            abi.encodeWithSignature(\"compute(uint256)\", i)\n        );\n        assertTrue(ok);\n        uint256 result = abi.decode(data, (uint256));\n        assertEq(result, expectedResult(i));\n    }\n}\n```\n\n## Testing Keamanan\n\n```solidity\nfunction testReentrancy() public {\n    \u002F\u002F Deploy kontrak penyerang yang mencoba reentrancy\n    Attacker attacker = new Attacker(bot);\n    \n    \u002F\u002F Berikan dana ke attacker\n    deal(WETH, address(attacker), 10 ether);\n    \n    \u002F\u002F Serangan harus gagal\n    vm.expectRevert();\n    attacker.attack();\n}\n\nfunction testUnauthorizedAccess() public {\n    \u002F\u002F Panggil fungsi admin dari non-operator\n    vm.prank(address(0xdead));\n    (bool ok,) = bot.call(\n        abi.encodePacked(uint8(0x03))  \u002F\u002F withdraw\n    );\n    assertFalse(ok, \"Non-operator berhasil memanggil withdraw\");\n}\n```\n\n## Best Practice Testing Huff\n\n1. **100% path coverage** — Test setiap cabang JUMPI di kontrak\n2. **Boundary testing** — Test dengan 0, 1, MAX_UINT256, dan nilai batas lainnya\n3. **Gas regression** — Jalankan gas snapshot di CI untuk mendeteksi regresi\n4. **Fork test** — Selalu test terhadap state mainnet nyata\n5. **Fuzzing** — Minimal 10.000 iterasi per fungsi\n6. **Negative testing** — Verifikasi bahwa calldata invalid ditangani dengan benar\n7. **Dokumentasi test** — Setiap test harus menjelaskan skenario apa yang diverifikasi\n\n## Kesimpulan\n\nTesting kontrak Huff memerlukan pendekatan yang lebih ketat dari testing Solidity karena tidak ada safety net. Foundry dengan foundry-huff memberikan toolchain lengkap: fork testing untuk akurasi state, asersi gas untuk regresi, dan fuzzing untuk edge case. Investasi dalam test suite yang komprehensif membayar dirinya sendiri dengan mencegah bug yang mahal di produksi.","\u003Ch2 id=\"mengapa-testing-kontrak-huff-berbeda\">Mengapa Testing Kontrak Huff Berbeda\u003C\u002Fh2>\n\u003Cp>Kontrak Huff beroperasi di tingkat opcode mentah — tanpa pemeriksaan overflow, tanpa revert message, tanpa guardrail Solidity. Ini berarti testing menjadi lebih kritis: satu kesalahan stack akan menyebabkan perilaku yang tidak terduga tanpa error message yang berguna.\u003C\u002Fp>\n\u003Cp>Foundry adalah framework testing terbaik untuk kontrak Huff karena:\u003C\u002Fp>\n\u003Col>\n\u003Cli>\u003Cstrong>foundry-huff\u003C\u002Fstrong> — Plugin yang mengkompilasi dan men-deploy file \u003Ccode>.huff\u003C\u002Fcode> dalam test Solidity\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Fork testing\u003C\u002Fstrong> — Simulasikan terhadap state mainnet nyata\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Gas reporting\u003C\u002Fstrong> — Lacak biaya gas per fungsi\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Fuzzing\u003C\u002Fstrong> — Temukan edge case dengan input acak\u003C\u002Fli>\n\u003C\u002Fol>\n\u003Ch2 id=\"setup-foundry-huff\">Setup foundry-huff\u003C\u002Fh2>\n\u003Cpre>\u003Ccode class=\"language-bash\">forge install huff-language\u002Ffoundry-huff\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Tambahkan ke \u003Ccode>foundry.toml\u003C\u002Fcode>:\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-toml\">[profile.default]\nffi = true  # Diperlukan untuk kompilasi Huff\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Contoh deployment di test:\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-solidity\">import {HuffDeployer} from \"foundry-huff\u002FHuffDeployer.sol\";\n\ncontract MyHuffTest is Test {\n    address public target;\n    \n    function setUp() public {\n        target = HuffDeployer.deploy(\"src\u002FMyContract\");\n    }\n    \n    function testBasicFunction() public {\n        (bool ok, bytes memory data) = target.call(\n            abi.encodeWithSignature(\"getValue()\")\n        );\n        assertTrue(ok);\n        uint256 value = abi.decode(data, (uint256));\n        assertEq(value, 42);\n    }\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch2 id=\"fork-testing-terhadap-mainnet\">Fork Testing Terhadap Mainnet\u003C\u002Fh2>\n\u003Cp>Fork test memungkinkan Anda menguji kontrak Huff terhadap state blockchain nyata — termasuk token balance, pool reserves, dan harga oracle.\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-solidity\">contract ForkTest is Test {\n    address constant WETH = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;\n    address constant USDC = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48;\n    address constant UNISWAP_PAIR = 0xB4e16d0168e52d35CaCD2c6185b44281Ec28C9Dc;\n    \n    address bot;\n    \n    function setUp() public {\n        \u002F\u002F Fork mainnet pada block tertentu\n        vm.createSelectFork(\"mainnet\", 18_000_000);\n        bot = HuffDeployer.deploy(\"src\u002FSwapBot\");\n        \n        \u002F\u002F Berikan WETH ke bot\n        deal(WETH, bot, 10 ether);\n    }\n    \n    function testSwapExactIn() public {\n        uint256 balanceBefore = IERC20(USDC).balanceOf(address(this));\n        \n        \u002F\u002F Panggil bot untuk swap WETH -&gt; USDC\n        (bool ok,) = bot.call(\n            abi.encodePacked(\n                uint8(0x01),      \u002F\u002F opcode: swapExactIn\n                uint256(1 ether)  \u002F\u002F amount\n            )\n        );\n        assertTrue(ok, \"Swap gagal\");\n        \n        uint256 balanceAfter = IERC20(USDC).balanceOf(address(this));\n        assertGt(balanceAfter, balanceBefore, \"Tidak menerima USDC\");\n    }\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch3>Keuntungan Fork Testing\u003C\u002Fh3>\n\u003Cul>\n\u003Cli>\u003Cstrong>State nyata\u003C\u002Fstrong> — Reserves pool, oracle price, token balance semuanya nyata\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Reprodusibilitas\u003C\u002Fstrong> — Pin ke block tertentu untuk hasil deterministik\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Edge case\u003C\u002Fstrong> — Temukan masalah dengan token non-standar (USDT, rebase token)\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Ch2 id=\"asersi-gas\">Asersi Gas\u003C\u002Fh2>\n\u003Cp>Untuk kontrak Huff, gas adalah metrik kualitas utama. Foundry menyediakan snapshot gas:\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-solidity\">function testGasSwap() public {\n    uint256 gasBefore = gasleft();\n    \n    (bool ok,) = bot.call(\n        abi.encodePacked(uint8(0x01), uint256(1 ether))\n    );\n    assertTrue(ok);\n    \n    uint256 gasUsed = gasBefore - gasleft();\n    \n    \u002F\u002F Asersi batas gas\n    assertLt(gasUsed, 80_000, \"Swap melebihi batas gas\");\n    \n    \u002F\u002F Snapshot untuk tracking regresi\n    emit log_named_uint(\"Gas swap\", gasUsed);\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch3>Gas Snapshot untuk CI\u002FCD\u003C\u002Fh3>\n\u003Cpre>\u003Ccode class=\"language-bash\"># Buat snapshot awal\nforge snapshot\n\n# Bandingkan dengan snapshot sebelumnya\nforge snapshot --diff\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Output menunjukkan fungsi mana yang gas-nya berubah:\u003C\u002Fp>\n\u003Cpre>\u003Ccode>testGasSwap() (gas: -150) ✓\ntestGasTransfer() (gas: +30) ⚠\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch2 id=\"fuzzing-kontrak-huff\">Fuzzing Kontrak Huff\u003C\u002Fh2>\n\u003Cp>Fuzzing sangat penting untuk kontrak Huff karena tidak ada pemeriksaan otomatis:\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-solidity\">function testFuzz_SwapAmount(uint256 amount) public {\n    \u002F\u002F Batasi input ke range yang masuk akal\n    amount = bound(amount, 0.001 ether, 100 ether);\n    deal(WETH, bot, amount);\n    \n    (bool ok,) = bot.call(\n        abi.encodePacked(uint8(0x01), amount)\n    );\n    \n    \u002F\u002F Swap harus selalu berhasil untuk jumlah yang valid\n    assertTrue(ok, \"Swap gagal untuk jumlah valid\");\n}\n\nfunction testFuzz_InvalidCalldata(bytes calldata data) public {\n    \u002F\u002F Kontrak harus menangani calldata invalid dengan baik\n    (bool ok,) = bot.call(data);\n    \u002F\u002F Boleh gagal, tetapi tidak boleh hang atau berperilaku aneh\n    \u002F\u002F Verifikasi state tidak berubah\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Jalankan dengan iterasi tinggi:\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-bash\">forge test --match-test testFuzz -vvv --fuzz-runs 10000\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch2 id=\"testing-asersi-stack\">Testing Asersi Stack\u003C\u002Fh2>\n\u003Cp>Untuk memverifikasi bahwa makro Huff menangani stack dengan benar:\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-solidity\">function testStackBalance() public {\n    \u002F\u002F Test bahwa kontrak mengembalikan nilai yang benar\n    \u002F\u002F untuk berbagai input — jika stack tidak seimbang,\n    \u002F\u002F hasilnya akan salah\n    for (uint256 i = 0; i &lt; 100; i++) {\n        (bool ok, bytes memory data) = target.call(\n            abi.encodeWithSignature(\"compute(uint256)\", i)\n        );\n        assertTrue(ok);\n        uint256 result = abi.decode(data, (uint256));\n        assertEq(result, expectedResult(i));\n    }\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch2 id=\"testing-keamanan\">Testing Keamanan\u003C\u002Fh2>\n\u003Cpre>\u003Ccode class=\"language-solidity\">function testReentrancy() public {\n    \u002F\u002F Deploy kontrak penyerang yang mencoba reentrancy\n    Attacker attacker = new Attacker(bot);\n    \n    \u002F\u002F Berikan dana ke attacker\n    deal(WETH, address(attacker), 10 ether);\n    \n    \u002F\u002F Serangan harus gagal\n    vm.expectRevert();\n    attacker.attack();\n}\n\nfunction testUnauthorizedAccess() public {\n    \u002F\u002F Panggil fungsi admin dari non-operator\n    vm.prank(address(0xdead));\n    (bool ok,) = bot.call(\n        abi.encodePacked(uint8(0x03))  \u002F\u002F withdraw\n    );\n    assertFalse(ok, \"Non-operator berhasil memanggil withdraw\");\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch2 id=\"best-practice-testing-huff\">Best Practice Testing Huff\u003C\u002Fh2>\n\u003Col>\n\u003Cli>\u003Cstrong>100% path coverage\u003C\u002Fstrong> — Test setiap cabang JUMPI di kontrak\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Boundary testing\u003C\u002Fstrong> — Test dengan 0, 1, MAX_UINT256, dan nilai batas lainnya\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Gas regression\u003C\u002Fstrong> — Jalankan gas snapshot di CI untuk mendeteksi regresi\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Fork test\u003C\u002Fstrong> — Selalu test terhadap state mainnet nyata\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Fuzzing\u003C\u002Fstrong> — Minimal 10.000 iterasi per fungsi\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Negative testing\u003C\u002Fstrong> — Verifikasi bahwa calldata invalid ditangani dengan benar\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Dokumentasi test\u003C\u002Fstrong> — Setiap test harus menjelaskan skenario apa yang diverifikasi\u003C\u002Fli>\n\u003C\u002Fol>\n\u003Ch2 id=\"kesimpulan\">Kesimpulan\u003C\u002Fh2>\n\u003Cp>Testing kontrak Huff memerlukan pendekatan yang lebih ketat dari testing Solidity karena tidak ada safety net. Foundry dengan foundry-huff memberikan toolchain lengkap: fork testing untuk akurasi state, asersi gas untuk regresi, dan fuzzing untuk edge case. Investasi dalam test suite yang komprehensif membayar dirinya sendiri dengan mencegah bug yang mahal di produksi.\u003C\u002Fp>\n","id","b0000000-0000-0000-0000-000000000001",true,"2026-03-28T10:44:25.088608Z","Panduan testing kontrak Huff: foundry-huff, fork test mainnet, asersi gas, fuzzing, dan best practice keamanan.","testing Huff Foundry",null,"index, follow",[21,26,30,34],{"id":22,"name":23,"slug":24,"created_at":25},"c0000000-0000-0000-0000-000000000016","EVM","evm","2026-03-28T10:44:21.513630Z",{"id":27,"name":28,"slug":29,"created_at":25},"c0000000-0000-0000-0000-000000000021","Foundry","foundry",{"id":31,"name":32,"slug":33,"created_at":25},"c0000000-0000-0000-0000-000000000020","Gas Optimization","gas-optimization",{"id":35,"name":36,"slug":37,"created_at":25},"c0000000-0000-0000-0000-000000000017","Huff","huff","Blockchain",[40,46,52],{"id":41,"title":42,"slug":43,"excerpt":44,"locale":12,"category_name":38,"published_at":45},"d0000000-0000-0000-0000-000000000596","Lapisan Interoperabilitas Ethereum: Bagaimana 55+ L2 Menjadi Satu Chain","lapisan-interoperabilitas-ethereum-bagaimana-55-l2-menjadi-satu-chain","Ethereum memiliki 55+ rollup Layer 2, memecah likuiditas dan pengalaman pengguna. Lapisan Interoperabilitas Ethereum — menggabungkan pesan lintas-rollup, shared sequencer, dan based rollup — bertujuan menyatukan mereka menjadi satu jaringan yang dapat dikomposisi.","2026-03-28T10:44:44.364342Z",{"id":47,"title":48,"slug":49,"excerpt":50,"locale":12,"category_name":38,"published_at":51},"d0000000-0000-0000-0000-000000000595","ZK Proofs Melampaui Rollups: Inferensi AI Terverifikasi di Ethereum","zk-proofs-melampaui-rollups-inferensi-ai-terverifikasi-ethereum","Zero-knowledge proofs bukan lagi sekadar alat penskalaan. Pada 2026, zkML memungkinkan inferensi AI terverifikasi on-chain, ZK coprocessor memindahkan komputasi berat off-chain dengan verifikasi on-chain, dan sistem pembuktian baru seperti SP1 dan Jolt menjadikannya praktis.","2026-03-28T10:44:44.358370Z",{"id":53,"title":54,"slug":55,"excerpt":56,"locale":12,"category_name":38,"published_at":57},"d0000000-0000-0000-0000-000000000572","EIP-7702 dalam Praktik: Membangun Alur Akun Pintar Setelah Pectra","eip-7702-dalam-praktik-membangun-alur-akun-pintar-setelah-pectra","EIP-7702 memungkinkan EOA Ethereum mana pun untuk sementara bertindak sebagai kontrak pintar dalam satu transaksi. Berikut cara mengimplementasikan transaksi batch, sponsorship gas, dan social recovery menggunakan primitif account abstraction baru.","2026-03-28T10:44:42.816894Z",{"id":13,"name":59,"slug":60,"bio":61,"photo_url":18,"linkedin":18,"role":62,"created_at":63,"updated_at":63},"Open Soft Team","open-soft-team","The engineering team at Open Soft, building premium software solutions from Bali, Indonesia.","Engineering Team","2026-03-28T08:31:22.226811Z"]